847 lines
28 KiB
C++
847 lines
28 KiB
C++
#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);
|
|
}
|