Leaked source code of windows server 2003
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.

1015 lines
27 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(CComBSTR(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. /*
  346. CDSColumnSet*
  347. CDSClassCacheItemBase::GetColumnSet()
  348. {
  349. return m_pColumnSet;
  350. }
  351. */
  352. //
  353. // Display Specifier cached accessors
  354. //
  355. GUID* CDSClassCacheItemBase::GetAdminPropertyPages(UINT* pnCount)
  356. {
  357. *pnCount = m_nAdminPPCount;
  358. return m_pAdminPropertyPages;
  359. }
  360. void CDSClassCacheItemBase::SetAdminPropertyPages(UINT nCount, GUID* pGuids)
  361. {
  362. m_nAdminPPCount = nCount;
  363. if (m_pAdminPropertyPages != NULL)
  364. {
  365. delete[] m_pAdminPropertyPages;
  366. }
  367. m_pAdminPropertyPages = pGuids;
  368. }
  369. GUID* CDSClassCacheItemBase::GetAdminContextMenu(UINT* pnCount)
  370. {
  371. *pnCount = m_nAdminCMCount;
  372. return m_pAdminContextMenu;
  373. }
  374. void CDSClassCacheItemBase::SetAdminContextMenu(UINT nCount, GUID* pGuids)
  375. {
  376. m_nAdminCMCount = nCount;
  377. if (m_pAdminContextMenu != NULL)
  378. {
  379. delete[] m_pAdminContextMenu;
  380. }
  381. m_pAdminContextMenu = pGuids;
  382. }
  383. GUID* CDSClassCacheItemBase::GetAdminMultiSelectPropertyPages(UINT* pnCount)
  384. {
  385. *pnCount = m_nAdminMSPPCount;
  386. return m_pAdminMultiSelectPropertyPages;
  387. }
  388. void CDSClassCacheItemBase::SetAdminMultiSelectPropertyPages(UINT nCount, GUID* pGuids)
  389. {
  390. m_nAdminMSPPCount = nCount;
  391. if (m_pAdminMultiSelectPropertyPages != NULL)
  392. {
  393. delete[] m_pAdminMultiSelectPropertyPages;
  394. }
  395. m_pAdminMultiSelectPropertyPages = pGuids;
  396. }
  397. //////////////////////////////////////////////////////////////////////////
  398. // CDSClassIconIndexes
  399. void CDSClassIconIndexes::SetIconData(LPCWSTR lpszClass, BOOL bContainer, CDSComponentData *pCD, int)
  400. {
  401. DWORD dwBaseFlags = DSGIF_GETDEFAULTICON;
  402. if (bContainer)
  403. dwBaseFlags |= DSGIF_DEFAULTISCONTAINER;
  404. int iIconIndex;
  405. // get the generic icon
  406. HRESULT hr = pCD->AddClassIcon(lpszClass, DSGIF_ISNORMAL | dwBaseFlags, &iIconIndex);
  407. m_iIconIndex = SUCCEEDED(hr) ? iIconIndex : -1;
  408. m_iIconIndexOpen = m_iIconIndexDisabled = m_iIconIndex;
  409. // get the open icon
  410. hr = pCD->AddClassIcon(lpszClass, DSGIF_ISOPEN | dwBaseFlags, &iIconIndex);
  411. if (SUCCEEDED(hr))
  412. {
  413. m_iIconIndexOpen = iIconIndex;
  414. }
  415. // get the disabled icon
  416. hr = pCD->AddClassIcon(lpszClass, DSGIF_ISDISABLED | dwBaseFlags, &iIconIndex);
  417. if (SUCCEEDED(hr))
  418. {
  419. m_iIconIndexDisabled = iIconIndex;
  420. }
  421. TRACE(_T("Added icon for class: %s\n"), lpszClass);
  422. TRACE(_T("Index: %d\n"), m_iIconIndex);
  423. TRACE(_T("Open: %d\n"), m_iIconIndexOpen);
  424. TRACE(_T("Disabled: %d\n"), m_iIconIndexDisabled);
  425. }
  426. //////////////////////////////////////////////////////////////////////////
  427. // CDSClassCacheItemGeneric
  428. inline int CDSClassCacheItemGeneric::GetIconIndex(CDSCookie* pCookie, BOOL bOpen)
  429. {
  430. return m_iconIndexesStandard.GetIconIndex(pCookie->IsDisabled(), bOpen);
  431. }
  432. inline void CDSClassCacheItemGeneric::SetIconData(CDSComponentData *pCD)
  433. {
  434. m_iconIndexesStandard.SetIconData(GetClassName(), IsContainer(), pCD,0);
  435. }
  436. //////////////////////////////////////////////////////////////////////////
  437. // CDSClassCacheItemGroup
  438. inline int CDSClassCacheItemGroup::GetIconIndex(CDSCookie* pCookie, BOOL bOpen)
  439. {
  440. CDSClassIconIndexes* pIndexes = &m_iconIndexesStandard;
  441. CDSCookieInfoBase* pExtraInfo = pCookie->GetExtraInfo();
  442. if ( (pExtraInfo != NULL) && (pExtraInfo->GetClass() == CDSCookieInfoBase::group) )
  443. {
  444. if (((((CDSCookieInfoGroup*)pExtraInfo)->m_GroupType) & GROUP_TYPE_SECURITY_ENABLED) != 0)
  445. pIndexes = & m_iconIndexesAlternate;
  446. }
  447. return pIndexes->GetIconIndex(pCookie->IsDisabled(), bOpen);
  448. }
  449. inline void CDSClassCacheItemGroup::SetIconData(CDSComponentData *pCD)
  450. {
  451. LPCWSTR lpszClass = GetClassName();
  452. m_iconIndexesStandard.SetIconData(lpszClass, IsContainer(), pCD,0);
  453. m_iconIndexesAlternate.SetIconData(lpszClass, IsContainer(), pCD,1);
  454. /*
  455. // test just to get load some icons with a fake class and a fake "groupAlt-Display" object
  456. m_iconIndexesAlternate.SetIconData(L"groupAlt", m_bIsContainer, pCD, 1);
  457. */
  458. }
  459. //////////////////////////////////////////////////////////////////////////
  460. // CDSCache
  461. BOOL CDSCache::ToggleExpandSpecialClasses(BOOL bContainer)
  462. {
  463. _Lock();
  464. BOOL bFound = FALSE;
  465. CDSClassCacheItemBase* pItem;
  466. if (Lookup(L"computer", pItem))
  467. {
  468. pItem->SetContainerFlag(bContainer);
  469. bFound = TRUE;
  470. }
  471. if (Lookup(L"user", pItem))
  472. {
  473. pItem->SetContainerFlag(bContainer);
  474. bFound = TRUE;
  475. }
  476. #ifdef INETORGPERSON
  477. if (Lookup(L"inetOrgPerson", pItem))
  478. {
  479. pItem->SetContainerFlag(bContainer);
  480. bFound = TRUE;
  481. }
  482. #endif
  483. if (Lookup(L"group", pItem))
  484. {
  485. pItem->SetContainerFlag(bContainer);
  486. bFound = TRUE;
  487. }
  488. _Unlock();
  489. return bFound;
  490. }
  491. CDSColumnSet* CDSCache::FindColumnSet(LPCWSTR lpszColumnID)
  492. {
  493. _Lock();
  494. TRACE(L"Entering CDSCache::FindColumnSet\n");
  495. CDSColumnSet* pColumnSet = NULL;
  496. if (_wcsicmp(DEFAULT_COLUMN_SET, lpszColumnID) == 0)
  497. {
  498. //
  499. // return the default column set
  500. //
  501. pColumnSet = dynamic_cast<CDSColumnSet*>(m_ColumnList.GetDefaultColumnSet());
  502. }
  503. else if (_wcsicmp(SPECIAL_COLUMN_SET, lpszColumnID) == 0)
  504. {
  505. //
  506. // return the special column set
  507. //
  508. pColumnSet = dynamic_cast<CDSColumnSet*>(m_ColumnList.GetSpecialColumnSet());
  509. }
  510. else
  511. {
  512. pColumnSet = dynamic_cast<CDSColumnSet*>(m_ColumnList.FindColumnSet(lpszColumnID));
  513. }
  514. _Unlock();
  515. return pColumnSet;
  516. }
  517. CDSClassCacheItemBase* CDSCache::FindClassCacheItem(CDSComponentData* pCD,
  518. LPCWSTR lpszObjectClass,
  519. LPCWSTR lpszObjectLdapPath
  520. )
  521. {
  522. _Lock();
  523. CDSClassCacheItemBase* pDsCacheItem = NULL;
  524. BOOL bFound = m_Map.Lookup(lpszObjectClass, pDsCacheItem);
  525. if (!bFound)
  526. {
  527. // Item not found in cache, create, insert in the cache and return it
  528. TRACE(_T("did not find class <%s> for this item in the Cache.\n"), (LPCWSTR)lpszObjectClass);
  529. // Check to see if the object is a container
  530. CComPtr<IADs> spADsObject = NULL;
  531. if (lpszObjectLdapPath != NULL)
  532. {
  533. DSAdminOpenObject(lpszObjectLdapPath,
  534. IID_IADs,
  535. (LPVOID*)&spADsObject,
  536. TRUE /*bServer*/);
  537. // NOTICE: we might fail to bind here if we do not have read rights
  538. // this will give a NULL spADsObject, that will work just fine on the CreateItem() call below
  539. }
  540. // create object
  541. HRESULT hrCreate = CDSClassCacheItemBase::CreateItem(lpszObjectClass, spADsObject, pCD, &pDsCacheItem);
  542. ASSERT(pDsCacheItem != NULL);
  543. ASSERT(SUCCEEDED(hrCreate));
  544. // set in the cache
  545. m_Map.SetAt(lpszObjectClass, pDsCacheItem);
  546. }
  547. _Unlock();
  548. return pDsCacheItem;
  549. }
  550. #define DS_CACHE_STREAM_VERSION ((DWORD)0x0)
  551. HRESULT CDSCache::Save(IStream* pStm)
  552. {
  553. // save cache version number
  554. HRESULT hr = SaveDWordHelper(pStm, DS_CACHE_STREAM_VERSION);
  555. if (FAILED(hr))
  556. return hr;
  557. // save column list
  558. return m_ColumnList.Save(pStm);
  559. }
  560. HRESULT CDSCache::Load(IStream* pStm)
  561. {
  562. // load cache version number
  563. DWORD dwVersion;
  564. HRESULT hr = LoadDWordHelper(pStm, &dwVersion);
  565. if ( FAILED(hr) ||(dwVersion != DS_CACHE_STREAM_VERSION) )
  566. return E_FAIL;
  567. // load column list
  568. return m_ColumnList.Load(pStm);
  569. }
  570. HRESULT CDSCache::TabCollect_AddMultiSelectPropertyPages(LPPROPERTYSHEETCALLBACK pCall,
  571. LONG_PTR,
  572. LPDATAOBJECT pDataObject,
  573. MyBasePathsInfo* pBasePathsInfo)
  574. {
  575. HRESULT hr = S_OK;
  576. CString szClassName;
  577. CString szDisplayProperty = L"AdminMultiSelectPropertyPages";
  578. GUID* pGuids = NULL;
  579. UINT nCount = 0;
  580. if (IsHomogenousDSSelection(pDataObject, szClassName))
  581. {
  582. //
  583. // Get the guid for the multiselect proppages of the homogenous class selection
  584. //
  585. //
  586. // Check the cache first
  587. //
  588. BOOL bFoundGuids = FALSE;
  589. CDSClassCacheItemBase* pItem = NULL;
  590. BOOL bFoundItem = Lookup(szClassName, pItem);
  591. if (bFoundItem)
  592. {
  593. if (pItem == NULL)
  594. {
  595. ASSERT(FALSE);
  596. bFoundItem = FALSE;
  597. }
  598. else
  599. {
  600. //
  601. // Retrieve guids from cache
  602. //
  603. pGuids = pItem->GetAdminMultiSelectPropertyPages(&nCount);
  604. if (nCount > 0 && pGuids != NULL)
  605. {
  606. bFoundGuids = TRUE;
  607. }
  608. }
  609. }
  610. if (!bFoundGuids)
  611. {
  612. //
  613. // Class cache item did not contain GUID
  614. //
  615. hr = TabCollect_GetDisplayGUIDs(szClassName,
  616. szDisplayProperty,
  617. pBasePathsInfo,
  618. &nCount,
  619. &pGuids);
  620. if (FAILED(hr))
  621. {
  622. //
  623. // Try the default-Display object then
  624. //
  625. hr = TabCollect_GetDisplayGUIDs(L"default",
  626. szDisplayProperty,
  627. pBasePathsInfo,
  628. &nCount,
  629. &pGuids);
  630. if (FAILED(hr))
  631. {
  632. return hr;
  633. }
  634. }
  635. if (bFoundItem)
  636. {
  637. //
  638. // Cache the new guids
  639. //
  640. pItem->SetAdminMultiSelectPropertyPages(nCount, pGuids);
  641. }
  642. }
  643. }
  644. else
  645. {
  646. //
  647. // Get the default multi-select proppages
  648. //
  649. hr = TabCollect_GetDisplayGUIDs(L"default", szDisplayProperty, pBasePathsInfo, &nCount, &pGuids);
  650. //
  651. // Right now there is no default item in the cache so we have to get it each time from
  652. // the DS
  653. //
  654. }
  655. if (SUCCEEDED(hr))
  656. {
  657. if (nCount > 0 && pGuids != NULL)
  658. {
  659. //
  660. // Create all the pages, initialize, and then add them
  661. //
  662. for (UINT nIndex = 0; nIndex < nCount; nIndex++)
  663. {
  664. //
  665. // Create
  666. //
  667. CComPtr<IShellExtInit> spShellInit;
  668. hr = ::CoCreateInstance((pGuids[nIndex]),
  669. NULL,
  670. CLSCTX_INPROC_SERVER,
  671. IID_IShellExtInit,
  672. (PVOID*)&spShellInit);
  673. if (FAILED(hr))
  674. {
  675. continue;
  676. }
  677. //
  678. // Initialize
  679. //
  680. hr = spShellInit->Initialize(NULL, pDataObject, 0);
  681. if (FAILED(hr))
  682. {
  683. continue;
  684. }
  685. //
  686. // Add
  687. //
  688. CComPtr<IShellPropSheetExt> spPropSheetExt;
  689. hr = spShellInit->QueryInterface(IID_IShellPropSheetExt, (PVOID*)&spPropSheetExt);
  690. if (FAILED(hr))
  691. {
  692. continue;
  693. }
  694. hr = spPropSheetExt->AddPages(AddPageProc, (LPARAM)pCall);
  695. if (FAILED(hr))
  696. {
  697. TRACE(TEXT("spPropSheetExt->AddPages failed, hr: 0x%x\n"), hr);
  698. continue;
  699. }
  700. }
  701. }
  702. }
  703. return hr;
  704. }
  705. void CDSCache::_CollectDisplaySettings(MyBasePathsInfo* pBasePathsInfo)
  706. {
  707. static LPCWSTR lpszSettingsObjectClass = L"dsUISettings";
  708. static LPCWSTR lpszSettingsObject = L"cn=DS-UI-Default-Settings";
  709. static LPCWSTR lpszSecurityGroupProperty = L"msDS-Security-Group-Extra-Classes";
  710. static LPCWSTR lpszNonSecurityGroupProperty = L"msDS-Non-Security-Group-Extra-Classes";
  711. static LPCWSTR lpszFilterContainers = L"msDS-FilterContainers";
  712. if (pBasePathsInfo == NULL)
  713. {
  714. return;
  715. }
  716. //
  717. // get the display specifiers locale container (e.g. 409)
  718. //
  719. CComPtr<IADsContainer> spLocaleContainer;
  720. HRESULT hr = pBasePathsInfo->GetDisplaySpecifier(NULL, IID_IADsContainer, (void**)&spLocaleContainer);
  721. if (FAILED(hr))
  722. {
  723. return;
  724. }
  725. //
  726. // bind to the settings object
  727. //
  728. CComPtr<IDispatch> spIDispatchObject;
  729. hr = spLocaleContainer->GetObject(CComBSTR(lpszSettingsObjectClass),
  730. CComBSTR(lpszSettingsObject),
  731. &spIDispatchObject);
  732. if (FAILED(hr))
  733. {
  734. return;
  735. }
  736. CComPtr<IADs> spSettingsObject;
  737. hr = spIDispatchObject->QueryInterface(IID_IADs, (void**)&spSettingsObject);
  738. if (FAILED(hr))
  739. {
  740. return;
  741. }
  742. //
  743. // get the security group extra classes as a CStringList
  744. //
  745. CComVariant var;
  746. hr = spSettingsObject->Get(CComBSTR(lpszSecurityGroupProperty), &var);
  747. if (SUCCEEDED(hr))
  748. {
  749. hr = HrVariantToStringList(var, m_szSecurityGroupExtraClasses);
  750. }
  751. //
  752. // get the non-security group extra classes as a CStringList
  753. //
  754. var.Clear();
  755. hr = spSettingsObject->Get(CComBSTR(lpszNonSecurityGroupProperty), &var);
  756. if (SUCCEEDED(hr))
  757. {
  758. hr = HrVariantToStringList(var, m_szNonSecurityGroupExtraClasses);
  759. }
  760. //
  761. // get the additional filter containers as a CStringList
  762. //
  763. var.Clear();
  764. hr = spSettingsObject->Get(CComBSTR(lpszFilterContainers), &var);
  765. if (SUCCEEDED(hr))
  766. {
  767. CStringList szContainers;
  768. hr = HrVariantToStringList(var, szContainers);
  769. if (SUCCEEDED(hr))
  770. {
  771. //
  772. // Allocate the filter struct element
  773. //
  774. m_pfilterelementDsAdminDrillDown = new FilterElementStruct;
  775. if (m_pfilterelementDsAdminDrillDown != NULL)
  776. {
  777. //
  778. // Allocate the tokens
  779. //
  780. m_pfilterelementDsAdminDrillDown->ppTokens = new FilterTokenStruct*[szContainers.GetCount()];
  781. if (m_pfilterelementDsAdminDrillDown->ppTokens != NULL)
  782. {
  783. //
  784. // Allocate and fill in each token
  785. //
  786. int idx = 0;
  787. POSITION pos = szContainers.GetHeadPosition();
  788. while (pos != NULL)
  789. {
  790. CString szContainerCategory = szContainers.GetNext(pos);
  791. ASSERT(!szContainerCategory.IsEmpty());
  792. m_pfilterelementDsAdminDrillDown->ppTokens[idx] = new FilterTokenStruct;
  793. if (m_pfilterelementDsAdminDrillDown->ppTokens[idx] != NULL)
  794. {
  795. m_pfilterelementDsAdminDrillDown->ppTokens[idx]->nType = TOKEN_TYPE_CATEGORY;
  796. m_pfilterelementDsAdminDrillDown->ppTokens[idx]->lpszString = new WCHAR[szContainerCategory.GetLength() + 1];
  797. if (m_pfilterelementDsAdminDrillDown->ppTokens[idx]->lpszString != NULL)
  798. {
  799. wcscpy(m_pfilterelementDsAdminDrillDown->ppTokens[idx]->lpszString, (LPCWSTR)szContainerCategory);
  800. idx++;
  801. }
  802. }
  803. }
  804. //
  805. // Count only the ones that were added successfully
  806. //
  807. m_pfilterelementDsAdminDrillDown->cNumTokens = idx;
  808. //
  809. // But they all should have been added successfully so assert that
  810. //
  811. ASSERT(idx == szContainers.GetCount());
  812. }
  813. else
  814. {
  815. //
  816. // failed to allocate space for the tokens,
  817. // delete all the other allocated and set the
  818. // global to NULL
  819. //
  820. delete m_pfilterelementDsAdminDrillDown;
  821. m_pfilterelementDsAdminDrillDown = NULL;
  822. }
  823. }
  824. }
  825. }
  826. m_bDisplaySettingsCollected = TRUE;
  827. }
  828. BOOL CDSCache::CanAddToGroup(MyBasePathsInfo* pBasePathsInfo, PCWSTR pszClass, BOOL bSecurity)
  829. {
  830. _Lock();
  831. if (!m_bDisplaySettingsCollected)
  832. {
  833. _CollectDisplaySettings(pBasePathsInfo);
  834. }
  835. BOOL bResult = FALSE;
  836. if (bSecurity)
  837. {
  838. POSITION pos = m_szSecurityGroupExtraClasses.GetHeadPosition();
  839. while (pos != NULL)
  840. {
  841. CString szClass = m_szSecurityGroupExtraClasses.GetNext(pos);
  842. ASSERT(!szClass.IsEmpty());
  843. if (_wcsicmp(szClass, pszClass) == 0)
  844. {
  845. bResult = TRUE;
  846. break;
  847. }
  848. }
  849. }
  850. else
  851. {
  852. POSITION pos = m_szNonSecurityGroupExtraClasses.GetHeadPosition();
  853. while (pos != NULL)
  854. {
  855. CString szClass = m_szNonSecurityGroupExtraClasses.GetNext(pos);
  856. ASSERT(!szClass.IsEmpty());
  857. if (_wcsicmp(szClass, pszClass) == 0)
  858. {
  859. bResult = TRUE;
  860. break;
  861. }
  862. }
  863. }
  864. _Unlock();
  865. return bResult;
  866. }
  867. FilterElementStruct* CDSCache::GetFilterElementStruct(CDSComponentData* pDSComponentData)
  868. {
  869. _Lock();
  870. if (!m_bDisplaySettingsCollected)
  871. {
  872. _CollectDisplaySettings(pDSComponentData->GetBasePathsInfo());
  873. }
  874. _Unlock();
  875. return (SNAPINTYPE_SITE == pDSComponentData->QuerySnapinType()) ?
  876. &g_filterelementSiteReplDrillDown : m_pfilterelementDsAdminDrillDown;
  877. }