Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

846 lines
28 KiB

  1. #include "pch.h"
  2. #pragma hdrstop
  3. /*-----------------------------------------------------------------------------
  4. / Helper functions used by all
  5. /----------------------------------------------------------------------------*/
  6. //
  7. // Given a cache entry return a BOOL indicating if the class is really a container
  8. // or not, we find this from both the schema and the display specifier.
  9. //
  10. BOOL _IsClassContainer(LPCLASSCACHEENTRY pClassCacheEntry, BOOL fIgnoreTreatAsLeaf)
  11. {
  12. BOOL fClassIsContainer = FALSE;
  13. TraceEnter(TRACE_CACHE, "_IsClassContainer");
  14. // default to the treat as leaf flag, note that this is always
  15. // valid as it defaults to the schema value if it is not defined
  16. // in the display specifier.
  17. Trace(TEXT("fIsContainer is %scached and is %d"),
  18. pClassCacheEntry->dwCached & CLASSCACHE_CONTAINER ? TEXT(""):TEXT("not "),
  19. pClassCacheEntry->fIsContainer);
  20. Trace(TEXT("fTreatAsLeaf is %scached and is %d"),
  21. pClassCacheEntry->dwCached & CLASSCACHE_TREATASLEAF ? TEXT(""):TEXT("not "),
  22. pClassCacheEntry->fTreatAsLeaf);
  23. if ( !(pClassCacheEntry->dwCached & (CLASSCACHE_CONTAINER|CLASSCACHE_TREATASLEAF)) )
  24. {
  25. TraceMsg("Neither container or treat as leaf is cached, therefore returning");
  26. fClassIsContainer = TRUE;
  27. goto exit_gracefully;
  28. }
  29. if ( fIgnoreTreatAsLeaf )
  30. {
  31. if ( !(pClassCacheEntry->dwCached & CLASSCACHE_CONTAINER) )
  32. {
  33. TraceMsg("Object doesn't have the container flag cached");
  34. goto exit_gracefully;
  35. }
  36. fClassIsContainer = pClassCacheEntry->fIsContainer;
  37. goto exit_gracefully;
  38. }
  39. if ( !(pClassCacheEntry->dwCached & CLASSCACHE_TREATASLEAF) )
  40. {
  41. if ( !(pClassCacheEntry->dwCached & CLASSCACHE_CONTAINER) )
  42. {
  43. TraceMsg("Object doesn't have the treat as leaf flag cached");
  44. goto exit_gracefully;
  45. }
  46. fClassIsContainer = pClassCacheEntry->fIsContainer;
  47. goto exit_gracefully;
  48. }
  49. fClassIsContainer = pClassCacheEntry->fTreatAsLeaf;
  50. exit_gracefully:
  51. TraceLeaveValue(fClassIsContainer);
  52. }
  53. /*-----------------------------------------------------------------------------
  54. / COM API's exposed for accessing display specifiers.
  55. /----------------------------------------------------------------------------*/
  56. class CDsDisplaySpecifier : public IDsDisplaySpecifier
  57. {
  58. private:
  59. LONG _cRef;
  60. DWORD _dwFlags;
  61. LPWSTR _pszServer;
  62. LPWSTR _pszUserName;
  63. LPWSTR _pszPassword;
  64. LANGID _langid;
  65. HRESULT _GetClassCacheInfo(LPCWSTR pszClassName, LPCWSTR pszADsPath, DWORD dwFlags, CLASSCACHEENTRY **ppcce);
  66. public:
  67. CDsDisplaySpecifier();
  68. ~CDsDisplaySpecifier();
  69. // *** IUnknown ***
  70. STDMETHODIMP_(ULONG) AddRef();
  71. STDMETHODIMP_(ULONG) Release();
  72. STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR *ppv);
  73. // *** IDsDisplaySpecifier ***
  74. STDMETHOD(SetServer)(LPCWSTR pszServer, LPCWSTR pszUserName, LPCWSTR pszPassword, DWORD dwFlags);
  75. STDMETHOD(SetLanguageID)(LANGID langid);
  76. STDMETHOD(GetDisplaySpecifier)(LPCWSTR pszObjectClass, REFIID riid, void **ppv);
  77. STDMETHOD(GetIconLocation)(LPCWSTR pszObjectClass, DWORD dwFlags, LPWSTR pszBuffer, INT cchBuffer, INT *presid);
  78. STDMETHOD_(HICON, GetIcon)(LPCWSTR pszObjectClass, DWORD dwFlags, INT cxIcon, INT cyIcon);
  79. STDMETHOD(GetFriendlyClassName)(LPCWSTR pszObjectClass, LPWSTR pszBuffer, INT cchBuffer);
  80. STDMETHOD(GetFriendlyAttributeName)(LPCWSTR pszObjectClass, LPCWSTR pszAttributeName, LPWSTR pszBuffer, UINT cchBuffer);
  81. STDMETHOD_(BOOL, IsClassContainer)(LPCWSTR pszObjectClass, LPCWSTR pszADsPath, DWORD dwFlags);
  82. STDMETHOD(GetClassCreationInfo)(LPCWSTR pszObjectClass, LPDSCLASSCREATIONINFO* ppdscci);
  83. STDMETHOD(EnumClassAttributes)(LPCWSTR pszObjectClass, LPDSENUMATTRIBUTES pcbEnum, LPARAM lParam);
  84. STDMETHOD_(ADSTYPE, GetAttributeADsType)(LPCWSTR pszAttributeName);
  85. };
  86. //
  87. // construction/destruction
  88. //
  89. CDsDisplaySpecifier::CDsDisplaySpecifier() :
  90. _cRef(1),
  91. _dwFlags(0),
  92. _pszServer(NULL),
  93. _pszUserName(NULL),
  94. _pszPassword(NULL),
  95. _langid(GetUserDefaultUILanguage())
  96. {
  97. DllAddRef();
  98. }
  99. CDsDisplaySpecifier::~CDsDisplaySpecifier()
  100. {
  101. LocalFreeStringW(&_pszServer);
  102. LocalFreeStringW(&_pszUserName);
  103. LocalFreeStringW(&_pszPassword);
  104. DllRelease();
  105. }
  106. // IUnknown
  107. ULONG CDsDisplaySpecifier::AddRef()
  108. {
  109. return InterlockedIncrement(&_cRef);
  110. }
  111. ULONG CDsDisplaySpecifier::Release()
  112. {
  113. if (InterlockedDecrement(&_cRef))
  114. return _cRef;
  115. delete this;
  116. return 0;
  117. }
  118. HRESULT CDsDisplaySpecifier::QueryInterface(REFIID riid, void **ppv)
  119. {
  120. static const QITAB qit[] =
  121. {
  122. QITABENT(CDsDisplaySpecifier, IDsDisplaySpecifier), // IID_IDsDisplaySpecifier
  123. {0, 0 },
  124. };
  125. return QISearch(this, qit, riid, ppv);
  126. }
  127. // handle create instance
  128. STDAPI CDsDisplaySpecifier_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  129. {
  130. CDsDisplaySpecifier *pdds = new CDsDisplaySpecifier();
  131. if ( !pdds )
  132. return E_OUTOFMEMORY;
  133. HRESULT hres = pdds->QueryInterface(IID_IUnknown, (void **)ppunk);
  134. pdds->Release();
  135. return hres;
  136. }
  137. //
  138. // Class cache helper functions
  139. //
  140. HRESULT CDsDisplaySpecifier::_GetClassCacheInfo(LPCWSTR pszObjectClass, LPCWSTR pszADsPath,
  141. DWORD dwFlags, CLASSCACHEENTRY **ppcce)
  142. {
  143. CLASSCACHEGETINFO ccgi = { 0 };
  144. ccgi.dwFlags = dwFlags;
  145. ccgi.pObjectClass = (LPWSTR)pszObjectClass;
  146. ccgi.pPath = (LPWSTR)pszADsPath;
  147. ccgi.pServer = _pszServer;
  148. ccgi.pUserName = _pszUserName;
  149. ccgi.pPassword = _pszPassword;
  150. if ( _dwFlags & DSSSF_SIMPLEAUTHENTICATE )
  151. ccgi.dwFlags |= CLASSCACHE_SIMPLEAUTHENTICATE;
  152. if ( _dwFlags & DSSSF_DSAVAILABLE )
  153. ccgi.dwFlags |= CLASSCACHE_DSAVAILABLE;
  154. return ClassCache_GetClassInfo(&ccgi, ppcce);
  155. }
  156. /*-----------------------------------------------------------------------------
  157. / IDsDisplaySpecifier::SetServer
  158. / ------------------------------
  159. / To allow us to re-target other servers in the domains we allow the
  160. / owner of an IDsDisplaySpecifier object to set the prefered server,
  161. / this consists of the server name, the user name and the password.
  162. /
  163. / NTRAID 455406: Currently the password is stored clear text with the object,
  164. / this should be fixed - daviddv (10oct98)
  165. /
  166. / In:
  167. / pServer => server to use
  168. / pUserName => user name to be used
  169. / pPassword => password to be used
  170. / dwFlags => flags for this call
  171. /
  172. / Out:
  173. HRESULT
  174. /----------------------------------------------------------------------------*/
  175. STDMETHODIMP CDsDisplaySpecifier::SetServer(LPCWSTR pszServer, LPCWSTR pszUserName, LPCWSTR pszPassword, DWORD dwFlags)
  176. {
  177. HRESULT hres = S_OK;
  178. USES_CONVERSION;
  179. TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::SetServer");
  180. Trace(TEXT("pszServer %s"), pszServer ? W2CT(pszServer):TEXT("<none>"));
  181. Trace(TEXT("pszUserName %s"), pszUserName ? W2CT(pszUserName):TEXT("<none>"));
  182. Trace(TEXT("pszPassword %s"), pszPassword ? W2CT(pszPassword):TEXT("<none>"));
  183. // free previous credential information
  184. LocalFreeStringW(&_pszServer);
  185. LocalFreeStringW(&_pszUserName);
  186. LocalFreeStringW(&_pszPassword);
  187. // allocate as required the new ones
  188. _dwFlags = dwFlags;
  189. hres = LocalAllocStringW(&_pszServer, pszServer);
  190. if ( SUCCEEDED(hres) )
  191. hres = LocalAllocStringW(&_pszUserName, pszUserName);
  192. if ( SUCCEEDED(hres) )
  193. hres = LocalAllocStringW(&_pszPassword, pszPassword);
  194. // and tidy up if we failed
  195. if ( FAILED(hres ) )
  196. {
  197. LocalFreeStringW(&_pszServer);
  198. LocalFreeStringW(&_pszUserName);
  199. LocalFreeStringW(&_pszPassword);
  200. }
  201. TraceLeaveResult(hres);
  202. }
  203. /*-----------------------------------------------------------------------------
  204. / IDsDisplaySpecifier::SetLanguageID
  205. / ----------------------------------
  206. / Display specifiers are localised, by default we use the process locale
  207. / read from GetLocale during object creation. This call allows the
  208. / locale to be set.
  209. /
  210. / In:
  211. / langid == LANGID to be used for display specifier look up. If this
  212. / value is zero then we read using GetUserDefaultUILanguage() and set
  213. / accordingly.
  214. / Out:
  215. HRESULT
  216. /----------------------------------------------------------------------------*/
  217. STDMETHODIMP CDsDisplaySpecifier::SetLanguageID(LANGID langid)
  218. {
  219. TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::SetLanguageID");
  220. Trace(TEXT("lcid %0x8"), langid);
  221. if ( !langid )
  222. langid = GetUserDefaultUILanguage();
  223. _langid = langid; // can hardly go wrong...
  224. TraceLeaveResult(S_OK);
  225. }
  226. /*-----------------------------------------------------------------------------
  227. / IDsDisplaySpecifier::GetDisplaySpecifier
  228. / ----------------------------------------
  229. / Bind to the display specifier for a given class, try the users
  230. / locale, then the default locale calling ADsOpenObject as we
  231. / go. We use the specifier server, username and password.
  232. /
  233. / In:
  234. / pszObjectClass => object class to look up
  235. / riid, ppv => used to retrieve the COM object
  236. /
  237. / Out:
  238. HRESULT
  239. /----------------------------------------------------------------------------*/
  240. STDMETHODIMP CDsDisplaySpecifier::GetDisplaySpecifier(LPCWSTR pszObjectClass, REFIID riid, void **ppv)
  241. {
  242. HRESULT hres;
  243. CLASSCACHEGETINFO ccgi = { 0 };
  244. USES_CONVERSION;
  245. TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::GetDisplaySpecifer");
  246. Trace(TEXT("pszObjectClass: %s"), pszObjectClass ? W2CT(pszObjectClass):TEXT("<none>"));
  247. // fill out the display specifier record
  248. ccgi.pObjectClass = (LPWSTR)pszObjectClass;
  249. ccgi.pServer = (LPWSTR)_pszServer;
  250. ccgi.pUserName = (LPWSTR)_pszUserName;
  251. ccgi.pPassword = (LPWSTR)_pszPassword;
  252. ccgi.langid = _langid;
  253. hres = ::GetDisplaySpecifier(&ccgi, riid, ppv);
  254. FailGracefully(hres, "Failed when calling GetDisplaySpecifier");
  255. exit_gracefully:
  256. TraceLeaveResult(hres);
  257. }
  258. /*-----------------------------------------------------------------------------
  259. / IDsDisplaySpecifier::GetFriendlyClassName
  260. / -----------------------------------------
  261. / Retrieve the localised (friendly) name for an LDAP object class. If
  262. / the display specifier doesn't give a friendly name for the class
  263. / then we return the name we were originally given.
  264. /
  265. / In:
  266. / pszObjectClass => object class to look up
  267. / pszBuffer, cchBuffer = buffer to recieve the string
  268. /
  269. / Out:
  270. HRESULT
  271. /----------------------------------------------------------------------------*/
  272. STDMETHODIMP CDsDisplaySpecifier::GetFriendlyClassName(LPCWSTR pszObjectClass, LPWSTR pszBuffer, INT cchBuffer)
  273. {
  274. HRESULT hres;
  275. LPCLASSCACHEENTRY pcce = NULL;
  276. USES_CONVERSION;
  277. TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::GetFriendlyClassName");
  278. if ( !pszObjectClass || !pszBuffer )
  279. ExitGracefully(hres, E_INVALIDARG, "No class, or no buffer failure");
  280. Trace(TEXT("pszObjectClass: %s"), W2CT(pszObjectClass));
  281. // fetch a record from the cache, if we found it then set pszObjectClass
  282. // to be the friendly class name, otherwise we just return the class
  283. // name we were given.
  284. hres = _GetClassCacheInfo(pszObjectClass, NULL, CLASSCACHE_FRIENDLYNAME, &pcce);
  285. FailGracefully(hres, "Failed to get class information from cache");
  286. if ( pcce->dwCached & CLASSCACHE_FRIENDLYNAME)
  287. {
  288. Trace(TEXT("Friendly class name: %s"), W2CT(pcce->pFriendlyClassName));
  289. pszObjectClass = pcce->pFriendlyClassName;
  290. }
  291. StrCpyNW(pszBuffer, pszObjectClass, cchBuffer);
  292. hres = S_OK;
  293. exit_gracefully:
  294. ClassCache_ReleaseClassInfo(&pcce);
  295. TraceLeaveResult(hres);
  296. }
  297. /*-----------------------------------------------------------------------------
  298. / IDsDisplaySpecifier::GetFriendlyAttributeName
  299. / ---------------------------------------------
  300. / Lookup the classes display speifier, then check the attributeNames property
  301. / for a property name pair that matches the given attribute name. With
  302. / this information return that name to the caller, if that fails then
  303. / return the original name.
  304. /
  305. / In:
  306. / pszObjectClass -> class name to look up in the cache
  307. / pszAttributeName -> attribute name to look up in the cache
  308. / pszBuffer -> buffer to be filled
  309. / cchBuffer = size of the buffer
  310. /
  311. / Out:
  312. HRESULT
  313. /----------------------------------------------------------------------------*/
  314. STDMETHODIMP CDsDisplaySpecifier::GetFriendlyAttributeName(LPCWSTR pszObjectClass, LPCWSTR pszAttributeName, LPWSTR pszBuffer, UINT cchBuffer)
  315. {
  316. HRESULT hres;
  317. LPCLASSCACHEENTRY pcce = NULL;
  318. INT index;
  319. USES_CONVERSION;
  320. TraceEnter(TRACE_CACHE, "DsGetFriendlyAttributeName");
  321. if ( !pszObjectClass || !pszAttributeName || !pszBuffer || !cchBuffer )
  322. ExitGracefully(hres, E_INVALIDARG, "Bad class/attribute/return buffer");
  323. Trace(TEXT("pszbjectClass: %s"), W2CT(pszObjectClass));
  324. Trace(TEXT("pszAttributeName: %s"), W2CT(pszAttributeName));
  325. Trace(TEXT("pszBuffer %x, cchBuffer %d"), pszBuffer, cchBuffer);
  326. hres = _GetClassCacheInfo(pszObjectClass, NULL, CLASSCACHE_ATTRIBUTENAMES, &pcce);
  327. FailGracefully(hres, "Failed to get class information from cache");
  328. if ( pcce->dwCached & CLASSCACHE_ATTRIBUTENAMES )
  329. {
  330. ATTRIBUTENAME an = { 0 };
  331. an.pName = (LPWSTR)pszAttributeName;
  332. index = DPA_Search(pcce->hdpaAttributeNames, &an, 0, _CompareAttributeNameCB, NULL, DPAS_SORTED);
  333. if ( index != -1 )
  334. {
  335. LPATTRIBUTENAME pAN = (LPATTRIBUTENAME)DPA_GetPtr(pcce->hdpaAttributeNames, index);
  336. if (pAN)
  337. {
  338. pszAttributeName = pAN->pDisplayName;
  339. TraceAssert(pszAttributeName);
  340. }
  341. }
  342. }
  343. StrCpyNW(pszBuffer, pszAttributeName, cchBuffer);
  344. hres = S_OK;
  345. exit_gracefully:
  346. ClassCache_ReleaseClassInfo(&pcce);
  347. TraceLeaveResult(hres);
  348. }
  349. /*-----------------------------------------------------------------------------
  350. / IDsDisplaySpecifier::IsClassContainer
  351. / -------------------------------------
  352. / Return TRUE/FALSE indicating if the specified object class is a container,
  353. / we determine this both from the schema and the display specifier.
  354. /
  355. / The schema indicates if the class can container other objects, if so
  356. / then the object is a container. In the display specifier we have
  357. / an attribute "treatAsLeaf" which we use to override this setting, this
  358. / is used both from the admin tools and client UI.
  359. /
  360. / In:
  361. / pszObjectClass => object class to look up
  362. / pszADsPath => ADsPath of an object in the DS we can bind to and fetch
  363. / schema information from.
  364. / dwFlags => flags controlling this API:
  365. / DSICCF_IGNORETREATASLEAF = 1 => return schema attribute only, don't
  366. / override with treatAsLeaf attribute
  367. / from display specifier.
  368. / Out:
  369. BOOL
  370. /----------------------------------------------------------------------------*/
  371. STDMETHODIMP_(BOOL) CDsDisplaySpecifier::IsClassContainer(LPCWSTR pszObjectClass, LPCWSTR pszADsPath, DWORD dwFlags)
  372. {
  373. HRESULT hres;
  374. BOOL fres = FALSE;
  375. LPCLASSCACHEENTRY pcce = NULL;
  376. USES_CONVERSION;
  377. TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::IsClassContainer");
  378. if ( !pszObjectClass )
  379. ExitGracefully(hres, E_INVALIDARG, "No object class failure");
  380. Trace(TEXT("pszObjectClass: %s"), W2CT(pszObjectClass));
  381. Trace(TEXT("dwFlags %x"), dwFlags);
  382. hres = _GetClassCacheInfo(pszObjectClass,pszADsPath, CLASSCACHE_CONTAINER|CLASSCACHE_TREATASLEAF, &pcce);
  383. FailGracefully(hres, "Failed to get class information from cache");
  384. fres = _IsClassContainer(pcce, dwFlags & DSICCF_IGNORETREATASLEAF);
  385. Trace(TEXT("_IsClassContainer returns %d"), fres);
  386. exit_gracefully:
  387. ClassCache_ReleaseClassInfo(&pcce);
  388. TraceLeaveValue(fres);
  389. }
  390. /*-----------------------------------------------------------------------------
  391. / IDsDisplaySpecifier::GetIconLocation
  392. / ------------------------------------
  393. / Fetch the location of an icon from the DS, returning both the filename and
  394. / the resource ID as required. The caller can then load the image, or
  395. / display this information in a dialog.
  396. /
  397. / In:
  398. / pszObjectClass => class to retrieve for
  399. / dwFlags = flags for extraction:
  400. /
  401. / One of the following:
  402. / DSGIF_ISNORMAL => standard icon, or,
  403. / DSGIF_OPEN => open icon (open folders etc), or,
  404. / DSGIF_DISABLED => disabled icon (eg. disabled user account).
  405. /
  406. / Combined with any of the:
  407. / DSGIF_GETDEFAULTICON => if no icon exists for this object, return the default document
  408. / icon from shell32.
  409. /
  410. / pszBuffer, cchBuffer => buffer to recieve the filename
  411. / presid => receives the resource id, +ve for index, -ve for resource
  412. /
  413. / Out:
  414. / HRESULT
  415. /----------------------------------------------------------------------------*/
  416. STDMETHODIMP CDsDisplaySpecifier::GetIconLocation(LPCWSTR pszObjectClass, DWORD dwFlags, LPWSTR pszBuffer, INT cchBuffer, INT* presid)
  417. {
  418. HRESULT hres;
  419. LPCLASSCACHEENTRY pcce = NULL;
  420. USES_CONVERSION;
  421. TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::GetIconLocation");
  422. if ( !pszObjectClass || !pszBuffer )
  423. ExitGracefully(hres, E_INVALIDARG, "No object class/buffer failure");
  424. Trace(TEXT("pszObjectClass: %s"), W2CT(pszObjectClass));
  425. Trace(TEXT("dwFlags %x"), dwFlags);
  426. hres = _GetClassCacheInfo(pszObjectClass, NULL, CLASSCACHE_ICONS, &pcce);
  427. FailGracefully(hres, "Failed to get class information from cache");
  428. hres = _GetIconLocation(pcce, dwFlags, pszBuffer, cchBuffer, presid);
  429. FailGracefully(hres, "Failed calling GetIconLocation");
  430. exit_gracefully:
  431. ClassCache_ReleaseClassInfo(&pcce);
  432. TraceLeaveResult(hres);
  433. }
  434. /*-----------------------------------------------------------------------------
  435. / IDsDisplaySpecifier::GetIcon
  436. / ----------------------------
  437. / Load the icon for the object class given. Icon information is stored in the
  438. / display specifier, we support 15 different states (open, closed, disabled etc).
  439. /
  440. / We look up the resource name from the DS and we then call PrivateExtractIcons
  441. / to load the object from the file.
  442. /
  443. / In:
  444. / pszObjectClass => class to retrieve for
  445. / dwFlags = flags for extraction:
  446. /
  447. / One of the following:
  448. / DSGIF_ISNORMAL => standard icon, or,
  449. / DSGIF_OPEN => open icon (open folders etc), or,
  450. / DSGIF_DISABLED => disabled icon (eg. disabled user account).
  451. /
  452. / Combined with any of the:
  453. / DSGIF_GETDEFAULTICON => if no icon exists for this object, return the default document
  454. / icon from shell32.
  455. /
  456. / cxImage, cyImage = size of image to load
  457. /
  458. / Out:
  459. / HICON / == NULL if failed
  460. /----------------------------------------------------------------------------*/
  461. STDMETHODIMP_(HICON) CDsDisplaySpecifier::GetIcon(LPCWSTR pszObjectClass, DWORD dwFlags, INT cxImage, INT cyImage)
  462. {
  463. HRESULT hres;
  464. HICON hIcon = NULL;
  465. WCHAR szBuffer[MAX_PATH];
  466. INT resid;
  467. USES_CONVERSION;
  468. TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::GetIcon");
  469. if ( !pszObjectClass )
  470. ExitGracefully(hres, E_INVALIDARG, "no object class specified");
  471. Trace(TEXT("pszObjectClass %s, dwFlags %x, cxImage %d, cyImage %d"), W2CT(pszObjectClass), dwFlags, cxImage, cyImage);
  472. hres = GetIconLocation(pszObjectClass, dwFlags, szBuffer, ARRAYSIZE(szBuffer), &resid);
  473. FailGracefully(hres, "Failed when calling GetIconLocation");
  474. if ( hres == S_OK )
  475. {
  476. Trace(TEXT("Calling PrivateExtractIcons on %s,%d"), W2CT(szBuffer), resid);
  477. if ( 1 != PrivateExtractIcons(szBuffer, resid, cxImage, cyImage, &hIcon, NULL, 1, LR_LOADFROMFILE) )
  478. ExitGracefully(hres, E_FAIL, "Failed to load the icon given its path etc");
  479. hres = S_OK; // success
  480. }
  481. exit_gracefully:
  482. if ( !hIcon && (dwFlags & DSGIF_GETDEFAULTICON) )
  483. {
  484. //
  485. // failed to load the icon and they really want the default document, so give it to them
  486. //
  487. TraceMsg("Failed to load the icon, so picking up default document image");
  488. if ( 1 != PrivateExtractIcons(L"shell32.dll", -1, cxImage, cyImage, &hIcon, NULL, 1, LR_LOADFROMFILE) )
  489. {
  490. TraceMsg("Failed to load the default document icon from shell32");
  491. }
  492. }
  493. TraceLeaveValue(hIcon);
  494. }
  495. /*-----------------------------------------------------------------------------
  496. / IDsDisplaySpecifier::GetClassCreationInfo
  497. / -----------------------------------------
  498. / Given an object class return the CLSIDs of the objects that make up
  499. / its creation wizard.
  500. /
  501. / In:
  502. / pszObjectClass -> class to enumerate from
  503. / ppdscci -> DSCREATECLASSINFO structure pointer to fill
  504. /
  505. / Out:
  506. HRESULT
  507. /----------------------------------------------------------------------------*/
  508. STDMETHODIMP CDsDisplaySpecifier::GetClassCreationInfo(LPCWSTR pszObjectClass, LPDSCLASSCREATIONINFO* ppdscci)
  509. {
  510. HRESULT hres;
  511. LPDSCLASSCREATIONINFO pdscci = NULL;
  512. LPCLASSCACHEENTRY pcce = NULL;
  513. DWORD cbStruct = SIZEOF(DSCLASSCREATIONINFO);
  514. INT i;
  515. USES_CONVERSION;
  516. TraceEnter(TRACE_CACHE, "CDsDisplaySpecifer::GetClassCreationInfo");
  517. if ( !pszObjectClass || !ppdscci )
  518. ExitGracefully(hres, E_INVALIDARG, "No object class/pdscci passed");
  519. // call the caching code to retrieve the creation wizard information
  520. hres = _GetClassCacheInfo(pszObjectClass, NULL, CLASSCACHE_CREATIONINFO, &pcce);
  521. FailGracefully(hres, "Failed to get class information from cache");
  522. // now allocate the creation wizard structure and pass it to the
  523. // caller with the information filled in.
  524. if ( pcce->hdsaWizardExtn )
  525. cbStruct += SIZEOF(GUID)*(DSA_GetItemCount(pcce->hdsaWizardExtn)-1); // -1 as structure already has 1 in the array!
  526. Trace(TEXT("Allocating creationg structure: cbStruct %d"), cbStruct);
  527. pdscci = (LPDSCLASSCREATIONINFO)LocalAlloc(LPTR, cbStruct);
  528. if ( !pdscci )
  529. ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate return structure");
  530. //pdscci->dwFlags = 0;
  531. //pdscci->clsidWizardDialog = { 0 };
  532. //pdscci->clsidWizardPimaryPage = { 0 };
  533. //pdscci->cWizardExtensions = 0;
  534. //pdscci->aWizardExtensions = { 0 };
  535. if ( pcce->dwCached & CLASSCACHE_WIZARDDIALOG )
  536. {
  537. TraceGUID("clsidWizardDialog is ", pcce->clsidWizardDialog);
  538. pdscci->dwFlags |= DSCCIF_HASWIZARDDIALOG;
  539. pdscci->clsidWizardDialog = pcce->clsidWizardDialog;
  540. }
  541. if ( pcce->dwCached & CLASSCACHE_WIZARDPRIMARYPAGE )
  542. {
  543. TraceGUID("clsidWizardPrimaryPage is ", pcce->clsidWizardPrimaryPage);
  544. pdscci->dwFlags |= DSCCIF_HASWIZARDPRIMARYPAGE;
  545. pdscci->clsidWizardPrimaryPage = pcce->clsidWizardPrimaryPage;
  546. }
  547. if ( pcce->hdsaWizardExtn )
  548. {
  549. pdscci->cWizardExtensions = DSA_GetItemCount(pcce->hdsaWizardExtn);
  550. Trace(TEXT("Class has %d wizard extensions"), pdscci->cWizardExtensions);
  551. for ( i = 0 ; i < DSA_GetItemCount(pcce->hdsaWizardExtn) ; i++ )
  552. {
  553. LPGUID pGUID = (LPGUID)DSA_GetItemPtr(pcce->hdsaWizardExtn, i);
  554. TraceAssert(pGUID);
  555. TraceGUID("Wizard extension %d is ", *pGUID);
  556. pdscci->aWizardExtensions[i] = *pGUID;
  557. }
  558. }
  559. hres = S_OK; // success
  560. exit_gracefully:
  561. ClassCache_ReleaseClassInfo(&pcce);
  562. // it failed, therefore release pInfo if we have one, before setting
  563. // the return pointer for the caller.
  564. if ( FAILED(hres) && pdscci )
  565. {
  566. TraceMsg("Failed, so freeing info structure");
  567. LocalFree(pdscci);
  568. pdscci = NULL;
  569. }
  570. if ( ppdscci )
  571. {
  572. Trace(TEXT("Setting ppInfo to %08x"), pdscci);
  573. *ppdscci = pdscci;
  574. }
  575. TraceLeaveResult(hres);
  576. }
  577. /*-----------------------------------------------------------------------------
  578. / IDsDisplaySpecifier::EnumClassAttributes
  579. / ----------------------------------------
  580. / Enumerate all the attributes and their friendly names for the given object class.
  581. / The code looks up the display specifier and then calls given callback for each one,
  582. / passing the attribute name and its given "friendly name".
  583. /
  584. / In:
  585. / pszObjectClass -> class to enumerate from
  586. / pEnumCB -> callback function to enumerate to
  587. / lParam = lParam to pass to the CB fucntion
  588. /
  589. / Out:
  590. HRESULT
  591. /----------------------------------------------------------------------------*/
  592. // NTRAID 455406: this should return an enumerator
  593. typedef struct
  594. {
  595. LPDSENUMATTRIBUTES pcbEnum;
  596. LPARAM lParam;
  597. } CLASSENUMCBSTATE, * LPCLASSENUMCBSTATE;
  598. INT _EnumClassAttributesCB(LPVOID p, LPVOID pData)
  599. {
  600. LPATTRIBUTENAME pAttributeName = (LPATTRIBUTENAME)p;
  601. LPCLASSENUMCBSTATE pState = (LPCLASSENUMCBSTATE)pData;
  602. return SUCCEEDED(pState->pcbEnum(pState->lParam,
  603. pAttributeName->pName, pAttributeName->pDisplayName, pAttributeName->dwFlags));
  604. }
  605. STDMETHODIMP CDsDisplaySpecifier::EnumClassAttributes(LPCWSTR pszObjectClass, LPDSENUMATTRIBUTES pcbEnum, LPARAM lParam)
  606. {
  607. HRESULT hres;
  608. LPCLASSCACHEENTRY pcce = NULL;
  609. USES_CONVERSION;
  610. TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::EnumClassAttributes");
  611. if ( !pszObjectClass || !pcbEnum )
  612. ExitGracefully(hres, E_INVALIDARG, "Bad class/cb function");
  613. Trace(TEXT("pszObjectClass: %s"), W2CT(pszObjectClass));
  614. // call the cache code to pick up the friendly name, having done this we
  615. // can then copy it to the user buffer
  616. hres = _GetClassCacheInfo(pszObjectClass, NULL, CLASSCACHE_ATTRIBUTENAMES, &pcce);
  617. FailGracefully(hres, "Failed to get class information from cache");
  618. if ( pcce->dwCached & CLASSCACHE_ATTRIBUTENAMES )
  619. {
  620. CLASSENUMCBSTATE state = { pcbEnum, lParam };
  621. DPA_EnumCallback(pcce->hdpaAttributeNames, _EnumClassAttributesCB, &state);
  622. }
  623. hres = S_OK;
  624. exit_gracefully:
  625. ClassCache_ReleaseClassInfo(&pcce);
  626. TraceLeaveResult(hres);
  627. }
  628. /*-----------------------------------------------------------------------------
  629. / IDsDisplaySpecifier::GetAttributeADsType
  630. / ----------------------------------------
  631. / Look up the given attribute for its ADsType.
  632. /
  633. / In:
  634. / pszAttributeName = attribute to look up
  635. /
  636. / Out:
  637. / ADSTYPE
  638. /----------------------------------------------------------------------------*/
  639. STDMETHODIMP_(ADSTYPE) CDsDisplaySpecifier::GetAttributeADsType(LPCWSTR pszAttributeName)
  640. {
  641. TraceEnter(TRACE_CACHE, "CDsDisplaySpecifier::GetAttributeADsType");
  642. CLASSCACHEGETINFO ccgi = { 0 };
  643. ccgi.pServer = _pszServer;
  644. ccgi.pUserName = _pszUserName;
  645. ccgi.pPassword = _pszPassword;
  646. if ( _dwFlags & DSSSF_SIMPLEAUTHENTICATE )
  647. ccgi.dwFlags |= CLASSCACHE_SIMPLEAUTHENTICATE;
  648. if ( _dwFlags & DSSSF_DSAVAILABLE )
  649. ccgi.dwFlags |= CLASSCACHE_DSAVAILABLE;
  650. ADSTYPE adt = ClassCache_GetADsTypeFromAttribute(&ccgi, pszAttributeName);
  651. TraceLeaveValue(adt);
  652. }
  653. /*-----------------------------------------------------------------------------
  654. / Externally exported cache APIs
  655. /----------------------------------------------------------------------------*/
  656. CDsDisplaySpecifier g_dsDisplaySpecifier;
  657. //
  658. // these are exported for backwards compatiblity. We used to expose a series
  659. // of DsXXX APIs which dsquery, dsfolder and dsadmin all called. We have
  660. // now migrated these to a COM interface.
  661. //
  662. STDAPI_(HICON) DsGetIcon(DWORD dwFlags, LPWSTR pszObjectClass, INT cxImage, INT cyImage)
  663. {
  664. return g_dsDisplaySpecifier.GetIcon(pszObjectClass, dwFlags, cxImage, cyImage);
  665. }
  666. STDAPI DsGetFriendlyClassName(LPWSTR pszObjectClass, LPWSTR pszBuffer, UINT cchBuffer)
  667. {
  668. return g_dsDisplaySpecifier.GetFriendlyClassName(pszObjectClass, pszBuffer, cchBuffer);
  669. }