#include "pch.h" #pragma hdrstop /*----------------------------------------------------------------------------- / Helper functions used by all /----------------------------------------------------------------------------*/ // // Given a cache entry return a BOOL indicating if the class is really a container // or not, we find this from both the schema and the display specifier. // BOOL _IsClassContainer(LPCLASSCACHEENTRY pClassCacheEntry, BOOL fIgnoreTreatAsLeaf) { BOOL fClassIsContainer = FALSE; TraceEnter(TRACE_CACHE, "_IsClassContainer"); // default to the treat as leaf flag, note that this is always // valid as it defaults to the schema value if it is not defined // in the display specifier. Trace(TEXT("fIsContainer is %scached and is %d"), pClassCacheEntry->dwCached & CLASSCACHE_CONTAINER ? TEXT(""):TEXT("not "), pClassCacheEntry->fIsContainer); Trace(TEXT("fTreatAsLeaf is %scached and is %d"), pClassCacheEntry->dwCached & CLASSCACHE_TREATASLEAF ? TEXT(""):TEXT("not "), pClassCacheEntry->fTreatAsLeaf); if ( !(pClassCacheEntry->dwCached & (CLASSCACHE_CONTAINER|CLASSCACHE_TREATASLEAF)) ) { TraceMsg("Neither container or treat as leaf is cached, therefore returning"); fClassIsContainer = TRUE; goto exit_gracefully; } if ( fIgnoreTreatAsLeaf ) { if ( !(pClassCacheEntry->dwCached & CLASSCACHE_CONTAINER) ) { TraceMsg("Object doesn't have the container flag cached"); goto exit_gracefully; } fClassIsContainer = pClassCacheEntry->fIsContainer; goto exit_gracefully; } if ( !(pClassCacheEntry->dwCached & CLASSCACHE_TREATASLEAF) ) { if ( !(pClassCacheEntry->dwCached & CLASSCACHE_CONTAINER) ) { TraceMsg("Object doesn't have the treat as leaf flag cached"); goto exit_gracefully; } fClassIsContainer = pClassCacheEntry->fIsContainer; goto exit_gracefully; } fClassIsContainer = pClassCacheEntry->fTreatAsLeaf; exit_gracefully: TraceLeaveValue(fClassIsContainer); } /*----------------------------------------------------------------------------- / COM API's exposed for accessing display specifiers. /----------------------------------------------------------------------------*/ class CDsDisplaySpecifier : public IDsDisplaySpecifier { private: LONG _cRef; DWORD _dwFlags; LPWSTR _pszServer; LPWSTR _pszUserName; LPWSTR _pszPassword; LANGID _langid; HRESULT _GetClassCacheInfo(LPCWSTR pszClassName, LPCWSTR pszADsPath, DWORD dwFlags, CLASSCACHEENTRY **ppcce); public: CDsDisplaySpecifier(); ~CDsDisplaySpecifier(); // *** IUnknown *** STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR *ppv); // *** IDsDisplaySpecifier *** STDMETHOD(SetServer)(LPCWSTR pszServer, LPCWSTR pszUserName, LPCWSTR pszPassword, DWORD dwFlags); STDMETHOD(SetLanguageID)(LANGID langid); STDMETHOD(GetDisplaySpecifier)(LPCWSTR pszObjectClass, REFIID riid, void **ppv); STDMETHOD(GetIconLocation)(LPCWSTR pszObjectClass, DWORD dwFlags, LPWSTR pszBuffer, INT cchBuffer, INT *presid); STDMETHOD_(HICON, GetIcon)(LPCWSTR pszObjectClass, DWORD dwFlags, INT cxIcon, INT cyIcon); STDMETHOD(GetFriendlyClassName)(LPCWSTR pszObjectClass, LPWSTR pszBuffer, INT cchBuffer); STDMETHOD(GetFriendlyAttributeName)(LPCWSTR pszObjectClass, LPCWSTR pszAttributeName, LPWSTR pszBuffer, UINT cchBuffer); STDMETHOD_(BOOL, IsClassContainer)(LPCWSTR pszObjectClass, LPCWSTR pszADsPath, DWORD dwFlags); STDMETHOD(GetClassCreationInfo)(LPCWSTR pszObjectClass, LPDSCLASSCREATIONINFO* ppdscci); STDMETHOD(EnumClassAttributes)(LPCWSTR pszObjectClass, LPDSENUMATTRIBUTES pcbEnum, LPARAM lParam); STDMETHOD_(ADSTYPE, GetAttributeADsType)(LPCWSTR pszAttributeName); }; // // construction/destruction // CDsDisplaySpecifier::CDsDisplaySpecifier() : _cRef(1), _dwFlags(0), _pszServer(NULL), _pszUserName(NULL), _pszPassword(NULL), _langid(GetUserDefaultUILanguage()) { DllAddRef(); } CDsDisplaySpecifier::~CDsDisplaySpecifier() { LocalFreeStringW(&_pszServer); LocalFreeStringW(&_pszUserName); LocalFreeStringW(&_pszPassword); DllRelease(); } // IUnknown ULONG CDsDisplaySpecifier::AddRef() { return InterlockedIncrement(&_cRef); } ULONG CDsDisplaySpecifier::Release() { if (InterlockedDecrement(&_cRef)) return _cRef; delete this; return 0; } HRESULT CDsDisplaySpecifier::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CDsDisplaySpecifier, IDsDisplaySpecifier), // IID_IDsDisplaySpecifier {0, 0 }, }; return QISearch(this, qit, riid, ppv); } // handle create instance STDAPI CDsDisplaySpecifier_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi) { CDsDisplaySpecifier *pdds = new CDsDisplaySpecifier(); if ( !pdds ) return E_OUTOFMEMORY; HRESULT hres = pdds->QueryInterface(IID_IUnknown, (void **)ppunk); pdds->Release(); return hres; } // // Class cache helper functions // HRESULT CDsDisplaySpecifier::_GetClassCacheInfo(LPCWSTR pszObjectClass, LPCWSTR pszADsPath, DWORD dwFlags, CLASSCACHEENTRY **ppcce) { CLASSCACHEGETINFO ccgi = { 0 }; ccgi.dwFlags = dwFlags; ccgi.pObjectClass = (LPWSTR)pszObjectClass; ccgi.pPath = (LPWSTR)pszADsPath; ccgi.pServer = _pszServer; ccgi.pUserName = _pszUserName; ccgi.pPassword = _pszPassword; if ( _dwFlags & DSSSF_SIMPLEAUTHENTICATE ) ccgi.dwFlags |= CLASSCACHE_SIMPLEAUTHENTICATE; if ( _dwFlags & DSSSF_DSAVAILABLE ) ccgi.dwFlags |= CLASSCACHE_DSAVAILABLE; return ClassCache_GetClassInfo(&ccgi, ppcce); } /*----------------------------------------------------------------------------- / IDsDisplaySpecifier::SetServer / ------------------------------ / To allow us to re-target other servers in the domains we allow the / owner of an IDsDisplaySpecifier object to set the prefered server, / this consists of the server name, the user name and the password. / / NTRAID 455406: Currently the password is stored clear text with the object, / this should be fixed - daviddv (10oct98) / / In: / pServer => server to use / pUserName => user name to be used / pPassword => password to be used / dwFlags => flags for this call / / Out: HRESULT /----------------------------------------------------------------------------*/ STDMETHODIMP CDsDisplaySpecifier::SetServer(LPCWSTR pszServer, LPCWSTR pszUserName, LPCWSTR pszPassword, DWORD dwFlags) { HRESULT hres = S_OK; USES_CONVERSION; TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::SetServer"); Trace(TEXT("pszServer %s"), pszServer ? W2CT(pszServer):TEXT("")); Trace(TEXT("pszUserName %s"), pszUserName ? W2CT(pszUserName):TEXT("")); Trace(TEXT("pszPassword %s"), pszPassword ? W2CT(pszPassword):TEXT("")); // free previous credential information LocalFreeStringW(&_pszServer); LocalFreeStringW(&_pszUserName); LocalFreeStringW(&_pszPassword); // allocate as required the new ones _dwFlags = dwFlags; hres = LocalAllocStringW(&_pszServer, pszServer); if ( SUCCEEDED(hres) ) hres = LocalAllocStringW(&_pszUserName, pszUserName); if ( SUCCEEDED(hres) ) hres = LocalAllocStringW(&_pszPassword, pszPassword); // and tidy up if we failed if ( FAILED(hres ) ) { LocalFreeStringW(&_pszServer); LocalFreeStringW(&_pszUserName); LocalFreeStringW(&_pszPassword); } TraceLeaveResult(hres); } /*----------------------------------------------------------------------------- / IDsDisplaySpecifier::SetLanguageID / ---------------------------------- / Display specifiers are localised, by default we use the process locale / read from GetLocale during object creation. This call allows the / locale to be set. / / In: / langid == LANGID to be used for display specifier look up. If this / value is zero then we read using GetUserDefaultUILanguage() and set / accordingly. / Out: HRESULT /----------------------------------------------------------------------------*/ STDMETHODIMP CDsDisplaySpecifier::SetLanguageID(LANGID langid) { TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::SetLanguageID"); Trace(TEXT("lcid %0x8"), langid); if ( !langid ) langid = GetUserDefaultUILanguage(); _langid = langid; // can hardly go wrong... TraceLeaveResult(S_OK); } /*----------------------------------------------------------------------------- / IDsDisplaySpecifier::GetDisplaySpecifier / ---------------------------------------- / Bind to the display specifier for a given class, try the users / locale, then the default locale calling ADsOpenObject as we / go. We use the specifier server, username and password. / / In: / pszObjectClass => object class to look up / riid, ppv => used to retrieve the COM object / / Out: HRESULT /----------------------------------------------------------------------------*/ STDMETHODIMP CDsDisplaySpecifier::GetDisplaySpecifier(LPCWSTR pszObjectClass, REFIID riid, void **ppv) { HRESULT hres; CLASSCACHEGETINFO ccgi = { 0 }; USES_CONVERSION; TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::GetDisplaySpecifer"); Trace(TEXT("pszObjectClass: %s"), pszObjectClass ? W2CT(pszObjectClass):TEXT("")); // fill out the display specifier record ccgi.pObjectClass = (LPWSTR)pszObjectClass; ccgi.pServer = (LPWSTR)_pszServer; ccgi.pUserName = (LPWSTR)_pszUserName; ccgi.pPassword = (LPWSTR)_pszPassword; ccgi.langid = _langid; hres = ::GetDisplaySpecifier(&ccgi, riid, ppv); FailGracefully(hres, "Failed when calling GetDisplaySpecifier"); exit_gracefully: TraceLeaveResult(hres); } /*----------------------------------------------------------------------------- / IDsDisplaySpecifier::GetFriendlyClassName / ----------------------------------------- / Retrieve the localised (friendly) name for an LDAP object class. If / the display specifier doesn't give a friendly name for the class / then we return the name we were originally given. / / In: / pszObjectClass => object class to look up / pszBuffer, cchBuffer = buffer to recieve the string / / Out: HRESULT /----------------------------------------------------------------------------*/ STDMETHODIMP CDsDisplaySpecifier::GetFriendlyClassName(LPCWSTR pszObjectClass, LPWSTR pszBuffer, INT cchBuffer) { HRESULT hres; LPCLASSCACHEENTRY pcce = NULL; USES_CONVERSION; TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::GetFriendlyClassName"); if ( !pszObjectClass || !pszBuffer ) ExitGracefully(hres, E_INVALIDARG, "No class, or no buffer failure"); Trace(TEXT("pszObjectClass: %s"), W2CT(pszObjectClass)); // fetch a record from the cache, if we found it then set pszObjectClass // to be the friendly class name, otherwise we just return the class // name we were given. hres = _GetClassCacheInfo(pszObjectClass, NULL, CLASSCACHE_FRIENDLYNAME, &pcce); FailGracefully(hres, "Failed to get class information from cache"); if ( pcce->dwCached & CLASSCACHE_FRIENDLYNAME) { Trace(TEXT("Friendly class name: %s"), W2CT(pcce->pFriendlyClassName)); pszObjectClass = pcce->pFriendlyClassName; } StrCpyNW(pszBuffer, pszObjectClass, cchBuffer); hres = S_OK; exit_gracefully: ClassCache_ReleaseClassInfo(&pcce); TraceLeaveResult(hres); } /*----------------------------------------------------------------------------- / IDsDisplaySpecifier::GetFriendlyAttributeName / --------------------------------------------- / Lookup the classes display speifier, then check the attributeNames property / for a property name pair that matches the given attribute name. With / this information return that name to the caller, if that fails then / return the original name. / / In: / pszObjectClass -> class name to look up in the cache / pszAttributeName -> attribute name to look up in the cache / pszBuffer -> buffer to be filled / cchBuffer = size of the buffer / / Out: HRESULT /----------------------------------------------------------------------------*/ STDMETHODIMP CDsDisplaySpecifier::GetFriendlyAttributeName(LPCWSTR pszObjectClass, LPCWSTR pszAttributeName, LPWSTR pszBuffer, UINT cchBuffer) { HRESULT hres; LPCLASSCACHEENTRY pcce = NULL; INT index; USES_CONVERSION; TraceEnter(TRACE_CACHE, "DsGetFriendlyAttributeName"); if ( !pszObjectClass || !pszAttributeName || !pszBuffer || !cchBuffer ) ExitGracefully(hres, E_INVALIDARG, "Bad class/attribute/return buffer"); Trace(TEXT("pszbjectClass: %s"), W2CT(pszObjectClass)); Trace(TEXT("pszAttributeName: %s"), W2CT(pszAttributeName)); Trace(TEXT("pszBuffer %x, cchBuffer %d"), pszBuffer, cchBuffer); hres = _GetClassCacheInfo(pszObjectClass, NULL, CLASSCACHE_ATTRIBUTENAMES, &pcce); FailGracefully(hres, "Failed to get class information from cache"); if ( pcce->dwCached & CLASSCACHE_ATTRIBUTENAMES ) { ATTRIBUTENAME an = { 0 }; an.pName = (LPWSTR)pszAttributeName; index = DPA_Search(pcce->hdpaAttributeNames, &an, 0, _CompareAttributeNameCB, NULL, DPAS_SORTED); if ( index != -1 ) { LPATTRIBUTENAME pAN = (LPATTRIBUTENAME)DPA_GetPtr(pcce->hdpaAttributeNames, index); if (pAN) { pszAttributeName = pAN->pDisplayName; TraceAssert(pszAttributeName); } } } StrCpyNW(pszBuffer, pszAttributeName, cchBuffer); hres = S_OK; exit_gracefully: ClassCache_ReleaseClassInfo(&pcce); TraceLeaveResult(hres); } /*----------------------------------------------------------------------------- / IDsDisplaySpecifier::IsClassContainer / ------------------------------------- / Return TRUE/FALSE indicating if the specified object class is a container, / we determine this both from the schema and the display specifier. / / The schema indicates if the class can container other objects, if so / then the object is a container. In the display specifier we have / an attribute "treatAsLeaf" which we use to override this setting, this / is used both from the admin tools and client UI. / / In: / pszObjectClass => object class to look up / pszADsPath => ADsPath of an object in the DS we can bind to and fetch / schema information from. / dwFlags => flags controlling this API: / DSICCF_IGNORETREATASLEAF = 1 => return schema attribute only, don't / override with treatAsLeaf attribute / from display specifier. / Out: BOOL /----------------------------------------------------------------------------*/ STDMETHODIMP_(BOOL) CDsDisplaySpecifier::IsClassContainer(LPCWSTR pszObjectClass, LPCWSTR pszADsPath, DWORD dwFlags) { HRESULT hres; BOOL fres = FALSE; LPCLASSCACHEENTRY pcce = NULL; USES_CONVERSION; TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::IsClassContainer"); if ( !pszObjectClass ) ExitGracefully(hres, E_INVALIDARG, "No object class failure"); Trace(TEXT("pszObjectClass: %s"), W2CT(pszObjectClass)); Trace(TEXT("dwFlags %x"), dwFlags); hres = _GetClassCacheInfo(pszObjectClass,pszADsPath, CLASSCACHE_CONTAINER|CLASSCACHE_TREATASLEAF, &pcce); FailGracefully(hres, "Failed to get class information from cache"); fres = _IsClassContainer(pcce, dwFlags & DSICCF_IGNORETREATASLEAF); Trace(TEXT("_IsClassContainer returns %d"), fres); exit_gracefully: ClassCache_ReleaseClassInfo(&pcce); TraceLeaveValue(fres); } /*----------------------------------------------------------------------------- / IDsDisplaySpecifier::GetIconLocation / ------------------------------------ / Fetch the location of an icon from the DS, returning both the filename and / the resource ID as required. The caller can then load the image, or / display this information in a dialog. / / In: / pszObjectClass => class to retrieve for / dwFlags = flags for extraction: / / One of the following: / DSGIF_ISNORMAL => standard icon, or, / DSGIF_OPEN => open icon (open folders etc), or, / DSGIF_DISABLED => disabled icon (eg. disabled user account). / / Combined with any of the: / DSGIF_GETDEFAULTICON => if no icon exists for this object, return the default document / icon from shell32. / / pszBuffer, cchBuffer => buffer to recieve the filename / presid => receives the resource id, +ve for index, -ve for resource / / Out: / HRESULT /----------------------------------------------------------------------------*/ STDMETHODIMP CDsDisplaySpecifier::GetIconLocation(LPCWSTR pszObjectClass, DWORD dwFlags, LPWSTR pszBuffer, INT cchBuffer, INT* presid) { HRESULT hres; LPCLASSCACHEENTRY pcce = NULL; USES_CONVERSION; TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::GetIconLocation"); if ( !pszObjectClass || !pszBuffer ) ExitGracefully(hres, E_INVALIDARG, "No object class/buffer failure"); Trace(TEXT("pszObjectClass: %s"), W2CT(pszObjectClass)); Trace(TEXT("dwFlags %x"), dwFlags); hres = _GetClassCacheInfo(pszObjectClass, NULL, CLASSCACHE_ICONS, &pcce); FailGracefully(hres, "Failed to get class information from cache"); hres = _GetIconLocation(pcce, dwFlags, pszBuffer, cchBuffer, presid); FailGracefully(hres, "Failed calling GetIconLocation"); exit_gracefully: ClassCache_ReleaseClassInfo(&pcce); TraceLeaveResult(hres); } /*----------------------------------------------------------------------------- / IDsDisplaySpecifier::GetIcon / ---------------------------- / Load the icon for the object class given. Icon information is stored in the / display specifier, we support 15 different states (open, closed, disabled etc). / / We look up the resource name from the DS and we then call PrivateExtractIcons / to load the object from the file. / / In: / pszObjectClass => class to retrieve for / dwFlags = flags for extraction: / / One of the following: / DSGIF_ISNORMAL => standard icon, or, / DSGIF_OPEN => open icon (open folders etc), or, / DSGIF_DISABLED => disabled icon (eg. disabled user account). / / Combined with any of the: / DSGIF_GETDEFAULTICON => if no icon exists for this object, return the default document / icon from shell32. / / cxImage, cyImage = size of image to load / / Out: / HICON / == NULL if failed /----------------------------------------------------------------------------*/ STDMETHODIMP_(HICON) CDsDisplaySpecifier::GetIcon(LPCWSTR pszObjectClass, DWORD dwFlags, INT cxImage, INT cyImage) { HRESULT hres; HICON hIcon = NULL; WCHAR szBuffer[MAX_PATH]; INT resid; USES_CONVERSION; TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::GetIcon"); if ( !pszObjectClass ) ExitGracefully(hres, E_INVALIDARG, "no object class specified"); Trace(TEXT("pszObjectClass %s, dwFlags %x, cxImage %d, cyImage %d"), W2CT(pszObjectClass), dwFlags, cxImage, cyImage); hres = GetIconLocation(pszObjectClass, dwFlags, szBuffer, ARRAYSIZE(szBuffer), &resid); FailGracefully(hres, "Failed when calling GetIconLocation"); if ( hres == S_OK ) { Trace(TEXT("Calling PrivateExtractIcons on %s,%d"), W2CT(szBuffer), resid); if ( 1 != PrivateExtractIcons(szBuffer, resid, cxImage, cyImage, &hIcon, NULL, 1, LR_LOADFROMFILE) ) ExitGracefully(hres, E_FAIL, "Failed to load the icon given its path etc"); hres = S_OK; // success } exit_gracefully: if ( !hIcon && (dwFlags & DSGIF_GETDEFAULTICON) ) { // // failed to load the icon and they really want the default document, so give it to them // TraceMsg("Failed to load the icon, so picking up default document image"); if ( 1 != PrivateExtractIcons(L"shell32.dll", -1, cxImage, cyImage, &hIcon, NULL, 1, LR_LOADFROMFILE) ) { TraceMsg("Failed to load the default document icon from shell32"); } } TraceLeaveValue(hIcon); } /*----------------------------------------------------------------------------- / IDsDisplaySpecifier::GetClassCreationInfo / ----------------------------------------- / Given an object class return the CLSIDs of the objects that make up / its creation wizard. / / In: / pszObjectClass -> class to enumerate from / ppdscci -> DSCREATECLASSINFO structure pointer to fill / / Out: HRESULT /----------------------------------------------------------------------------*/ STDMETHODIMP CDsDisplaySpecifier::GetClassCreationInfo(LPCWSTR pszObjectClass, LPDSCLASSCREATIONINFO* ppdscci) { HRESULT hres; LPDSCLASSCREATIONINFO pdscci = NULL; LPCLASSCACHEENTRY pcce = NULL; DWORD cbStruct = SIZEOF(DSCLASSCREATIONINFO); INT i; USES_CONVERSION; TraceEnter(TRACE_CACHE, "CDsDisplaySpecifer::GetClassCreationInfo"); if ( !pszObjectClass || !ppdscci ) ExitGracefully(hres, E_INVALIDARG, "No object class/pdscci passed"); // call the caching code to retrieve the creation wizard information hres = _GetClassCacheInfo(pszObjectClass, NULL, CLASSCACHE_CREATIONINFO, &pcce); FailGracefully(hres, "Failed to get class information from cache"); // now allocate the creation wizard structure and pass it to the // caller with the information filled in. if ( pcce->hdsaWizardExtn ) cbStruct += SIZEOF(GUID)*(DSA_GetItemCount(pcce->hdsaWizardExtn)-1); // -1 as structure already has 1 in the array! Trace(TEXT("Allocating creationg structure: cbStruct %d"), cbStruct); pdscci = (LPDSCLASSCREATIONINFO)LocalAlloc(LPTR, cbStruct); if ( !pdscci ) ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate return structure"); //pdscci->dwFlags = 0; //pdscci->clsidWizardDialog = { 0 }; //pdscci->clsidWizardPimaryPage = { 0 }; //pdscci->cWizardExtensions = 0; //pdscci->aWizardExtensions = { 0 }; if ( pcce->dwCached & CLASSCACHE_WIZARDDIALOG ) { TraceGUID("clsidWizardDialog is ", pcce->clsidWizardDialog); pdscci->dwFlags |= DSCCIF_HASWIZARDDIALOG; pdscci->clsidWizardDialog = pcce->clsidWizardDialog; } if ( pcce->dwCached & CLASSCACHE_WIZARDPRIMARYPAGE ) { TraceGUID("clsidWizardPrimaryPage is ", pcce->clsidWizardPrimaryPage); pdscci->dwFlags |= DSCCIF_HASWIZARDPRIMARYPAGE; pdscci->clsidWizardPrimaryPage = pcce->clsidWizardPrimaryPage; } if ( pcce->hdsaWizardExtn ) { pdscci->cWizardExtensions = DSA_GetItemCount(pcce->hdsaWizardExtn); Trace(TEXT("Class has %d wizard extensions"), pdscci->cWizardExtensions); for ( i = 0 ; i < DSA_GetItemCount(pcce->hdsaWizardExtn) ; i++ ) { LPGUID pGUID = (LPGUID)DSA_GetItemPtr(pcce->hdsaWizardExtn, i); TraceAssert(pGUID); TraceGUID("Wizard extension %d is ", *pGUID); pdscci->aWizardExtensions[i] = *pGUID; } } hres = S_OK; // success exit_gracefully: ClassCache_ReleaseClassInfo(&pcce); // it failed, therefore release pInfo if we have one, before setting // the return pointer for the caller. if ( FAILED(hres) && pdscci ) { TraceMsg("Failed, so freeing info structure"); LocalFree(pdscci); pdscci = NULL; } if ( ppdscci ) { Trace(TEXT("Setting ppInfo to %08x"), pdscci); *ppdscci = pdscci; } TraceLeaveResult(hres); } /*----------------------------------------------------------------------------- / IDsDisplaySpecifier::EnumClassAttributes / ---------------------------------------- / Enumerate all the attributes and their friendly names for the given object class. / The code looks up the display specifier and then calls given callback for each one, / passing the attribute name and its given "friendly name". / / In: / pszObjectClass -> class to enumerate from / pEnumCB -> callback function to enumerate to / lParam = lParam to pass to the CB fucntion / / Out: HRESULT /----------------------------------------------------------------------------*/ // NTRAID 455406: this should return an enumerator typedef struct { LPDSENUMATTRIBUTES pcbEnum; LPARAM lParam; } CLASSENUMCBSTATE, * LPCLASSENUMCBSTATE; INT _EnumClassAttributesCB(LPVOID p, LPVOID pData) { LPATTRIBUTENAME pAttributeName = (LPATTRIBUTENAME)p; LPCLASSENUMCBSTATE pState = (LPCLASSENUMCBSTATE)pData; return SUCCEEDED(pState->pcbEnum(pState->lParam, pAttributeName->pName, pAttributeName->pDisplayName, pAttributeName->dwFlags)); } STDMETHODIMP CDsDisplaySpecifier::EnumClassAttributes(LPCWSTR pszObjectClass, LPDSENUMATTRIBUTES pcbEnum, LPARAM lParam) { HRESULT hres; LPCLASSCACHEENTRY pcce = NULL; USES_CONVERSION; TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::EnumClassAttributes"); if ( !pszObjectClass || !pcbEnum ) ExitGracefully(hres, E_INVALIDARG, "Bad class/cb function"); Trace(TEXT("pszObjectClass: %s"), W2CT(pszObjectClass)); // call the cache code to pick up the friendly name, having done this we // can then copy it to the user buffer hres = _GetClassCacheInfo(pszObjectClass, NULL, CLASSCACHE_ATTRIBUTENAMES, &pcce); FailGracefully(hres, "Failed to get class information from cache"); if ( pcce->dwCached & CLASSCACHE_ATTRIBUTENAMES ) { CLASSENUMCBSTATE state = { pcbEnum, lParam }; DPA_EnumCallback(pcce->hdpaAttributeNames, _EnumClassAttributesCB, &state); } hres = S_OK; exit_gracefully: ClassCache_ReleaseClassInfo(&pcce); TraceLeaveResult(hres); } /*----------------------------------------------------------------------------- / IDsDisplaySpecifier::GetAttributeADsType / ---------------------------------------- / Look up the given attribute for its ADsType. / / In: / pszAttributeName = attribute to look up / / Out: / ADSTYPE /----------------------------------------------------------------------------*/ STDMETHODIMP_(ADSTYPE) CDsDisplaySpecifier::GetAttributeADsType(LPCWSTR pszAttributeName) { TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::GetAttributeADsType"); CLASSCACHEGETINFO ccgi = { 0 }; ccgi.pServer = _pszServer; ccgi.pUserName = _pszUserName; ccgi.pPassword = _pszPassword; if ( _dwFlags & DSSSF_SIMPLEAUTHENTICATE ) ccgi.dwFlags |= CLASSCACHE_SIMPLEAUTHENTICATE; if ( _dwFlags & DSSSF_DSAVAILABLE ) ccgi.dwFlags |= CLASSCACHE_DSAVAILABLE; ADSTYPE adt = ClassCache_GetADsTypeFromAttribute(&ccgi, pszAttributeName); TraceLeaveValue(adt); } /*----------------------------------------------------------------------------- / Externally exported cache APIs /----------------------------------------------------------------------------*/ CDsDisplaySpecifier g_dsDisplaySpecifier; // // these are exported for backwards compatiblity. We used to expose a series // of DsXXX APIs which dsquery, dsfolder and dsadmin all called. We have // now migrated these to a COM interface. // STDAPI_(HICON) DsGetIcon(DWORD dwFlags, LPWSTR pszObjectClass, INT cxImage, INT cyImage) { return g_dsDisplaySpecifier.GetIcon(pszObjectClass, dwFlags, cxImage, cyImage); } STDAPI DsGetFriendlyClassName(LPWSTR pszObjectClass, LPWSTR pszBuffer, UINT cchBuffer) { return g_dsDisplaySpecifier.GetFriendlyClassName(pszObjectClass, pszBuffer, cchBuffer); }