WindowsXP-SP1/admin/select/src/attributemanager.cxx
2020-09-30 16:53:49 +02:00

1281 lines
36 KiB
C++

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997 - 2000.
//
// File: AttributeManager.cxx
//
// Contents: Implementation of class to cache class and attribute
// strings and class icons used to display LDAP and WinNT
// classes and attributes.
//
// Classes: CAttributeManager
//
// History: 05-16-2000 DavidMun Created
//
//---------------------------------------------------------------------------
#include "headers.hxx"
#pragma hdrstop
const vector<ATTR_INFO> CAttributeManager::s_AttrEmpty;
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::CAttributeManager
//
// Synopsis: ctor
//
// Arguments: [rop] - containing instance of Object Picker
//
// History: 05-16-2000 DavidMun Created
//
//---------------------------------------------------------------------------
CAttributeManager::CAttributeManager(
const CObjectPicker &rop):
m_rop(rop),
m_ulNextNewAttrIndex(AK_LAST)
{
TRACE_CONSTRUCTOR(CAttributeManager);
InitializeCriticalSection(&m_cs);
m_himlClassIcons = ImageList_Create(
// NTRAID#NTBUG9-193518-2000/11/21-sburns
// NTRAID#NTBUG9-191961-2000/11/21-sburns
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
ILC_COLOR16 | ILC_MASK,
1,
1);
if (!m_himlClassIcons)
{
DBG_OUT_LASTERROR;
}
Clear();
}
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::~CAttributeManager
//
// Synopsis: dtor
//
// History: 05-16-2000 DavidMun Created
//
//---------------------------------------------------------------------------
CAttributeManager::~CAttributeManager()
{
TRACE_DESTRUCTOR(CAttributeManager);
if (m_himlClassIcons)
{
// bvt break fix: jdh VERIFY(ImageList_Destroy(m_himlClassIcons));
ImageList_Destroy(m_himlClassIcons);
m_himlClassIcons = NULL;
}
DeleteCriticalSection(&m_cs);
}
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::Clear
//
// Synopsis: Discard the cache
//
// History: 05-25-2000 DavidMun Created
//
//---------------------------------------------------------------------------
void
CAttributeManager::Clear()
{
TRACE_METHOD(CAttributeManager, Clear);
if (m_himlClassIcons)
{
ImageList_RemoveAll(m_himlClassIcons);
}
m_vClasses.clear();
m_AttrInfoMap.clear();
m_rpDispSpec.Relinquish();
m_rpDispSpecContainer.Relinquish();
//
// Restore the common attributes which have predefined ATTR_KEY values.
// The display name is initialized on-demand at runtime, since it's
// localized.
//
m_AttrInfoMap[AK_NAME].strAdsiName = L"name";
m_AttrInfoMap[AK_NAME].Type = ADSTYPE_CASE_IGNORE_STRING;
m_AttrInfoMap[AK_NAME].vstrDisplayName.push_back(String::load(IDS_LVCOLUMN_0));
m_AttrInfoMap[AK_NAME].vstrOwningClassesAdsiNames.push_back(L"*");
m_AttrInfoMap[AK_DISPLAY_PATH].vstrDisplayName.push_back(String::load(IDS_LVCOLUMN_1));
m_AttrInfoMap[AK_DISPLAY_PATH].vstrOwningClassesAdsiNames.push_back(L"*");
m_AttrInfoMap[AK_EMAIL_ADDRESSES].strAdsiName = L"mail";
m_AttrInfoMap[AK_EMAIL_ADDRESSES].Type = ADSTYPE_CASE_IGNORE_STRING;
m_AttrInfoMap[AK_ADSPATH].strAdsiName = L"adsPath";
m_AttrInfoMap[AK_ADSPATH].Type = ADSTYPE_CASE_IGNORE_STRING;
m_AttrInfoMap[AK_OBJECT_CLASS].strAdsiName = L"objectClass";
m_AttrInfoMap[AK_OBJECT_CLASS].Type = ADSTYPE_CASE_IGNORE_STRING;
m_AttrInfoMap[AK_USER_PRINCIPAL_NAME].strAdsiName = L"userPrincipalName";
m_AttrInfoMap[AK_USER_PRINCIPAL_NAME].Type = ADSTYPE_CASE_IGNORE_STRING;
m_AttrInfoMap[AK_COMPANY].strAdsiName = L"company";
m_AttrInfoMap[AK_COMPANY].Type = ADSTYPE_CASE_IGNORE_STRING;
m_AttrInfoMap[AK_DESCRIPTION].strAdsiName = L"description";
m_AttrInfoMap[AK_DESCRIPTION].Type = ADSTYPE_CASE_IGNORE_STRING;
m_AttrInfoMap[AK_SAMACCOUNTNAME].strAdsiName = L"sAMAccountName";
m_AttrInfoMap[AK_SAMACCOUNTNAME].Type = ADSTYPE_CASE_IGNORE_STRING;
m_AttrInfoMap[AK_OBJECT_SID].strAdsiName = L"objectSid";
m_AttrInfoMap[AK_OBJECT_SID].Type = ADSTYPE_OCTET_STRING;
m_AttrInfoMap[AK_GROUP_TYPE].strAdsiName = L"groupType";
m_AttrInfoMap[AK_GROUP_TYPE].Type = ADSTYPE_INTEGER;
m_AttrInfoMap[AK_USER_ACCT_CTRL].strAdsiName = L"userAccountControl";
m_AttrInfoMap[AK_USER_ACCT_CTRL].Type = ADSTYPE_INTEGER;
}
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::GetImageList
//
// Synopsis: Return the imagelist owned by this class
//
// Arguments: [phiml] - filled with pointer to this class's imagelist.
//
// Returns: S_OK or E_OUTOFMEMORY
//
// History: 06-22-2000 DavidMun Created
//
// Notes: Caller (or common controls that caller associates the
// imagelist with) must NOT free the imagelist.
//
//---------------------------------------------------------------------------
HRESULT
CAttributeManager::GetImageList(
HIMAGELIST *phiml) const
{
HRESULT hr = S_OK;
ASSERT(phiml);
*phiml = m_himlClassIcons;
if (!m_himlClassIcons)
{
DBG_OUT_HRESULT(E_OUTOFMEMORY);
hr = E_OUTOFMEMORY;
}
return hr;
}
//+--------------------------------------------------------------------------
//
// Class: CFindClass
//
// Purpose: Functor for looking up an element of m_vClasses by class
// name.
//
// History: 06-22-2000 DavidMun Created
//
//---------------------------------------------------------------------------
class CFindClass
{
public:
CFindClass(
const String &strClass,
BOOL fDownlevel):
m_strClass(strClass),
m_fDownlevel(fDownlevel)
{
}
BOOL
operator()(const CLASS_INFO &ci)
{
return ((m_fDownlevel && (ci.ulFlags & CI_FLAG_IS_DOWNLEVEL)) ||
(!m_fDownlevel && !(ci.ulFlags & CI_FLAG_IS_DOWNLEVEL))) &&
!m_strClass.icompare(ci.strAdsiName);
}
private:
BOOL m_fDownlevel;
const String &m_strClass;
};
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::GetIconIndexFromObject
//
// Synopsis: Wrapper for GetIconIndexFromClass--extracts necessary
// arguments (flags and class) from [dso] and forwards call.
//
// Arguments: [hwnd] - for binding
// [dso] - object
// [pintIndex] - on success, filled with index to icon
//
// Returns:
//
// History: 08-02-2000 DavidMun Created
//
// Notes:
//
//---------------------------------------------------------------------------
HRESULT
CAttributeManager::GetIconIndexFromObject(
HWND hwnd,
const CDsObject &dso,
INT *pintIndex) const
{
ULONG ulFlags = 0;
if (dso.GetDisabled())
{
ulFlags |= DSOP_GETICON_FLAG_DISABLED;
}
const CScopeManager &rsm = m_rop.GetScopeManager();
const CScope &rScope = rsm.LookupScopeById(dso.GetOwningScopeID());
if (IsDownlevel(rScope))
{
ulFlags |= DSOP_GETICON_FLAG_DOWNLEVEL;
}
ASSERT(dso.GetClass());
if (!dso.GetClass())
{
DBG_OUT_HRESULT(E_FAIL);
return E_FAIL;
}
return GetIconIndexFromClass(hwnd, dso.GetClass(), ulFlags, pintIndex);
}
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::GetIconIndexFromClass
//
// Synopsis: Return an index into the imagelist owned by this
// which contains an icon representing class named [strClass].
//
// Arguments: [hwnd] - for binding
// [strClass] - class to look up
// [ulFlags] - DSOP_GETICON_FLAG_*
// [pintIndex] - filled with index to icon, -1 if none could
// be found
//
// Returns: HRESULT
//
// History: 06-22-2000 DavidMun Created
//
// Notes: May access DS or resource file to procure the icon.
//
//---------------------------------------------------------------------------
HRESULT
CAttributeManager::GetIconIndexFromClass(
HWND hwnd,
const String &strClass,
ULONG ulFlags,
INT *pintIndex) const
{
ASSERT(pintIndex);
HRESULT hr = S_OK;
do
{
// init out param for failure
*pintIndex = -1;
// find the entry in m_vClasses for class with ldap name strClass
ClassInfoVector::iterator it;
hr = _ReadClassInfo(hwnd,
strClass,
(ulFlags & DSOP_GETICON_FLAG_DOWNLEVEL),
&it);
BREAK_ON_FAIL_HRESULT(hr);
if (ulFlags & DSOP_GETICON_FLAG_DISABLED)
{
*pintIndex = it->iDisabledIcon;
}
else
{
*pintIndex = it->iIcon;
}
} while (0);
return hr;
}
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::CopyIconToImageList
//
// Synopsis: Copy the icon representing class [strClass] from the
// imagelist owned by this to the imagelist with handle
// pointed to by [phimlDest].
//
// Arguments: [hwnd] - for bind
// [strClass] - class for which to find icon
// [ulFlags] - DSOP_GETICON_FLAG_*
// [phimlDest] - destination imagelist
//
// Returns: HRESULT
//
// History: 06-22-2000 DavidMun Created
//
//---------------------------------------------------------------------------
HRESULT
CAttributeManager::CopyIconToImageList(
HWND hwnd,
const String &strClass,
ULONG ulFlags,
HIMAGELIST *phimlDest) const
{
TRACE_METHOD(CAttributeManager, CopyIconToImageList);
ASSERT(phimlDest);
HRESULT hr = S_OK;
do
{
// find the entry in m_vClasses for class with ldap name strClass
ClassInfoVector::iterator it;
hr = _ReadClassInfo(hwnd,
strClass,
(ulFlags & DSOP_GETICON_FLAG_DOWNLEVEL),
&it);
BREAK_ON_FAIL_HRESULT(hr);
HICON hIcon = NULL;
if (ulFlags & DSOP_GETICON_FLAG_DISABLED)
{
// must Destroy this HICON
hIcon = ImageList_GetIcon(m_himlClassIcons,
it->iDisabledIcon,
ILD_NORMAL);
}
else
{
// must Destroy this HICON
hIcon = ImageList_GetIcon(m_himlClassIcons,
it->iIcon,
ILD_NORMAL);
}
if (hIcon)
{
ImageList_AddIcon(*phimlDest, hIcon);
DestroyIcon(hIcon); // NTRAID#NTBUG9-212260-2000/11/13-sburns
}
else
{
hr = HRESULT_FROM_LASTERROR;
DBG_OUT_LASTERROR;
break;
}
} while (0);
return hr;
}
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::GetAttrKeysForSelectedClasses
//
// Synopsis: Return a vector of ATTR_KEYs denoting all the attributes
// available for the classes which are currently selected in
// the 'look for' control.
//
// Arguments: [hwnd] - for bind
//
// Returns: Vector as described.
//
// History: 06-13-2000 DavidMun Created
//
//---------------------------------------------------------------------------
AttrKeyVector
CAttributeManager::GetAttrKeysForSelectedClasses(
HWND hwnd) const
{
TRACE_METHOD(CAttributeManager, GetAttrKeysForSelectedClasses);
vector<String> vstrClasses;
GetSelectedClasses(&vstrClasses);
BOOL fDownlevel = FALSE;
if (IsDownlevel(m_rop.GetScopeManager().GetCurScope()))
{
fDownlevel = TRUE;
}
return GetAttrKeysForClasses(hwnd, fDownlevel, vstrClasses);
}
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::GetSelectedClasses
//
// Synopsis: Fill [pvstrClasses] with the LDAP class name strings for
// all the classes currently selected in Look For.
//
// Arguments: [pvstrClasses] - filled with class strings as described
//
// History: 06-15-2000 DavidMun Created
//
//---------------------------------------------------------------------------
void
CAttributeManager::GetSelectedClasses(
vector<String> *pvstrClasses) const
{
ULONG flSelectedClasses =
m_rop.GetFilterManager().GetCurScopeSelectedFilterFlags();
ASSERT(flSelectedClasses);
ASSERT(!(flSelectedClasses & DOWNLEVEL_FILTER_BIT));
if (flSelectedClasses & DSOP_FILTER_USERS)
{
pvstrClasses->push_back(c_wzUserObjectClass);
}
if (flSelectedClasses & ALL_UPLEVEL_GROUP_FILTERS)
{
pvstrClasses->push_back(c_wzGroupObjectClass);
}
if (flSelectedClasses & DSOP_FILTER_COMPUTERS)
{
pvstrClasses->push_back(c_wzComputerObjectClass);
}
if (flSelectedClasses & DSOP_FILTER_CONTACTS)
{
pvstrClasses->push_back(c_wzContactObjectClass);
}
}
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::GetAttrKeysForClasses
//
// Synopsis: Return attribute keys for only the classes [vstrClasses].
//
// Arguments: [hwnd] - for bind
// [fDownlevel] - TRUE => all classes downlevel,
// FALSE => all classes uplevel
// [vstrClasses] - classes that should be represented by
// entries in returned vector
//
// Returns: AttrKeyVector containing ATTR_KEYs for only the
// classes in [vstrClasses].
//
// History: 06-12-2000 DavidMun Created
//
// Notes: The attribute infos in the returned vector may list classes
// in addition to those in [vstrClasses].
//
//---------------------------------------------------------------------------
AttrKeyVector
CAttributeManager::GetAttrKeysForClasses(
HWND hwnd,
BOOL fDownlevel,
const vector<String> &vstrClasses) const
{
TRACE_METHOD(CAttributeManager, GetAttrKeysForClasses);
AttrKeyVector vakResult;
//
// First ensure that we've read display specifier info on all the
// classes in vstrClasses, as well as all their attributes.
//
vector<String>::const_iterator itvstr;
for (itvstr = vstrClasses.begin(); itvstr != vstrClasses.end(); itvstr++)
{
_ReadAttrInfo(hwnd, fDownlevel, *itvstr); // calls _ReadClassInfo first
}
//
// Now populate a new AttrKeyVector with the keys of all the attributes
// that apply to any class in vstrClasses.
//
AttrInfoMap::const_iterator itAttrInfoMap;
for (itAttrInfoMap = m_AttrInfoMap.begin();
itAttrInfoMap != m_AttrInfoMap.end();
itAttrInfoMap++)
{
vector<String>::const_iterator itOwning;
//
// Iterate over the owning classes of the current attribute. If
// any of those classes matches one in [vstrClasses], then the
// key of the current ATTR_INFO should be copied into the output vector.
//
BOOL fMatch = FALSE;
for (itOwning = itAttrInfoMap->second.vstrOwningClassesAdsiNames.begin();
itOwning != itAttrInfoMap->second.vstrOwningClassesAdsiNames.end();
itOwning++)
{
for (itvstr = vstrClasses.begin();
itvstr != vstrClasses.end();
itvstr++)
{
if (!itvstr->icompare(*itOwning))
{
fMatch = TRUE;
vakResult.push_back(itAttrInfoMap->first);
break;
}
}
if (fMatch)
{
break;
}
}
}
return vakResult;
}
//
// A pointer to an ATTR_CALLBACK_INFO instance is passed to static
// function CAttributeManager::_AttrEnumCallback() as its lParam.
//
struct ATTR_CALLBACK_INFO
{
ATTR_CALLBACK_INFO():
pThis(NULL)
{
}
~ATTR_CALLBACK_INFO()
{
pThis = NULL;
}
const CAttributeManager *pThis;
String strClass;
};
//+--------------------------------------------------------------------------
//
// Class: CFindAttrByAdsiName
//
// Purpose: Used as a functor to look up the attribute key of a given
// class name.
//
// History: 06-22-2000 DavidMun Created
//
//---------------------------------------------------------------------------
class CFindAttrByAdsiName
{
public:
CFindAttrByAdsiName(
const String &strAdsiName):
m_strAdsiName(strAdsiName)
{
}
BOOL
operator()(const pair<ATTR_KEY, ATTR_INFO> &rKeyInfoPair)
{
return !m_strAdsiName.icompare(rKeyInfoPair.second.strAdsiName);
}
private:
const String &m_strAdsiName;
};
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::DemandInit
//
// Synopsis: Bind to the display specifier container if we haven't already
//
// Returns: Result of attempting bind.
//
// History: 05-23-2000 DavidMun Created
//
//---------------------------------------------------------------------------
HRESULT
CAttributeManager::DemandInit(
HWND hwnd) const
{
HRESULT hr = S_OK;
WCHAR wzUserName[MAX_PATH];
WCHAR wzPassword[MAX_PATH];
do
{
//
// If DS is not available, there's nothing to do here
//
if (!ConfigSupportsDs(m_rop.GetTargetComputerConfig()))
{
break;
}
//
// Create display specifier instance if we haven't already.
//
if (!m_rpDispSpec.get())
{
hr = m_rpDispSpec.AcquireViaCreateInstance(CLSID_DsDisplaySpecifier,
NULL,
CLSCTX_INPROC,
IID_IDsDisplaySpecifier);
BREAK_ON_FAIL_HRESULT(hr);
}
ASSERT(m_rpDispSpec.get());
//
// Bind to display specifier container if necessary
// If we are already bound and the target hasn't changed
// there is no need to bind again so break.
//
if (m_rpDispSpecContainer.get())
{
break;
}
VOID *pv = NULL;
hr = m_rop.GetRootDSE().BindToDisplaySpecifiersContainer(hwnd,
IID_IADsContainer,
&pv);
BREAK_ON_FAIL_HRESULT(hr);
m_rpDispSpecContainer.Acquire(
static_cast<IADsContainer *>(pv));
ASSERT(m_rpDispSpecContainer.get());
g_pBinder->GetDefaultCreds(PROVIDER_LDAP,
wzUserName,
wzPassword);
if (*wzUserName)
{
String strDcName = m_rop.GetTargetDomainDc();
if(strDcName.size() > 2 && strDcName[0] == L'\\' && strDcName[1] == L'\\')
strDcName.erase(0, 2);
hr = m_rpDispSpec->SetServer(strDcName.c_str(),
wzUserName,
wzPassword,
DSSSF_DSAVAILABLE);
BREAK_ON_FAIL_HRESULT(hr);
}
} while (0);
ZeroMemory(wzPassword, sizeof wzPassword);
ZeroMemory(wzUserName, sizeof wzUserName);
return hr;
}
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::_ReadClassInfo
//
// Synopsis: Read and cache display specifier information for [strClass].
//
// Arguments: [hwnd] - for binding
// [strClass] - name of class to read info for
// [fDownlevel] - TRUE => [strClass] is name of downlevel class,
// FALSE => [strClass] is LDAP class name
// [pit] - filled with iterator at relevant CLASS_INFO
//
// Returns: HRESULT
//
// History: 05-23-2000 DavidMun Created
//
//---------------------------------------------------------------------------
HRESULT
CAttributeManager::_ReadClassInfo(
HWND hwnd,
const String &strClass,
BOOL fDownlevel,
ClassInfoVector::iterator *pit) const
{
//TRACE_METHOD(CAttributeManager, _ReadClassInfo);
ASSERT(pit);
HRESULT hr = S_OK;
CLASS_INFO ci;
PWSTR pwzBuf = NULL;
ci.strAdsiName = strClass;
do
{
//
// See if we've already got info on this class
//
CFindClass predicate(strClass, fDownlevel);
*pit = find_if(m_vClasses.begin(), m_vClasses.end(), predicate);
if (*pit != m_vClasses.end())
{
// success, return iterator pointing to cached info
break;
}
Dbg(DEB_TRACE,
"CAttributeManager::_ReadClassInfo<%#x> Reading class %ws\n",
this,
strClass.c_str());
//
// If DS is not available on target machine class info must be
// hardcoded.
//
BOOL fDsAvailable = ConfigSupportsDs(m_rop.GetTargetComputerConfig());
//
// Don't have cached info for this class.
// Read display info from the specifier for this class
//
// Special-case downlevel classes, as they won't appear in the
// DS.
//
BOOL fIsLocalGroup = !strClass.icompare(c_wzLocalGroupClass);
BOOL fIsGlobalGroup = !strClass.icompare(c_wzGlobalGroupClass);
BOOL fIsGroup = !strClass.icompare(c_wzGroupObjectClass);
BOOL fIsUser = !strClass.icompare(c_wzUserObjectClass);
BOOL fIsComputer = !strClass.icompare(c_wzComputerObjectClass);
if (fIsLocalGroup || fIsGlobalGroup)
{
HICON hIcon;
ULONG idiGroup = fIsLocalGroup ? IDI_LOCAL_GROUP : IDI_GROUP;
int idsGroup = fIsLocalGroup ? IDS_LOCAL_GROUP : IDS_GLOBAL_GROUP;
hIcon = LoadIcon(g_hinst, MAKEINTRESOURCE(idiGroup));
ci.iIcon = ImageList_AddIcon(m_himlClassIcons, hIcon);
ci.strDisplayName = String::load(idsGroup);
}
else if (fDownlevel || !fDsAvailable)
{
HICON hIcon;
ULONG idi;
ULONG idiDisabled = 0;
int ids;
if (fIsUser)
{
idi = IDI_USER;
idiDisabled = IDI_DISABLED_USER;
ids = IDS_USER;
}
else if (fIsGroup)
{
idi = IDI_GROUP;
ids = IDS_GROUP;
}
else if (fIsComputer)
{
idi = IDI_COMPUTER;
idiDisabled = IDI_DISABLED_COMPUTER;
ids = IDS_COMPUTER;
}
else
{
Dbg(DEB_ERROR,
"unexpected class %ws for non-DS machine config\n",
strClass.c_str());
hr = E_INVALIDARG;
break;
}
hIcon = LoadIcon(g_hinst, MAKEINTRESOURCE(idi));
ci.iIcon = ImageList_AddIcon(m_himlClassIcons, hIcon);
if (idiDisabled)
{
hIcon = LoadIcon(g_hinst, MAKEINTRESOURCE(idiDisabled));
ci.iDisabledIcon = ImageList_AddIcon(m_himlClassIcons, hIcon);
}
ci.strDisplayName = String::load(ids);
ci.ulFlags |= CI_FLAG_IS_DOWNLEVEL;
}
else
{
CWaitCursor Hourglass;
hr = DemandInit(hwnd);
BREAK_ON_FAIL_HRESULT(hr);
HICON hIcon;
{
TIMER("IDsDisplaySpecifier::GetIcon(%ws)", strClass.c_str());
hIcon = m_rpDispSpec->GetIcon(strClass.c_str(),
DSGIF_ISNORMAL
| DSGIF_GETDEFAULTICON,
16,
16);
}
ci.iIcon = ImageList_AddIcon(m_himlClassIcons, hIcon);
DestroyIcon(hIcon);
{
TIMER("IDsDisplaySpecifier::GetIcon(%ws, DSGIF_ISDISABLED)",
strClass.c_str());
hIcon = m_rpDispSpec->GetIcon(strClass.c_str(),
DSGIF_ISDISABLED
| DSGIF_GETDEFAULTICON,
16,
16);
}
ci.iDisabledIcon = ImageList_AddIcon(m_himlClassIcons, hIcon);
DestroyIcon(hIcon);
pwzBuf = new WCHAR [MAX_PATH + 1];
{
TIMER("IDsDisplaySpecifier::GetFriendlyClassName(%ws)",
strClass.c_str());
hr = m_rpDispSpec->GetFriendlyClassName(strClass.c_str(),
pwzBuf,
MAX_PATH);
}
if (SUCCEEDED(hr))
{
ci.strDisplayName = pwzBuf;
}
else
{
ci.strDisplayName = strClass;
}
}
//
// Add new info to class vector
//
m_vClasses.push_back(ci);
*pit = m_vClasses.end() - 1;
} while (0);
delete [] pwzBuf;
return hr;
}
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::_ReadAttrInfo
//
// Synopsis: Read all class and attribute information for class with ADSI
// name [strClass] from the display specifier interface.
//
// Arguments: [hwnd] - for bind
// [strClass] - class for which to read attributes
//
// History: 06-12-2000 DavidMun Created
//
//---------------------------------------------------------------------------
HRESULT
CAttributeManager::_ReadAttrInfo(
HWND hwnd,
BOOL fDownlevel,
const String &strClass) const
{
//TRACE_METHOD(CAttributeManager, _ReadAttrInfo);
ClassInfoVector::iterator itClass;
HRESULT hr = S_OK;
do
{
hr = _ReadClassInfo(hwnd, strClass, fDownlevel, &itClass); // calls DemandInit
BREAK_ON_FAIL_HRESULT(hr);
//
// If we've been here before for this class and successfully read its
// attributes, leave.
//
if (itClass->ulFlags & CI_FLAG_READ_ATTR_INFO)
{
break;
}
//
// If the DS is not available, then leave, as there are no
// attributes to be read.
//
BOOL fDsAvailable = ConfigSupportsDs(m_rop.GetTargetComputerConfig());
if (!fDsAvailable)
{
break;
}
//
// Remember the last attribute we know about before doing the enum.
//
AttrInfoMap::iterator itLastOld = m_AttrInfoMap.end();
itLastOld--;
//
// Enumerate via callback all the display specifer attributes for class
//
Dbg(DEB_TRACE, "Reading attributes for class %ws\n", strClass.c_str());
ATTR_CALLBACK_INFO aci;
aci.pThis = this;
aci.strClass = strClass;
hr = m_rpDispSpec->EnumClassAttributes(strClass.c_str(),
_AttrEnumCallback,
reinterpret_cast<LPARAM>(&aci));
//
// Now for any attributes added, set their type
//
AttrInfoMap::iterator itMap = itLastOld;
itMap++;
for (; itMap != m_AttrInfoMap.end(); itMap++)
{
itMap->second.Type =
m_rpDispSpec->GetAttributeADsType(itMap->second.strAdsiName.c_str());
// Dbg(DEB_TRACE,
// "%ws, %ws, %#x\n",
// itMap->second.strAdsiName.c_str(),
// itMap->second.strDisplayName.c_str(),
// itMap->second.Type);
}
//
// Remember that we read the attributes for this class
//
itClass->ulFlags |= CI_FLAG_READ_ATTR_INFO;
} while (0);
return hr;
}
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::_AttrEnumCallback
//
// Synopsis: Receive the callback from the display specifier enumerator
// for the attributes of a specific class.
//
// Arguments: [lParam] - ATTR_CALLBACK_INFO *
// [pszAttributeName] - ADSI (LDAP) name of attribute
// [pszDisplayName] - human-readable name of attribute
// [dwFlags] - unused
//
// Returns: S_OK (an error would only halt the enumeration)
//
// History: 06-12-2000 DavidMun Created
//
//---------------------------------------------------------------------------
HRESULT CALLBACK
CAttributeManager::_AttrEnumCallback(
LPARAM lParam,
LPCWSTR pszAttributeName,
LPCWSTR pszDisplayName,
DWORD dwFlags)
{
ATTR_CALLBACK_INFO *paci = reinterpret_cast<ATTR_CALLBACK_INFO *>(lParam);
const CAttributeManager *pThis = paci->pThis;
ASSERT(pszAttributeName);
ASSERT(pszDisplayName);
CAutoCritSec Lock(const_cast<CRITICAL_SECTION*>(&pThis->m_cs));
do
{
if (!pszAttributeName)
{
DBG_OUT_HRESULT(E_POINTER);
break;
}
//
// See if there's already an entry in m_AttrInfoMap for this
// attribute.
// This can happen because more than one class of object might have the
// same attribute.
//
ATTR_KEY key = pThis->GetAttrKey(pszAttributeName);
if(AddIfNotPresent(&pThis->m_AttrInfoMap[key].vstrOwningClassesAdsiNames,
paci->strClass))
{
if (pszDisplayName)
{
pThis->m_AttrInfoMap[key].vstrDisplayName.push_back(pszDisplayName);
}
else
{
//
// not localized, but better than nothing. will be overwritten
// with localized name should a later enumeration of some other
// class' attributes have one for this attribute.
//
pThis->m_AttrInfoMap[key].vstrDisplayName.push_back(pszAttributeName);
}
}
//
// _ReadAttrInfo will go back and set the Type values for all
// enumerated attributes
//
} while (0);
return S_OK;
}
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::GetAttrKey
//
// Synopsis: Return the key for attribute with ADSI name [strAdsiName],
// creating one if necessary.
//
// Arguments: [strAdsiName] - name of attribute to find in
// m_AttrInfoMap.
//
// Returns: New or existing key
//
// History: 06-13-2000 DavidMun Created
//
// Note: Only caller is dsobject which has a class and VARTYPE in
// addition to attribute name. It could supply those to make
// the new ATTR_INFO structure contain more data, but right now
// nothing needs to use that.
//
//---------------------------------------------------------------------------
ATTR_KEY
CAttributeManager::GetAttrKey(
const String &strAdsiName) const
{
//TRACE_METHOD(CAttributeManager, GetAttrKey);
CFindAttrByAdsiName pred(strAdsiName);
AttrInfoMap::iterator itAttr;
itAttr = find_if(m_AttrInfoMap.begin(),
m_AttrInfoMap.end(),
pred);
if (itAttr != m_AttrInfoMap.end())
{
return itAttr->first;
}
//
// Master attribute list doesn't contain an entry for this attribute
// (pszAttributeName) yet. Create one.
//
ATTR_KEY key = static_cast<ATTR_KEY>(++m_ulNextNewAttrIndex);
m_AttrInfoMap[key].strAdsiName = strAdsiName;
return key;
}
BOOL
CAttributeManager::
IsAttributeLoaded(
ATTR_KEY ak) const
{
CAutoCritSec Lock(const_cast<CRITICAL_SECTION *>(&m_cs));
return !m_AttrInfoMap[ak].vstrDisplayName.empty();
}
//+--------------------------------------------------------------------------
//
// Member: CAttributeManager::GetAttrDisplayName
//
// Synopsis: Return the human-readable name for attribute with key [ak]
//
// Arguments: [ak] - represents attribute for which to return name
//
// Returns: Localized name of attribute
//
// History: 06-14-2000 DavidMun Created
//
//---------------------------------------------------------------------------
const String &
CAttributeManager::GetAttrDisplayName(
ATTR_KEY ak) const
{
CAutoCritSec Lock(const_cast<CRITICAL_SECTION *>(&m_cs));
String strClass = GetClassName(m_rop);
vector<String>::const_iterator itClass;
vector<String>::const_iterator itDisplayName;
//
// Iterate over the owning classes of the current attribute. If
// any of those classes matches one in [vstrClasses], then the
// key of the current ATTR_INFO should be copied into the output vector.
//
BOOL fMatch = FALSE;
for (itClass = m_AttrInfoMap[ak].vstrOwningClassesAdsiNames.begin(),
itDisplayName = m_AttrInfoMap[ak].vstrDisplayName.begin();
itClass != m_AttrInfoMap[ak].vstrOwningClassesAdsiNames.end() &&
itDisplayName != m_AttrInfoMap[ak].vstrDisplayName.end();
itClass++,
itDisplayName++)
{
if (!itClass->icompare(strClass))
{
fMatch = TRUE;
break;
}
if (fMatch)
{
break;
}
}
if(!fMatch)
itDisplayName = m_AttrInfoMap[ak].vstrDisplayName.begin();
const String *pstrDisplayName = NULL;
if(itDisplayName != m_AttrInfoMap[ak].vstrDisplayName.end())
pstrDisplayName = &*itDisplayName;
else
pstrDisplayName = &m_AttrInfoMap[ak].strAdsiName;
//
// If we don't have a display name for the attribute yet, then we
// haven't read the attr info from the DS yet. Caller is responsible
// for telling us which classes to read before attempting to get
// display info about them.
//
if (pstrDisplayName->empty())
{
Dbg(DEB_ERROR, "No display name for ATTR_KEY=%u\n", ak);
}
ASSERT(!pstrDisplayName->empty());
return *pstrDisplayName;
}