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.

1005 lines
26 KiB

  1. // DSCache.cpp : implementation file
  2. //
  3. //+-------------------------------------------------------------------------
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1999
  7. //
  8. // File: DSCache.cpp
  9. //
  10. // Contents: TBD
  11. //
  12. // History: 31-jan-97 jimharr created
  13. //
  14. //--------------------------------------------------------------------------
  15. #include "stdafx.h"
  16. #include "resource.h"
  17. #include "util.h"
  18. #include "dsutil.h"
  19. #include "dscache.h"
  20. #include "dscookie.h"
  21. #include "newobj.h"
  22. #include "gencreat.h"
  23. #include "querysup.h"
  24. #ifdef _DEBUG
  25. #define new DEBUG_NEW
  26. #undef THIS_FILE
  27. static char THIS_FILE[] = __FILE__;
  28. #endif
  29. //////////////////////////////////////////////////////////////////////////
  30. // helper functions
  31. HRESULT HrVariantToStringList(const VARIANT& refvar, CStringList& refstringlist); // prototype
  32. static CString g_szAllTypesArr[8];
  33. void InitGroupTypeStringTable()
  34. {
  35. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  36. CString szSecTypeArr[2];
  37. szSecTypeArr[0].LoadString(IDS_GROUP_SECURITY);
  38. szSecTypeArr[1].LoadString(IDS_GROUP_DISTRIBUTION);
  39. CString szTypeArr[4];
  40. szTypeArr[0].LoadString(IDS_GROUP_GLOBAL);
  41. szTypeArr[1].LoadString(IDS_GROUP_DOMAIN_LOCAL);
  42. szTypeArr[2].LoadString(IDS_GROUP_UNIVERSAL);
  43. szTypeArr[3].LoadString(IDS_GROUP_BUILTIN_LOCAL);
  44. for (int iSec=0; iSec<2; iSec++)
  45. {
  46. for (int iType=0; iType<4; iType++)
  47. {
  48. int k = (iSec*4)+iType;
  49. g_szAllTypesArr[k] = szSecTypeArr[iSec];
  50. g_szAllTypesArr[k] += szTypeArr[iType];
  51. }
  52. }
  53. }
  54. LPCWSTR GetGroupTypeStringHelper(INT GroupType)
  55. {
  56. // need to map the type into the array index
  57. // first part (2 types)
  58. int iSec = (GroupType & GROUP_TYPE_SECURITY_ENABLED) ? 0 : 1;
  59. //
  60. // second part (4 types)
  61. //
  62. // NOTE : can't use the following switch here because there may be some
  63. // extra bits used in the group type. See bug #90507.
  64. // switch (GroupType & ~GROUP_TYPE_SECURITY_ENABLED)
  65. //
  66. int iType = -1;
  67. if (GroupType & GROUP_TYPE_ACCOUNT_GROUP)
  68. {
  69. iType = 0;
  70. }
  71. else if (GroupType & GROUP_TYPE_RESOURCE_GROUP)
  72. {
  73. iType = 1;
  74. }
  75. else if (GroupType & GROUP_TYPE_UNIVERSAL_GROUP)
  76. {
  77. iType = 2;
  78. }
  79. else if (GroupType & GROUP_TYPE_BUILTIN_LOCAL_GROUP ||
  80. GroupType & GROUP_TYPE_RESOURCE_GROUP)
  81. {
  82. iType = 3;
  83. }
  84. else
  85. {
  86. ASSERT(FALSE); // this should never happen, invalid bit pattern
  87. return NULL;
  88. }
  89. int k = (iSec*4)+iType;
  90. ASSERT((k>=0) && (k<8));
  91. ASSERT(!g_szAllTypesArr[k].IsEmpty());
  92. return g_szAllTypesArr[k];
  93. }
  94. //////////////////////////////////////////////////////////////////////////
  95. // CDSClassCacheItemBase
  96. CDSClassCacheItemBase::~CDSClassCacheItemBase()
  97. {
  98. if (m_pMandPropsList != NULL)
  99. {
  100. delete m_pMandPropsList;
  101. }
  102. if (m_pAdminContextMenu != NULL)
  103. {
  104. delete[] m_pAdminContextMenu;
  105. }
  106. if (m_pAdminPropertyPages != NULL)
  107. {
  108. delete[] m_pAdminPropertyPages ;
  109. }
  110. if (m_pAdminMultiSelectPropertyPages != NULL)
  111. {
  112. delete[] m_pAdminMultiSelectPropertyPages;
  113. }
  114. }
  115. HRESULT CDSClassCacheItemBase::CreateItem(LPCWSTR lpszClass,
  116. IADs* pDSObject,
  117. CDSComponentData* pCD,
  118. CDSClassCacheItemBase** ppItem)
  119. {
  120. ASSERT(ppItem != NULL);
  121. // determine which type of object we have
  122. if (wcscmp(lpszClass, L"user") == 0
  123. #ifdef INETORGPERSON
  124. || _wcsicmp(lpszClass, L"inetOrgPerson") == 0
  125. #endif
  126. )
  127. {
  128. *ppItem = new CDSClassCacheItemUser;
  129. }
  130. else if(wcscmp(lpszClass,L"group") == 0)
  131. {
  132. *ppItem = new CDSClassCacheItemGroup;
  133. }
  134. else
  135. {
  136. *ppItem = new CDSClassCacheItemGeneric;
  137. }
  138. if (*ppItem == NULL)
  139. return E_OUTOFMEMORY;
  140. HRESULT hr = (*ppItem)->Init(lpszClass, pDSObject, pCD);
  141. if (FAILED(hr))
  142. {
  143. delete *ppItem;
  144. *ppItem = NULL;
  145. }
  146. return hr;
  147. }
  148. HRESULT CDSClassCacheItemBase::Init(LPCWSTR lpszClass, IADs* pDSObject, CDSComponentData *pCD)
  149. {
  150. HRESULT hr = S_OK;
  151. // init to default values
  152. m_bIsContainer = FALSE;
  153. m_GUID = GUID_NULL;
  154. m_szClass = lpszClass;
  155. m_szFriendlyClassName = lpszClass;
  156. m_szNamingAttribute = L"cn";
  157. ASSERT(!m_szClass.IsEmpty());
  158. // get schema path to bind to class object in the schema
  159. CComBSTR bstrSchema;
  160. if (pDSObject != NULL)
  161. {
  162. // we have an ADSI pointer to use
  163. hr = pDSObject->get_Schema(&bstrSchema);
  164. }
  165. else
  166. {
  167. // no object yet (create new case)
  168. CString strSchema;
  169. pCD->GetBasePathsInfo()->GetAbstractSchemaPath(strSchema);
  170. strSchema += L"/";
  171. strSchema += lpszClass;
  172. bstrSchema = (LPCWSTR)strSchema;
  173. }
  174. // bind to the schema object
  175. CComPtr<IADsClass> spDsClass;
  176. hr = DSAdminOpenObject(bstrSchema,
  177. IID_IADsClass,
  178. (LPVOID *)&spDsClass,
  179. TRUE /*bServer*/);
  180. if (SUCCEEDED(hr))
  181. {
  182. // got class info from the schema
  183. // se the container flag
  184. if ((!wcscmp(lpszClass, L"computer")) ||
  185. (!wcscmp(lpszClass, L"user")) ||
  186. #ifdef INETORGPERSON
  187. (!wcscmp(lpszClass, L"inetOrgPerson")) ||
  188. #endif
  189. (!wcscmp(lpszClass,L"group")))
  190. {
  191. // special classes we know about
  192. m_bIsContainer = pCD->ExpandComputers();
  193. }
  194. else
  195. {
  196. // generic class, ask the schema
  197. VARIANT_BOOL bIsContainer;
  198. hr = spDsClass->get_Container(&bIsContainer);
  199. if (SUCCEEDED(hr))
  200. {
  201. if (bIsContainer)
  202. {
  203. m_bIsContainer = TRUE;
  204. }
  205. }
  206. }
  207. // get the class GUID
  208. CComVariant Var;
  209. hr = spDsClass->Get(L"schemaIDGUID", &Var);
  210. if (SUCCEEDED(hr))
  211. {
  212. GUID* pgtemp;
  213. pgtemp = (GUID*) (Var.parray->pvData);
  214. m_GUID = *pgtemp;
  215. }
  216. // get the friendly class name
  217. WCHAR wszBuf[120];
  218. hr = pCD->GetBasePathsInfo()->GetFriendlyClassName(lpszClass, wszBuf, 120);
  219. if (SUCCEEDED(hr))
  220. {
  221. m_szFriendlyClassName = wszBuf;
  222. }
  223. // get the naming attribute
  224. Var.Clear();
  225. hr = spDsClass->get_NamingProperties(&Var);
  226. // fill out m_szNamingAttribute here.
  227. if (SUCCEEDED(hr))
  228. {
  229. m_szNamingAttribute = Var.bstrVal;
  230. }
  231. }
  232. else
  233. {
  234. // we failed getting class info from the schema
  235. if (wcscmp(L"Unknown", lpszClass) == 0)
  236. {
  237. m_szFriendlyClassName.LoadString(IDS_DISPLAYTEXT_NONE);
  238. }
  239. }
  240. // locate the column set for this class
  241. m_pColumnSet = pCD->FindColumnSet(lpszClass);
  242. ASSERT(m_pColumnSet != NULL);
  243. // set the icon index(es)
  244. SetIconData(pCD);
  245. return S_OK;
  246. }
  247. CMandatoryADsAttributeList*
  248. CDSClassCacheItemBase::GetMandatoryAttributeList(CDSComponentData* pCD)
  249. {
  250. // got it already cached ?
  251. if (m_pMandPropsList != NULL) {
  252. return m_pMandPropsList;
  253. }
  254. // need to build the list
  255. HRESULT hr = S_OK;
  256. CComBSTR bstrSchema;
  257. IADsClass * pDsClass = NULL;
  258. CMandatoryADsAttribute* pNamingAttribute = NULL;
  259. POSITION pos = NULL;
  260. CComVariant MandatoryList;
  261. CStringList Strings;
  262. CString csProp;
  263. LPTSTR pszSyntax;
  264. const LPTSTR pszNameSyntax = L"2.5.5.12";
  265. CDSSearch SchemaSrch(pCD->m_pClassCache, pCD);
  266. CString strPhysSchema;
  267. const int cCols = 2;
  268. LPTSTR pszAttributes[cCols] = {L"ADsPath",
  269. L"attributeSyntax" };
  270. ADS_SEARCH_COLUMN ColumnData;
  271. m_pMandPropsList = new CMandatoryADsAttributeList;
  272. // get the class object from the schema
  273. CString strSchema;
  274. pCD->GetBasePathsInfo()->GetAbstractSchemaPath(strSchema);
  275. strSchema += L"/";
  276. strSchema += GetClassName();
  277. bstrSchema = (LPCWSTR)strSchema;
  278. hr = DSAdminOpenObject(bstrSchema,
  279. IID_IADsClass,
  280. (LPVOID *)&pDsClass,
  281. TRUE /*bServer*/);
  282. if (FAILED(hr))
  283. goto CleanUp;
  284. pCD->GetBasePathsInfo()->GetSchemaPath(strPhysSchema);
  285. SchemaSrch.Init (strPhysSchema);
  286. SchemaSrch.SetSearchScope(ADS_SCOPE_ONELEVEL);
  287. hr = pDsClass->get_MandatoryProperties (&MandatoryList);
  288. if (FAILED(hr))
  289. goto CleanUp;
  290. hr = HrVariantToStringList (IN MandatoryList, OUT Strings);
  291. if (FAILED(hr))
  292. goto CleanUp;
  293. pos = Strings.GetHeadPosition();
  294. TRACE(_T("class: %s\n"), GetClassName());
  295. while (pos != NULL) {
  296. csProp = Strings.GetNext(INOUT pos);
  297. // skip WHAT????
  298. if (!wcscmp(csProp, gsz_objectClass) ||
  299. !wcscmp(csProp, gsz_nTSecurityDescriptor) ||
  300. !wcscmp(csProp, gsz_instanceType) ||
  301. !wcscmp(csProp, gsz_objectCategory) ||
  302. !wcscmp(csProp, gsz_objectSid)) {
  303. continue;
  304. }
  305. TRACE(_T("\tmandatory prop: %s.\n"), csProp);
  306. CString csFilter = CString(L"(&(objectClass=attributeSchema)(lDAPDisplayName=") +
  307. csProp + CString(L"))");
  308. SchemaSrch.SetFilterString((LPTSTR)(LPCTSTR)csFilter);
  309. SchemaSrch.SetAttributeList (pszAttributes, cCols);
  310. hr = SchemaSrch.DoQuery ();
  311. if (SUCCEEDED(hr)) {
  312. hr = SchemaSrch.GetNextRow();
  313. if (SUCCEEDED(hr)) {
  314. hr = SchemaSrch.GetColumn(pszAttributes[cCols - 1],
  315. &ColumnData);
  316. TRACE(_T("\t\tattributeSyntax: %s\n"),
  317. ColumnData.pADsValues->CaseIgnoreString);
  318. pszSyntax = ColumnData.pADsValues->CaseIgnoreString;
  319. CMandatoryADsAttribute* pAttr = new CMandatoryADsAttribute((LPCTSTR)csProp,
  320. NULL,
  321. pszSyntax);
  322. if (wcscmp(csProp, GetNamingAttribute()) == 0)
  323. pNamingAttribute = pAttr;
  324. else
  325. m_pMandPropsList->AddTail(pAttr);
  326. } // if
  327. SchemaSrch.m_pObj->FreeColumn (&ColumnData);
  328. } // if
  329. } // while
  330. // make sure naming attribute is present
  331. if (pNamingAttribute == NULL)
  332. {
  333. pNamingAttribute = new CMandatoryADsAttribute(GetNamingAttribute(),
  334. NULL,
  335. pszNameSyntax);
  336. }
  337. // make sure the naming attribute is the first in the list
  338. m_pMandPropsList->AddHead(pNamingAttribute);
  339. CleanUp:
  340. if (pDsClass) {
  341. pDsClass->Release();
  342. }
  343. return m_pMandPropsList;
  344. }
  345. CDSColumnSet*
  346. CDSClassCacheItemBase::GetColumnSet()
  347. {
  348. return m_pColumnSet;
  349. }
  350. //
  351. // Display Specifier cached accessors
  352. //
  353. GUID* CDSClassCacheItemBase::GetAdminPropertyPages(UINT* pnCount)
  354. {
  355. *pnCount = m_nAdminPPCount;
  356. return m_pAdminPropertyPages;
  357. }
  358. void CDSClassCacheItemBase::SetAdminPropertyPages(UINT nCount, GUID* pGuids)
  359. {
  360. m_nAdminPPCount = nCount;
  361. if (m_pAdminPropertyPages != NULL)
  362. {
  363. delete[] m_pAdminPropertyPages;
  364. }
  365. m_pAdminPropertyPages = pGuids;
  366. }
  367. GUID* CDSClassCacheItemBase::GetAdminContextMenu(UINT* pnCount)
  368. {
  369. *pnCount = m_nAdminCMCount;
  370. return m_pAdminContextMenu;
  371. }
  372. void CDSClassCacheItemBase::SetAdminContextMenu(UINT nCount, GUID* pGuids)
  373. {
  374. m_nAdminCMCount = nCount;
  375. if (m_pAdminContextMenu != NULL)
  376. {
  377. delete[] m_pAdminContextMenu;
  378. }
  379. m_pAdminContextMenu = pGuids;
  380. }
  381. GUID* CDSClassCacheItemBase::GetAdminMultiSelectPropertyPages(UINT* pnCount)
  382. {
  383. *pnCount = m_nAdminMSPPCount;
  384. return m_pAdminMultiSelectPropertyPages;
  385. }
  386. void CDSClassCacheItemBase::SetAdminMultiSelectPropertyPages(UINT nCount, GUID* pGuids)
  387. {
  388. m_nAdminMSPPCount = nCount;
  389. if (m_pAdminMultiSelectPropertyPages != NULL)
  390. {
  391. delete[] m_pAdminMultiSelectPropertyPages;
  392. }
  393. m_pAdminMultiSelectPropertyPages = pGuids;
  394. }
  395. //////////////////////////////////////////////////////////////////////////
  396. // CDSClassIconIndexes
  397. void CDSClassIconIndexes::SetIconData(LPCWSTR lpszClass, BOOL bContainer, CDSComponentData *pCD, int)
  398. {
  399. DWORD dwBaseFlags = DSGIF_GETDEFAULTICON;
  400. if (bContainer)
  401. dwBaseFlags |= DSGIF_DEFAULTISCONTAINER;
  402. int iIconIndex;
  403. // get the generic icon
  404. HRESULT hr = pCD->AddClassIcon(lpszClass, DSGIF_ISNORMAL | dwBaseFlags, &iIconIndex);
  405. m_iIconIndex = SUCCEEDED(hr) ? iIconIndex : -1;
  406. m_iIconIndexOpen = m_iIconIndexDisabled = m_iIconIndex;
  407. // get the open icon
  408. hr = pCD->AddClassIcon(lpszClass, DSGIF_ISOPEN | dwBaseFlags, &iIconIndex);
  409. if (SUCCEEDED(hr))
  410. {
  411. m_iIconIndexOpen = iIconIndex;
  412. }
  413. // get the disabled icon
  414. hr = pCD->AddClassIcon(lpszClass, DSGIF_ISDISABLED | dwBaseFlags, &iIconIndex);
  415. if (SUCCEEDED(hr))
  416. {
  417. m_iIconIndexDisabled = iIconIndex;
  418. }
  419. TRACE(_T("Added icon for class: %s\n"), lpszClass);
  420. TRACE(_T("Index: %d\n"), m_iIconIndex);
  421. TRACE(_T("Open: %d\n"), m_iIconIndexOpen);
  422. TRACE(_T("Disabled: %d\n"), m_iIconIndexDisabled);
  423. }
  424. //////////////////////////////////////////////////////////////////////////
  425. // CDSClassCacheItemGeneric
  426. inline int CDSClassCacheItemGeneric::GetIconIndex(CDSCookie* pCookie, BOOL bOpen)
  427. {
  428. return m_iconIndexesStandard.GetIconIndex(pCookie->IsDisabled(), bOpen);
  429. }
  430. inline void CDSClassCacheItemGeneric::SetIconData(CDSComponentData *pCD)
  431. {
  432. m_iconIndexesStandard.SetIconData(GetClassName(), IsContainer(), pCD,0);
  433. }
  434. //////////////////////////////////////////////////////////////////////////
  435. // CDSClassCacheItemGroup
  436. inline int CDSClassCacheItemGroup::GetIconIndex(CDSCookie* pCookie, BOOL bOpen)
  437. {
  438. CDSClassIconIndexes* pIndexes = &m_iconIndexesStandard;
  439. CDSCookieInfoBase* pExtraInfo = pCookie->GetExtraInfo();
  440. if ( (pExtraInfo != NULL) && (pExtraInfo->GetClass() == CDSCookieInfoBase::group) )
  441. {
  442. if (((((CDSCookieInfoGroup*)pExtraInfo)->m_GroupType) & GROUP_TYPE_SECURITY_ENABLED) != 0)
  443. pIndexes = & m_iconIndexesAlternate;
  444. }
  445. return pIndexes->GetIconIndex(pCookie->IsDisabled(), bOpen);
  446. }
  447. inline void CDSClassCacheItemGroup::SetIconData(CDSComponentData *pCD)
  448. {
  449. LPCWSTR lpszClass = GetClassName();
  450. m_iconIndexesStandard.SetIconData(lpszClass, IsContainer(), pCD,0);
  451. m_iconIndexesAlternate.SetIconData(lpszClass, IsContainer(), pCD,1);
  452. /*
  453. // test just to get load some icons with a fake class and a fake "groupAlt-Display" object
  454. m_iconIndexesAlternate.SetIconData(L"groupAlt", m_bIsContainer, pCD, 1);
  455. */
  456. }
  457. //////////////////////////////////////////////////////////////////////////
  458. // CDSCache
  459. BOOL CDSCache::ToggleExpandSpecialClasses(BOOL bContainer)
  460. {
  461. _Lock();
  462. BOOL bFound = FALSE;
  463. CDSClassCacheItemBase* pItem;
  464. if (Lookup(L"computer", pItem))
  465. {
  466. pItem->SetContainerFlag(bContainer);
  467. bFound = TRUE;
  468. }
  469. if (Lookup(L"user", pItem))
  470. {
  471. pItem->SetContainerFlag(bContainer);
  472. bFound = TRUE;
  473. }
  474. #ifdef INETORGPERSON
  475. if (Lookup(L"inetOrgPerson", pItem))
  476. {
  477. pItem->SetContainerFlag(bContainer);
  478. bFound = TRUE;
  479. }
  480. #endif
  481. if (Lookup(L"group", pItem))
  482. {
  483. pItem->SetContainerFlag(bContainer);
  484. bFound = TRUE;
  485. }
  486. _Unlock();
  487. return bFound;
  488. }
  489. CDSColumnSet* CDSCache::FindColumnSet(LPCWSTR lpszColumnID)
  490. {
  491. _Lock();
  492. CDSColumnSet* pColumnSet = NULL;
  493. if (_wcsicmp(DEFAULT_COLUMN_SET, lpszColumnID) == 0)
  494. {
  495. //
  496. // return the default column set
  497. //
  498. pColumnSet = dynamic_cast<CDSColumnSet*>(m_ColumnList.GetDefaultColumnSet());
  499. }
  500. else
  501. {
  502. pColumnSet = dynamic_cast<CDSColumnSet*>(m_ColumnList.FindColumnSet(lpszColumnID));
  503. }
  504. _Unlock();
  505. return pColumnSet;
  506. }
  507. CDSClassCacheItemBase* CDSCache::FindClassCacheItem(CDSComponentData* pCD,
  508. LPCWSTR lpszObjectClass,
  509. LPCWSTR lpszObjectLdapPath
  510. )
  511. {
  512. _Lock();
  513. CDSClassCacheItemBase* pDsCacheItem = NULL;
  514. BOOL bFound = m_Map.Lookup(lpszObjectClass, pDsCacheItem);
  515. if (!bFound)
  516. {
  517. // Item not found in cache, create, insert in the cache and return it
  518. TRACE(_T("did not find class <%s> for this item in the Cache.\n"), (LPCWSTR)lpszObjectClass);
  519. // Check to see if the object is a container
  520. CComPtr<IADs> spADsObject = NULL;
  521. if (lpszObjectLdapPath != NULL)
  522. {
  523. DSAdminOpenObject(lpszObjectLdapPath,
  524. IID_IADs,
  525. (LPVOID*)&spADsObject,
  526. TRUE /*bServer*/);
  527. // NOTICE: we might fail to bind here if we do not have read rights
  528. // this will give a NULL spADsObject, that will work just fine on the CreateItem() call below
  529. }
  530. // create object
  531. HRESULT hrCreate = CDSClassCacheItemBase::CreateItem(lpszObjectClass, spADsObject, pCD, &pDsCacheItem);
  532. ASSERT(pDsCacheItem != NULL);
  533. ASSERT(SUCCEEDED(hrCreate));
  534. // set in the cache
  535. m_Map.SetAt(lpszObjectClass, pDsCacheItem);
  536. }
  537. _Unlock();
  538. return pDsCacheItem;
  539. }
  540. #define DS_CACHE_STREAM_VERSION ((DWORD)0x0)
  541. HRESULT CDSCache::Save(IStream* pStm)
  542. {
  543. // save cache version number
  544. HRESULT hr = SaveDWordHelper(pStm, DS_CACHE_STREAM_VERSION);
  545. if (FAILED(hr))
  546. return hr;
  547. // save column list
  548. return m_ColumnList.Save(pStm);
  549. }
  550. HRESULT CDSCache::Load(IStream* pStm)
  551. {
  552. // load cache version number
  553. DWORD dwVersion;
  554. HRESULT hr = LoadDWordHelper(pStm, &dwVersion);
  555. if ( FAILED(hr) ||(dwVersion != DS_CACHE_STREAM_VERSION) )
  556. return E_FAIL;
  557. // load column list
  558. return m_ColumnList.Load(pStm);
  559. }
  560. HRESULT CDSCache::TabCollect_AddMultiSelectPropertyPages(LPPROPERTYSHEETCALLBACK pCall,
  561. LONG_PTR,
  562. LPDATAOBJECT pDataObject,
  563. MyBasePathsInfo* pBasePathsInfo)
  564. {
  565. HRESULT hr = S_OK;
  566. CString szClassName;
  567. CString szDisplayProperty = L"AdminMultiSelectPropertyPages";
  568. GUID* pGuids = NULL;
  569. UINT nCount = 0;
  570. if (IsHomogenousDSSelection(pDataObject, szClassName))
  571. {
  572. //
  573. // Get the guid for the multiselect proppages of the homogenous class selection
  574. //
  575. //
  576. // Check the cache first
  577. //
  578. BOOL bFoundGuids = FALSE;
  579. CDSClassCacheItemBase* pItem = NULL;
  580. BOOL bFoundItem = Lookup(szClassName, pItem);
  581. if (bFoundItem)
  582. {
  583. if (pItem == NULL)
  584. {
  585. ASSERT(FALSE);
  586. bFoundItem = FALSE;
  587. }
  588. else
  589. {
  590. //
  591. // Retrieve guids from cache
  592. //
  593. pGuids = pItem->GetAdminMultiSelectPropertyPages(&nCount);
  594. if (nCount > 0 && pGuids != NULL)
  595. {
  596. bFoundGuids = TRUE;
  597. }
  598. }
  599. }
  600. if (!bFoundGuids)
  601. {
  602. //
  603. // Class cache item did not contain GUID
  604. //
  605. hr = TabCollect_GetDisplayGUIDs(szClassName,
  606. szDisplayProperty,
  607. pBasePathsInfo,
  608. &nCount,
  609. &pGuids);
  610. if (FAILED(hr))
  611. {
  612. //
  613. // Try the default-Display object then
  614. //
  615. hr = TabCollect_GetDisplayGUIDs(L"default",
  616. szDisplayProperty,
  617. pBasePathsInfo,
  618. &nCount,
  619. &pGuids);
  620. if (FAILED(hr))
  621. {
  622. return hr;
  623. }
  624. }
  625. if (bFoundItem)
  626. {
  627. //
  628. // Cache the new guids
  629. //
  630. pItem->SetAdminMultiSelectPropertyPages(nCount, pGuids);
  631. }
  632. }
  633. }
  634. else
  635. {
  636. //
  637. // Get the default multi-select proppages
  638. //
  639. hr = TabCollect_GetDisplayGUIDs(L"default", szDisplayProperty, pBasePathsInfo, &nCount, &pGuids);
  640. //
  641. // Right now there is no default item in the cache so we have to get it each time from
  642. // the DS
  643. //
  644. }
  645. if (SUCCEEDED(hr))
  646. {
  647. if (nCount > 0 && pGuids != NULL)
  648. {
  649. //
  650. // Create all the pages, initialize, and then add them
  651. //
  652. for (UINT nIndex = 0; nIndex < nCount; nIndex++)
  653. {
  654. //
  655. // Create
  656. //
  657. CComPtr<IShellExtInit> spShellInit;
  658. hr = ::CoCreateInstance((pGuids[nIndex]),
  659. NULL,
  660. CLSCTX_INPROC_SERVER,
  661. IID_IShellExtInit,
  662. (PVOID*)&spShellInit);
  663. if (FAILED(hr))
  664. {
  665. continue;
  666. }
  667. //
  668. // Initialize
  669. //
  670. hr = spShellInit->Initialize(NULL, pDataObject, 0);
  671. if (FAILED(hr))
  672. {
  673. continue;
  674. }
  675. //
  676. // Add
  677. //
  678. CComPtr<IShellPropSheetExt> spPropSheetExt;
  679. hr = spShellInit->QueryInterface(IID_IShellPropSheetExt, (PVOID*)&spPropSheetExt);
  680. if (FAILED(hr))
  681. {
  682. continue;
  683. }
  684. hr = spPropSheetExt->AddPages(AddPageProc, (LPARAM)pCall);
  685. if (FAILED(hr))
  686. {
  687. TRACE(TEXT("spPropSheetExt->AddPages failed, hr: 0x%x\n"), hr);
  688. continue;
  689. }
  690. }
  691. }
  692. }
  693. return hr;
  694. }
  695. void CDSCache::_CollectDisplaySettings(MyBasePathsInfo* pBasePathsInfo)
  696. {
  697. static LPCWSTR lpszSettingsObjectClass = L"dsUISettings";
  698. static LPCWSTR lpszSettingsObject = L"cn=DS-UI-Default-Settings";
  699. static LPCWSTR lpszSecurityGroupProperty = L"msDS-Security-Group-Extra-Classes";
  700. static LPCWSTR lpszNonSecurityGroupProperty = L"msDS-Non-Security-Group-Extra-Classes";
  701. static LPCWSTR lpszFilterContainers = L"ms-DS-Filter-Containers";
  702. if (pBasePathsInfo == NULL)
  703. {
  704. return;
  705. }
  706. //
  707. // get the display specifiers locale container (e.g. 409)
  708. //
  709. CComPtr<IADsContainer> spLocaleContainer;
  710. HRESULT hr = pBasePathsInfo->GetDisplaySpecifier(NULL, IID_IADsContainer, (void**)&spLocaleContainer);
  711. if (FAILED(hr))
  712. {
  713. return;
  714. }
  715. //
  716. // bind to the settings object
  717. //
  718. CComPtr<IDispatch> spIDispatchObject;
  719. hr = spLocaleContainer->GetObject((LPWSTR)lpszSettingsObjectClass,
  720. (LPWSTR)lpszSettingsObject,
  721. &spIDispatchObject);
  722. if (FAILED(hr))
  723. {
  724. return;
  725. }
  726. CComPtr<IADs> spSettingsObject;
  727. hr = spIDispatchObject->QueryInterface(IID_IADs, (void**)&spSettingsObject);
  728. if (FAILED(hr))
  729. {
  730. return;
  731. }
  732. //
  733. // get the security group extra classes as a CStringList
  734. //
  735. CComVariant var;
  736. hr = spSettingsObject->Get((LPWSTR)lpszSecurityGroupProperty, &var);
  737. if (SUCCEEDED(hr))
  738. {
  739. hr = HrVariantToStringList(var, m_szSecurityGroupExtraClasses);
  740. }
  741. //
  742. // get the non-security group extra classes as a CStringList
  743. //
  744. var.Clear();
  745. hr = spSettingsObject->Get((LPWSTR)lpszNonSecurityGroupProperty, &var);
  746. if (SUCCEEDED(hr))
  747. {
  748. hr = HrVariantToStringList(var, m_szNonSecurityGroupExtraClasses);
  749. }
  750. //
  751. // get the additional filter containers as a CStringList
  752. //
  753. var.Clear();
  754. hr = spSettingsObject->Get((LPWSTR)lpszFilterContainers, &var);
  755. if (SUCCEEDED(hr))
  756. {
  757. CStringList szContainers;
  758. hr = HrVariantToStringList(var, szContainers);
  759. if (SUCCEEDED(hr))
  760. {
  761. //
  762. // Allocate the filter struct element
  763. //
  764. m_pfilterelementDsAdminDrillDown = new FilterElementStruct;
  765. if (m_pfilterelementDsAdminDrillDown != NULL)
  766. {
  767. //
  768. // Allocate the tokens
  769. //
  770. m_pfilterelementDsAdminDrillDown->ppTokens = new FilterTokenStruct*[szContainers.GetCount()];
  771. if (m_pfilterelementDsAdminDrillDown->ppTokens != NULL)
  772. {
  773. //
  774. // Allocate and fill in each token
  775. //
  776. int idx = 0;
  777. POSITION pos = szContainers.GetHeadPosition();
  778. while (pos != NULL)
  779. {
  780. CString szContainerCategory = szContainers.GetNext(pos);
  781. ASSERT(!szContainerCategory.IsEmpty());
  782. m_pfilterelementDsAdminDrillDown->ppTokens[idx] = new FilterTokenStruct;
  783. if (m_pfilterelementDsAdminDrillDown->ppTokens[idx] != NULL)
  784. {
  785. m_pfilterelementDsAdminDrillDown->ppTokens[idx]->nType = TOKEN_TYPE_CATEGORY;
  786. m_pfilterelementDsAdminDrillDown->ppTokens[idx]->lpszString = new WCHAR[szContainerCategory.GetLength() + 1];
  787. if (m_pfilterelementDsAdminDrillDown->ppTokens[idx]->lpszString != NULL)
  788. {
  789. wcscpy(m_pfilterelementDsAdminDrillDown->ppTokens[idx]->lpszString, (LPCWSTR)szContainerCategory);
  790. idx++;
  791. }
  792. }
  793. }
  794. //
  795. // Count only the ones that were added successfully
  796. //
  797. m_pfilterelementDsAdminDrillDown->cNumTokens = idx;
  798. //
  799. // But they all should have been added successfully so assert that
  800. //
  801. ASSERT(idx == szContainers.GetCount());
  802. }
  803. else
  804. {
  805. //
  806. // failed to allocate space for the tokens,
  807. // delete all the other allocated and set the
  808. // global to NULL
  809. //
  810. delete m_pfilterelementDsAdminDrillDown;
  811. m_pfilterelementDsAdminDrillDown = NULL;
  812. }
  813. }
  814. }
  815. }
  816. m_bDisplaySettingsCollected = TRUE;
  817. }
  818. BOOL CDSCache::CanAddToGroup(MyBasePathsInfo* pBasePathsInfo, PCWSTR pszClass, BOOL bSecurity)
  819. {
  820. _Lock();
  821. if (!m_bDisplaySettingsCollected)
  822. {
  823. _CollectDisplaySettings(pBasePathsInfo);
  824. }
  825. BOOL bResult = FALSE;
  826. if (bSecurity)
  827. {
  828. POSITION pos = m_szSecurityGroupExtraClasses.GetHeadPosition();
  829. while (pos != NULL)
  830. {
  831. CString szClass = m_szSecurityGroupExtraClasses.GetNext(pos);
  832. ASSERT(!szClass.IsEmpty());
  833. if (_wcsicmp(szClass, pszClass) == 0)
  834. {
  835. bResult = TRUE;
  836. break;
  837. }
  838. }
  839. }
  840. else
  841. {
  842. POSITION pos = m_szNonSecurityGroupExtraClasses.GetHeadPosition();
  843. while (pos != NULL)
  844. {
  845. CString szClass = m_szNonSecurityGroupExtraClasses.GetNext(pos);
  846. ASSERT(!szClass.IsEmpty());
  847. if (_wcsicmp(szClass, pszClass) == 0)
  848. {
  849. bResult = TRUE;
  850. break;
  851. }
  852. }
  853. }
  854. _Unlock();
  855. return bResult;
  856. }
  857. FilterElementStruct* CDSCache::GetFilterElementStruct(CDSComponentData* pDSComponentData)
  858. {
  859. _Lock();
  860. if (!m_bDisplaySettingsCollected)
  861. {
  862. _CollectDisplaySettings(pDSComponentData->GetBasePathsInfo());
  863. }
  864. _Unlock();
  865. return (SNAPINTYPE_SITE == pDSComponentData->QuerySnapinType()) ?
  866. &g_filterelementSiteReplDrillDown : m_pfilterelementDsAdminDrillDown;
  867. }