windows-nt/Source/XPSP1/NT/shell/ext/dsui/dsuiext/cacheapi.cpp

847 lines
28 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
#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("<none>"));
Trace(TEXT("pszUserName %s"), pszUserName ? W2CT(pszUserName):TEXT("<none>"));
Trace(TEXT("pszPassword %s"), pszPassword ? W2CT(pszPassword):TEXT("<none>"));
// 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("<none>"));
// 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);
}