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.

1649 lines
41 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Windows NT Directory Service Property Pages
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1999
  7. //
  8. // File: objlist.cxx
  9. //
  10. // Contents: Link-lists of objects and list-view controls displaying objects.
  11. //
  12. // History: 20-Nov-97 EricB created
  13. //
  14. //-----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #include "proppage.h"
  17. #include "objlist.h"
  18. CClassIconCache g_ClassIconCache;
  19. //+----------------------------------------------------------------------------
  20. //
  21. // Class: CMemberLinkList
  22. //
  23. // Purpose: Linked list of membership class objects.
  24. //
  25. //-----------------------------------------------------------------------------
  26. CMemberLinkList::~CMemberLinkList(void)
  27. {
  28. CMemberListItem * pItem = m_pListHead, * pNext;
  29. while (pItem)
  30. {
  31. pNext = pItem->Next();
  32. delete pItem;
  33. pItem = pNext;
  34. }
  35. }
  36. //+----------------------------------------------------------------------------
  37. //
  38. // Method: CMemberLinkList::FindItemRemove
  39. //
  40. // Synopsis: Search for an element with a matching DN and, if found, remove
  41. // it from the list and return its pointer. Returns NULL if not
  42. // found.
  43. //
  44. //-----------------------------------------------------------------------------
  45. CMemberListItem *
  46. CMemberLinkList::FindItemRemove(PWSTR pwzDN)
  47. {
  48. CMemberListItem * pItem = m_pListHead;
  49. while (pItem)
  50. {
  51. dspAssert(pItem->m_pwzDN);
  52. if (_wcsicmp(pItem->m_pwzDN, pwzDN) == 0)
  53. {
  54. if (pItem->Prev() == NULL)
  55. {
  56. // this item is the list head.
  57. //
  58. m_pListHead = pItem->Next();
  59. }
  60. pItem->UnLink();
  61. return pItem;
  62. }
  63. pItem = pItem->Next();
  64. }
  65. return NULL;
  66. }
  67. //+----------------------------------------------------------------------------
  68. //
  69. // Method: CMemberLinkList::FindItemRemove
  70. //
  71. // Synopsis: Search for an element with a matching SID and, if found, remove
  72. // it from the list and return its pointer. Returns NULL if not
  73. // found.
  74. //
  75. //-----------------------------------------------------------------------------
  76. CMemberListItem *
  77. CMemberLinkList::FindItemRemove(PSID pSid)
  78. {
  79. CMemberListItem * pItem = m_pListHead;
  80. while (pItem)
  81. {
  82. dspAssert(pItem->m_pwzDN);
  83. if (pItem->m_pSid && EqualSid(pItem->m_pSid, pSid))
  84. {
  85. if (pItem->Prev() == NULL)
  86. {
  87. // this item is the list head.
  88. //
  89. m_pListHead = pItem->Next();
  90. }
  91. pItem->UnLink();
  92. return pItem;
  93. }
  94. pItem = pItem->Next();
  95. }
  96. return NULL;
  97. }
  98. //+----------------------------------------------------------------------------
  99. //
  100. // Method: CMemberLinkList::RemoveFirstItem
  101. //
  102. // Synopsis: Remove the first item from the list.
  103. //
  104. //-----------------------------------------------------------------------------
  105. CMemberListItem *
  106. CMemberLinkList::RemoveFirstItem(void)
  107. {
  108. CMemberListItem * pItem = m_pListHead;
  109. if (pItem)
  110. {
  111. m_pListHead = pItem->Next();
  112. pItem->UnLink();
  113. return pItem;
  114. }
  115. return NULL;
  116. }
  117. //+----------------------------------------------------------------------------
  118. //
  119. // Method: CMemberLinkList::AddItem
  120. //
  121. // Synopsis: Insert an item into the list.
  122. //
  123. //-----------------------------------------------------------------------------
  124. BOOL
  125. CMemberLinkList::AddItem(CMemberListItem * pItem, BOOL fMember)
  126. {
  127. if (!pItem->m_fIsAlreadyMember)
  128. {
  129. return TRUE;
  130. }
  131. CMemberListItem * pItemCopy;
  132. if (m_pListHead == NULL)
  133. {
  134. pItemCopy = pItem->Copy();
  135. CHECK_NULL(pItemCopy, return FALSE);
  136. pItemCopy->m_fIsAlreadyMember = fMember;
  137. m_pListHead = pItemCopy;
  138. }
  139. else
  140. {
  141. CMemberListItem * pCur = m_pListHead;
  142. //
  143. // Make sure the item isn't already in the list.
  144. //
  145. while (pCur)
  146. {
  147. dspAssert(pCur->m_pwzDN);
  148. if (_wcsicmp(pCur->m_pwzDN, pItem->m_pwzDN) == 0)
  149. {
  150. return TRUE;
  151. }
  152. pCur = pCur->Next();
  153. }
  154. pItemCopy = pItem->Copy();
  155. CHECK_NULL(pItemCopy, return FALSE);
  156. pItemCopy->m_fIsAlreadyMember = fMember;
  157. pItemCopy->LinkAfter(m_pListHead);
  158. }
  159. return TRUE;
  160. }
  161. //+----------------------------------------------------------------------------
  162. //
  163. // Method: CMemberLinkList::GetItemCount
  164. //
  165. // Synopsis: Return the count of elements in the list.
  166. //
  167. //-----------------------------------------------------------------------------
  168. int
  169. CMemberLinkList::GetItemCount(void)
  170. {
  171. int cItem = 0;
  172. CMemberListItem * pItem = m_pListHead;
  173. while (pItem)
  174. {
  175. cItem++;
  176. pItem = pItem->Next();
  177. }
  178. return cItem;
  179. }
  180. //+----------------------------------------------------------------------------
  181. //
  182. // Class: CDsObjList
  183. //
  184. // Purpose: Base class for DS object lists that employ a two column
  185. // list view to show object Name and Folder.
  186. //
  187. //-----------------------------------------------------------------------------
  188. CDsObjList::CDsObjList(HWND hPage, int idList) :
  189. m_hPage(hPage),
  190. m_idList(idList),
  191. m_nCurItem(0),
  192. m_fShowIcons(FALSE),
  193. m_fLimitExceeded(FALSE)
  194. {
  195. }
  196. CDsObjList::~CDsObjList(void)
  197. {
  198. }
  199. //+----------------------------------------------------------------------------
  200. //
  201. // Method: CDsObjList::Init
  202. //
  203. // Synopsis: Initialize the list view, add its columns.
  204. //
  205. //-----------------------------------------------------------------------------
  206. HRESULT
  207. CDsObjList::Init(BOOL fShowIcons)
  208. {
  209. m_fShowIcons = fShowIcons;
  210. m_hList = GetDlgItem(m_hPage, m_idList);
  211. if (m_hList == NULL)
  212. {
  213. return HRESULT_FROM_WIN32(GetLastError());
  214. }
  215. ListView_SetExtendedListViewStyle(m_hList, LVS_EX_FULLROWSELECT);
  216. //
  217. // Set the column headings.
  218. //
  219. PTSTR ptsz;
  220. RECT rect;
  221. GetClientRect(m_hList, &rect);
  222. if (!LoadStringToTchar(IDS_COL_TITLE_OBJNAME, &ptsz))
  223. {
  224. ReportError(GetLastError(), 0, m_hPage);
  225. return HRESULT_FROM_WIN32(GetLastError());
  226. }
  227. LV_COLUMN lvc = {0};
  228. lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  229. lvc.fmt = LVCFMT_LEFT;
  230. lvc.cx = OBJ_LIST_NAME_COL_WIDTH;
  231. lvc.pszText = ptsz;
  232. lvc.iSubItem = IDX_NAME_COL;
  233. ListView_InsertColumn(m_hList, IDX_NAME_COL, &lvc);
  234. delete ptsz;
  235. if (!LoadStringToTchar(IDS_COL_TITLE_OBJFOLDER, &ptsz))
  236. {
  237. ReportError(GetLastError(), 0, m_hPage);
  238. return HRESULT_FROM_WIN32(GetLastError());
  239. }
  240. lvc.cx = rect.right - OBJ_LIST_NAME_COL_WIDTH;
  241. lvc.pszText = ptsz;
  242. lvc.iSubItem = IDX_FOLDER_COL;
  243. ListView_InsertColumn(m_hList, IDX_FOLDER_COL, &lvc);
  244. delete ptsz;
  245. if (m_fShowIcons)
  246. {
  247. // Assign the imagelist to the listview
  248. //
  249. ListView_SetImageList(m_hList,
  250. g_ClassIconCache.GetImageList(),
  251. LVSIL_SMALL);
  252. }
  253. return S_OK;
  254. }
  255. //+----------------------------------------------------------------------------
  256. //
  257. // Method: GetNameParts
  258. //
  259. // Synopsis: The folder path and object name should be separated by a
  260. // newline character. Return a pointer to the name and allocate
  261. // a buffer for the folder part. Return NULL for the folder part
  262. // if a newline is not found. No folder is returned if the input
  263. // pointer pcstrFolder is NULL.
  264. //
  265. //-----------------------------------------------------------------------------
  266. void
  267. GetNameParts(const CStr& cstrCanonicalNameEx, CStr& cstrFolder, CStr & cstrName)
  268. {
  269. int nCR = cstrCanonicalNameEx.Find(TEXT('\n'));
  270. if (-1 != nCR)
  271. {
  272. cstrFolder = cstrCanonicalNameEx.Left(nCR);
  273. cstrName = cstrCanonicalNameEx.Right(cstrCanonicalNameEx.GetLength() - nCR - 1);
  274. // Remove any escaping from the name
  275. //
  276. int nBackSlash;
  277. while ((nBackSlash = cstrName.Find(TEXT('\\'))) != -1)
  278. {
  279. CStr cstrTemp = cstrName.Left(nBackSlash);
  280. int count = cstrName.GetLength() - nBackSlash - 1;
  281. if (count > 0)
  282. {
  283. cstrTemp += cstrName.Right(cstrName.GetLength() - nBackSlash - 1);
  284. }
  285. cstrName = cstrTemp;
  286. }
  287. }
  288. else
  289. {
  290. cstrName = cstrCanonicalNameEx;
  291. cstrFolder.Empty();
  292. }
  293. }
  294. //+----------------------------------------------------------------------------
  295. //
  296. // Method: CDsObjList::InsertIntoList
  297. //
  298. // Synopsis: Insert the item into the listview control.
  299. //
  300. //-----------------------------------------------------------------------------
  301. HRESULT
  302. CDsObjList::InsertIntoList(PTSTR ptzDisplayName, PVOID pData, int iIcon)
  303. {
  304. HRESULT hr = S_OK;
  305. //
  306. // The name and folder should be separated by a new line character.
  307. //
  308. CStr cstrFolder, cstrName;
  309. CStr cstrDisplayName = ptzDisplayName;
  310. GetNameParts(cstrDisplayName, cstrFolder, cstrName);
  311. CHECK_HRESULT(hr, return hr);
  312. LV_ITEM lvi = {0};
  313. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  314. lvi.iSubItem = IDX_NAME_COL;
  315. lvi.pszText = const_cast<PTSTR>((LPCTSTR)cstrName);
  316. lvi.lParam = (LPARAM)pData;
  317. lvi.iItem = m_nCurItem;
  318. if (-1 != iIcon)
  319. {
  320. lvi.mask |= LVIF_IMAGE;
  321. // if the limit is exceeded use the default icon.
  322. lvi.iImage = (m_fLimitExceeded) ? 0 : iIcon;
  323. }
  324. int NewIndex = ListView_InsertItem(m_hList, &lvi);
  325. dspAssert(NewIndex != -1);
  326. if (!cstrFolder.IsEmpty())
  327. {
  328. ListView_SetItemText(m_hList, NewIndex, IDX_FOLDER_COL,
  329. const_cast<PTSTR>((LPCTSTR)cstrFolder));
  330. //delete ptzFolder;
  331. }
  332. m_nCurItem++;
  333. return hr;
  334. }
  335. //+----------------------------------------------------------------------------
  336. //
  337. // Method: CDsObjList::GetItem
  338. //
  339. // Synopsis: Returns the name and item data for the indicated item. Any of
  340. // the input pointers can be NULL to skip that parameter.
  341. //
  342. //-----------------------------------------------------------------------------
  343. HRESULT
  344. CDsObjList::GetItem(int index, PTSTR * pptzName, PVOID * ppData)
  345. {
  346. TCHAR tzBuf[256];
  347. LV_ITEM lvi;
  348. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  349. lvi.iItem = index;
  350. lvi.iSubItem = IDX_NAME_COL;
  351. lvi.pszText = tzBuf;
  352. lvi.cchTextMax = 256;
  353. if (!ListView_GetItem(m_hList, &lvi))
  354. {
  355. return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
  356. }
  357. if (pptzName)
  358. {
  359. if (lvi.pszText)
  360. {
  361. *pptzName = new TCHAR[_tcslen(lvi.pszText) + 1];
  362. CHECK_NULL_REPORT(*pptzName, m_hPage, return FALSE);
  363. _tcscpy(*pptzName, lvi.pszText);
  364. }
  365. else
  366. {
  367. *pptzName = NULL;
  368. }
  369. }
  370. if (ppData)
  371. {
  372. *ppData = (PVOID)lvi.lParam;
  373. }
  374. return S_OK;
  375. }
  376. //+----------------------------------------------------------------------------
  377. //
  378. // Method: CDsObjList::GetCurListItem
  379. //
  380. // Synopsis: Returns the index, name (in an allocated buffer), and pointer
  381. // to the item data. Any of the input pointers can be NULL to skip
  382. // that parameter.
  383. //
  384. //-----------------------------------------------------------------------------
  385. BOOL
  386. CDsObjList::GetCurListItem(int * pIndex, PTSTR * pptzName, PVOID * ppData)
  387. {
  388. int i = ListView_GetNextItem(m_hList, -1, LVNI_SELECTED);
  389. if (i < 0)
  390. {
  391. dspDebugOut((DEB_ITRACE, "DsProp: no list selection.\n"));
  392. return FALSE;
  393. }
  394. HRESULT hr = GetItem(i, pptzName, ppData);
  395. if (FAILED(hr))
  396. {
  397. dspAssert(FALSE);
  398. return FALSE;
  399. }
  400. if (pIndex)
  401. {
  402. *pIndex = i;
  403. }
  404. return TRUE;
  405. }
  406. //+----------------------------------------------------------------------------
  407. //
  408. // Method: CDsObjList::GetCurListItems
  409. //
  410. // Synopsis: Returns an array of indexes, names (in an allocated buffers), and pointers
  411. // to the items data. Any of the input pointers can be NULL to skip
  412. // that parameter.
  413. //
  414. //-----------------------------------------------------------------------------
  415. BOOL
  416. CDsObjList::GetCurListItems(int ** ppIndex, PTSTR ** ppptzName, PVOID ** pppData, int* pNumSelected)
  417. {
  418. int iStartPoint = -1;
  419. int i = -1;
  420. UINT nSelected = ListView_GetSelectedCount(m_hList);
  421. if (ppIndex)
  422. {
  423. *ppIndex = new int[nSelected];
  424. }
  425. if (ppptzName)
  426. {
  427. *ppptzName = new PTSTR[nSelected];
  428. }
  429. if (pppData)
  430. {
  431. *pppData = new PVOID[nSelected];
  432. }
  433. for (UINT idx = 0; idx < nSelected; idx++)
  434. {
  435. i = ListView_GetNextItem(m_hList, iStartPoint, LVNI_SELECTED);
  436. if (i < 0)
  437. {
  438. dspDebugOut((DEB_ITRACE, "DsProp: no list selection.\n"));
  439. if (ppIndex)
  440. {
  441. delete[] ppIndex;
  442. *ppIndex = 0;
  443. }
  444. if (ppptzName)
  445. {
  446. delete[] ppptzName;
  447. *ppptzName = 0;
  448. }
  449. if (pppData)
  450. {
  451. delete[] pppData;
  452. *pppData = 0;
  453. }
  454. return FALSE;
  455. }
  456. HRESULT hr;
  457. if (ppptzName == NULL && pppData == NULL)
  458. {
  459. hr = GetItem(i, NULL, NULL);
  460. }
  461. else if (pppData == NULL)
  462. {
  463. hr = GetItem(i, &((*ppptzName)[idx]), NULL);
  464. }
  465. else if (ppptzName == NULL)
  466. {
  467. hr = GetItem(i, NULL, &((*pppData)[idx]));
  468. }
  469. else
  470. {
  471. hr = GetItem(i, &((*ppptzName)[idx]), &((*pppData)[idx]));
  472. }
  473. if (FAILED(hr))
  474. {
  475. dspAssert(FALSE);
  476. if (ppIndex != NULL)
  477. {
  478. delete[] ppIndex;
  479. *ppIndex = 0;
  480. }
  481. if (ppptzName != NULL)
  482. {
  483. delete[] ppptzName;
  484. *ppptzName = 0;
  485. }
  486. if (pppData != NULL)
  487. {
  488. delete[] pppData;
  489. *pppData = 0;
  490. }
  491. return FALSE;
  492. }
  493. iStartPoint = i;
  494. (*ppIndex)[idx] = i;
  495. }
  496. *pNumSelected = nSelected;
  497. return TRUE;
  498. }
  499. //+----------------------------------------------------------------------------
  500. //
  501. // Method: CDsMembershipList::InsertIntoList
  502. //
  503. // Synopsis: Insert the item into the listview control.
  504. //
  505. // Arguments: [pwzPath] - object DN.
  506. // [iIcon] - object icon, -1 means ignore.
  507. // [fAlreadyMember] - already member of group, not a new member in an add/apply-pending state.
  508. // [fPrimary] - member by virtue of primaryGroupID attribute.
  509. // [fIgnoreDups] - don't report error if already in list; used for merging in reverse membership.
  510. // [fDontChkDups] - don't check for duplicates; used for initial listing of direct membership.
  511. //
  512. //-----------------------------------------------------------------------------
  513. HRESULT
  514. CDsMembershipList::InsertIntoList(PWSTR pwzPath, int iIcon, BOOL fAlreadyMember,
  515. BOOL fPrimary, BOOL fIgnoreDups,
  516. BOOL fDontChkDups, ULONG ulScopeType)
  517. {
  518. HRESULT hr = S_OK, hrRet = S_OK;
  519. PWSTR pwzPathCopy = NULL, pwzCanEx = NULL;
  520. PTSTR ptzCanEx = NULL;
  521. CMemberListItem * pListItem = NULL;
  522. BOOL fCanBePrimary = FALSE;
  523. //
  524. // Convert the distinguished name to a more friendly variant for display
  525. // in the list.
  526. //
  527. if (DSOP_SCOPE_TYPE_EXTERNAL_DOWNLEVEL_DOMAIN == ulScopeType)
  528. {
  529. if (!UnicodeToTchar(pwzPath, &ptzCanEx))
  530. {
  531. REPORT_ERROR(E_OUTOFMEMORY, m_hPage);
  532. hr = E_OUTOFMEMORY;
  533. goto ErrorCleanup;
  534. }
  535. PTSTR ptzSlash = _tcspbrk(ptzCanEx, TEXT("\\/"));
  536. if (ptzSlash)
  537. {
  538. *ptzSlash = TEXT('\n');
  539. }
  540. }
  541. else
  542. {
  543. hr = CrackName(pwzPath, &pwzCanEx, GET_OBJ_CAN_NAME_EX, m_hPage);
  544. if (DS_NAME_ERROR_NO_MAPPING == HRESULT_CODE(hr))
  545. {
  546. hrRet = MAKE_HRESULT(SEVERITY_ERROR, 0, DS_NAME_ERROR_NO_MAPPING);
  547. hr = S_OK;
  548. }
  549. CHECK_HRESULT(hr, goto ErrorCleanup);
  550. if (!UnicodeToTchar(pwzCanEx, &ptzCanEx))
  551. {
  552. LocalFreeStringW(&pwzCanEx);
  553. REPORT_ERROR(E_OUTOFMEMORY, m_hPage);
  554. hr = E_OUTOFMEMORY;
  555. goto ErrorCleanup;
  556. }
  557. LocalFreeStringW(&pwzCanEx);
  558. }
  559. if (!fDontChkDups)
  560. {
  561. //
  562. // Check to see if the item is already in the list.
  563. //
  564. LV_ITEM lvi;
  565. lvi.mask = LVIF_PARAM;
  566. lvi.iItem = 0;
  567. lvi.iSubItem = IDX_NAME_COL;
  568. while (ListView_GetItem(m_hList, &lvi))
  569. {
  570. pListItem = (CMemberListItem *)lvi.lParam;
  571. dspAssert(pListItem);
  572. if (_wcsicmp(pListItem->m_pwzDN, pwzPath) == 0)
  573. {
  574. if (fIgnoreDups)
  575. {
  576. DO_DEL(ptzCanEx);
  577. return S_OK;
  578. }
  579. CStr cstrName;
  580. CStr cstrCanEx = ptzCanEx;
  581. CStr cstrFolder;
  582. GetNameParts(cstrCanEx, cstrFolder, cstrName);
  583. ErrMsgParam(IDS_GRP_ALREADY_MEMBER,
  584. reinterpret_cast<LPARAM>((LPCTSTR)cstrName), m_hPage);
  585. DO_DEL(ptzCanEx);
  586. return HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
  587. }
  588. lvi.iItem++;
  589. }
  590. }
  591. //
  592. // Put the item into the list.
  593. //
  594. pListItem = new CMemberListItem;
  595. CHECK_NULL_REPORT(pListItem, m_hPage, goto ErrorCleanup);
  596. if (!AllocWStr(pwzPath, &pwzPathCopy))
  597. {
  598. REPORT_ERROR(E_OUTOFMEMORY, m_hPage);
  599. hr = E_OUTOFMEMORY;
  600. goto ErrorCleanup;
  601. }
  602. pListItem->m_ptzName = ptzCanEx;
  603. pListItem->m_pwzDN = pwzPathCopy;
  604. pListItem->m_fIsAlreadyMember = fAlreadyMember;
  605. pListItem->m_fCanBePrimary = fCanBePrimary;
  606. pListItem->m_fIsPrimary = fPrimary;
  607. pListItem->m_ulScopeType = ulScopeType;
  608. hr = CDsObjList::InsertIntoList(ptzCanEx, pListItem, iIcon);
  609. CHECK_HRESULT(hr, goto ErrorCleanup);
  610. return hrRet;
  611. ErrorCleanup:
  612. DO_DEL(pwzPathCopy);
  613. DO_DEL(ptzCanEx);
  614. DO_DEL(pListItem);
  615. return hr;
  616. }
  617. //+----------------------------------------------------------------------------
  618. //
  619. // Method: CDsMembershipList::InsertIntoList
  620. //
  621. // Synopsis: Insert the item into the listview control. This method uses
  622. // the object-SID to identify the new group member which in this
  623. // case is from an external domain.
  624. //
  625. // Arguments: [pSid] - a binary SID.
  626. // [pwzPath] - an object name in WINNT format (domain\name or
  627. // domain/name).
  628. //
  629. //-----------------------------------------------------------------------------
  630. HRESULT
  631. CDsMembershipList::InsertIntoList(PSID pSid, PWSTR pwzPath)
  632. {
  633. HRESULT hr;
  634. PTSTR ptzCanEx, ptzSlash;
  635. CMemberListItem * pListItem = NULL;
  636. if (!UnicodeToTchar(pwzPath, &ptzCanEx))
  637. {
  638. REPORT_ERROR(E_OUTOFMEMORY, m_hPage);
  639. return E_OUTOFMEMORY;
  640. }
  641. ptzSlash = _tcspbrk(ptzCanEx, TEXT("\n"));
  642. if (!ptzSlash)
  643. {
  644. ptzSlash = _tcspbrk(ptzCanEx, TEXT("/\\"));
  645. dspAssert(ptzSlash);
  646. if (ptzSlash)
  647. {
  648. *ptzSlash = TEXT('\n');
  649. }
  650. }
  651. //
  652. // Check to see if the item is already in the list. Use the display name
  653. // (canonical name) rather than the DN since the DN of an existing external
  654. // domain group member will be different from the initial path name (the
  655. // <SID=01050xxx> name).
  656. //
  657. LV_ITEM lvi;
  658. lvi.mask = LVIF_PARAM;
  659. lvi.iItem = 0;
  660. lvi.iSubItem = IDX_NAME_COL;
  661. while (ListView_GetItem(m_hList, &lvi))
  662. {
  663. pListItem = (CMemberListItem *)lvi.lParam;
  664. dspAssert(pListItem);
  665. if (_tcsicmp(pListItem->m_ptzName, ptzCanEx) == 0)
  666. {
  667. CStr cstrName;
  668. CStr cstrCanEx = ptzCanEx;
  669. CStr cstrFolder;
  670. GetNameParts(cstrCanEx, cstrFolder, cstrName);
  671. ErrMsgParam(IDS_GRP_ALREADY_MEMBER,
  672. reinterpret_cast<LPARAM>((LPCTSTR)cstrName), m_hPage);
  673. DO_DEL(ptzCanEx);
  674. return HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
  675. }
  676. lvi.iItem++;
  677. }
  678. //
  679. // Put the item into the list.
  680. //
  681. pListItem = new CMemberListItem;
  682. CHECK_NULL_REPORT(pListItem, m_hPage, return E_OUTOFMEMORY);
  683. PWSTR pwzSidPath;
  684. CStrW strSIDname;
  685. ConvertSidToPath(pSid, strSIDname);
  686. if (!AllocWStr(const_cast<PWSTR>((LPCWSTR)strSIDname), &pwzSidPath))
  687. {
  688. REPORT_ERROR(E_OUTOFMEMORY, m_hPage);
  689. hr = E_OUTOFMEMORY;
  690. goto ErrorCleanup;
  691. }
  692. pListItem->m_ptzName = ptzCanEx;
  693. pListItem->m_pwzDN = pwzSidPath;
  694. pListItem->m_fIsExternal = TRUE;
  695. pListItem->SetSid(pSid);
  696. hr = CDsObjList::InsertIntoList(ptzCanEx, pListItem);
  697. CHECK_HRESULT(hr, goto ErrorCleanup);
  698. return S_OK;
  699. ErrorCleanup:
  700. DO_DEL(pwzSidPath);
  701. DO_DEL(ptzCanEx);
  702. DO_DEL(pListItem);
  703. return hr;
  704. }
  705. //+----------------------------------------------------------------------------
  706. //
  707. // Method: CDsMembershipList::InsertIntoList
  708. //
  709. // Synopsis: Insert the item into the listview control.
  710. //
  711. //-----------------------------------------------------------------------------
  712. HRESULT
  713. CDsMembershipList::InsertIntoList(CMemberListItem * pItem)
  714. {
  715. HRESULT hr = S_OK;
  716. PWSTR pwzCanEx = NULL;
  717. PTSTR ptzCanEx = NULL;
  718. //
  719. // Convert the 1779 name to a more friendly variant for display
  720. // in the list.
  721. //
  722. hr = CrackName(pItem->m_pwzDN, &pwzCanEx, GET_OBJ_CAN_NAME_EX, m_hPage);
  723. CHECK_HRESULT(hr, goto ErrorCleanup);
  724. if (!UnicodeToTchar(pwzCanEx, &ptzCanEx))
  725. {
  726. LocalFreeStringW(&pwzCanEx);
  727. REPORT_ERROR(E_OUTOFMEMORY, m_hPage);
  728. hr = E_OUTOFMEMORY;
  729. goto ErrorCleanup;
  730. }
  731. LocalFreeStringW(&pwzCanEx);
  732. hr = CDsObjList::InsertIntoList(ptzCanEx, pItem);
  733. CHECK_HRESULT(hr, goto ErrorCleanup);
  734. return S_OK;
  735. ErrorCleanup:
  736. DO_DEL(ptzCanEx);
  737. DO_DEL(pItem);
  738. return hr;
  739. }
  740. //+----------------------------------------------------------------------------
  741. //
  742. // Method: CDsObjList::RemoveListItem
  743. //
  744. // Synopsis: Removes the indicated list item.
  745. //
  746. //-----------------------------------------------------------------------------
  747. BOOL
  748. CDsObjList::RemoveListItem(int Index)
  749. {
  750. if (!ListView_DeleteItem(m_hList, Index))
  751. {
  752. REPORT_ERROR(GetLastError(), m_hPage);
  753. return FALSE;
  754. }
  755. m_nCurItem--;
  756. return TRUE;
  757. }
  758. //+----------------------------------------------------------------------------
  759. //
  760. // Method: CDsMembershipList::RemoveListItem
  761. //
  762. // Synopsis: Removes the indicated list item, deleting the item data obj.
  763. //
  764. //-----------------------------------------------------------------------------
  765. BOOL
  766. CDsMembershipList::RemoveListItem(int Index)
  767. {
  768. CMemberListItem * pItem;
  769. LV_ITEM lvi;
  770. lvi.mask = LVIF_PARAM;
  771. lvi.iItem = Index;
  772. lvi.iSubItem = IDX_NAME_COL;
  773. if (!ListView_GetItem(m_hList, &lvi))
  774. {
  775. dspAssert(FALSE);
  776. return FALSE;
  777. }
  778. pItem = (CMemberListItem *)lvi.lParam;
  779. if (pItem)
  780. {
  781. delete pItem;
  782. }
  783. if (!ListView_DeleteItem(m_hList, Index))
  784. {
  785. REPORT_ERROR(GetLastError(), m_hPage);
  786. return FALSE;
  787. }
  788. m_nCurItem--;
  789. return TRUE;
  790. }
  791. //+----------------------------------------------------------------------------
  792. //
  793. // Method: CDsMembershipList::ClearList
  794. //
  795. // Synopsis: Remove all list items, freeing memory.
  796. //
  797. //-----------------------------------------------------------------------------
  798. void
  799. CDsMembershipList::ClearList(void)
  800. {
  801. CMemberListItem * pItem;
  802. LV_ITEM lvi;
  803. lvi.mask = LVIF_PARAM;
  804. lvi.iItem = 0;
  805. lvi.iSubItem = IDX_NAME_COL;
  806. while (ListView_GetItem(m_hList, &lvi))
  807. {
  808. pItem = (CMemberListItem *)lvi.lParam;
  809. if (pItem)
  810. {
  811. delete pItem;
  812. }
  813. lvi.iItem++;
  814. }
  815. ListView_DeleteAllItems(m_hList);
  816. m_nCurItem = 0;
  817. }
  818. //+----------------------------------------------------------------------------
  819. //
  820. // Method: CDsMembershipList::GetIndex
  821. //
  822. // Synopsis: Find the list entry whose DN matches and return the index.
  823. //
  824. // Arguments: [pwzDN] - DN to match, matches only first instance.
  825. // [ulStart] - Index on which to start search.
  826. // [ulEnd] - Search end index. If zero or less than ulStart,
  827. // search to the end of the list.
  828. //
  829. //-----------------------------------------------------------------------------
  830. int
  831. CDsMembershipList::GetIndex(LPCWSTR pwzDN, ULONG ulStart, ULONG ulEnd)
  832. {
  833. int i = ulStart;
  834. CMemberListItem * pItem;
  835. while (TRUE)
  836. {
  837. if (FAILED(GetItem(i, &pItem)))
  838. {
  839. return -1;
  840. }
  841. if (_wcsicmp(pwzDN, pItem->m_pwzDN) == 0)
  842. {
  843. return i;
  844. }
  845. if (ulEnd && (ULONG)i >= ulEnd)
  846. {
  847. return -1;
  848. }
  849. i++;
  850. }
  851. }
  852. //+----------------------------------------------------------------------------
  853. //
  854. // Method: CDsMembershipList::SetMemberIcons
  855. //
  856. // Synopsis: Query the DS for the class and userAccountControl of the list's
  857. // members. Use the returned info to select an icon for each item.
  858. //
  859. //-----------------------------------------------------------------------------
  860. HRESULT
  861. CDsMembershipList::SetMemberIcons(CDsPropPageBase *pPage)
  862. {
  863. HRESULT hr = S_OK;
  864. //
  865. // Just put this here so /W4 doesn't complain when compiling for Win9x
  866. //
  867. pPage;
  868. if (0 == g_ulMemberFilterCount)
  869. {
  870. return S_OK;
  871. }
  872. if ((ULONG)GetCount() > g_ulMemberQueryLimit)
  873. {
  874. m_fLimitExceeded = TRUE;
  875. return S_OK;
  876. }
  877. #if defined (DSADMIN)
  878. CComPtr <IDirectorySearch> spDsSearch;
  879. CSmartWStr cswzCleanObj;
  880. PWSTR pwzDnsDom;
  881. hr = pPage->SkipPrefix(pPage->GetObjPathName(), &cswzCleanObj);
  882. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  883. //
  884. // To bind to a GC, you need to supply the domain name rather than the
  885. // server path because the current DC may not be hosting a GC.
  886. //
  887. hr = CrackName(cswzCleanObj, &pwzDnsDom, GET_DNS_DOMAIN_NAME, pPage->GetHWnd());
  888. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  889. hr = DSPROP_GetGCSearchOnDomain(pwzDnsDom,
  890. IID_IDirectorySearch,
  891. (PVOID*)&spDsSearch);
  892. LocalFreeStringW(&pwzDnsDom);
  893. if (S_OK != hr)
  894. {
  895. if (S_FALSE == hr ||
  896. HRESULT_FROM_WIN32(ERROR_DS_SERVER_DOWN) == hr)
  897. {
  898. ErrMsg(IDS_WARN_NO_GC_FOUND, pPage->GetHWnd());
  899. }
  900. else if (HRESULT_FROM_WIN32(ERROR_LOGON_FAILURE) == hr)
  901. {
  902. ErrMsg(IDS_WARN_ACCESS_TO_GC_DENIED, pPage->GetHWnd());
  903. }
  904. else
  905. {
  906. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(),;);
  907. }
  908. return hr;
  909. }
  910. CStrW csFilter = L"(|", csClass, csClause;
  911. CMemberListItem * pItem;
  912. ULONG i, ulStart = 0, ulEnd;
  913. ADS_SEARCHPREF_INFO SearchPref;
  914. WCHAR wzSearchFormat[] = L"(%s=%s)";
  915. PWSTR pwzAttrNames[] = {g_wzDN, g_wzObjectClass, g_wzUserAccountControl};
  916. SearchPref.dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  917. SearchPref.vValue.Integer = ADS_SCOPE_SUBTREE;
  918. SearchPref.vValue.dwType = ADSTYPE_INTEGER;
  919. hr = spDsSearch->SetSearchPreference(&SearchPref, 1);
  920. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  921. while (TRUE)
  922. {
  923. ulEnd = ulStart + g_ulMemberFilterCount;
  924. for (i = ulStart; i < ulEnd; i++)
  925. {
  926. if (GetItem(i, &pItem) == HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS))
  927. {
  928. // End Of List, reset end counter.
  929. //
  930. ulEnd = i;
  931. break;
  932. }
  933. csClause.Format(wzSearchFormat, g_wzDN, pItem->m_pwzDN);
  934. csFilter += csClause;
  935. }
  936. csFilter += L")";
  937. ADS_SEARCH_HANDLE hSrch = NULL;
  938. dspDebugOut((DEB_USER14 | DEB_ITRACE, "About to do the member search.\n"));
  939. hr = spDsSearch->ExecuteSearch((PWSTR)(LPCWSTR)csFilter,
  940. pwzAttrNames, ARRAYLENGTH(pwzAttrNames),
  941. &hSrch);
  942. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  943. dspDebugOut((DEB_USER14 | DEB_ITRACE, "Member search returned.\n"));
  944. hr = spDsSearch->GetNextRow(hSrch);
  945. for (i = ulStart; (i < ulEnd) && (S_OK == hr); i++)
  946. {
  947. ADS_SEARCH_COLUMN Column;
  948. BOOL fDisabled = FALSE;
  949. CStrW csDN;
  950. int iIndex;
  951. //
  952. // Get the object dn.
  953. //
  954. hr = spDsSearch->GetColumn(hSrch, g_wzDN, &Column);
  955. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), break);
  956. csDN = Column.pADsValues->CaseIgnoreString;
  957. spDsSearch->FreeColumn(&Column);
  958. //
  959. // Get the object class.
  960. //
  961. hr = spDsSearch->GetColumn(hSrch, g_wzObjectClass, &Column);
  962. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), break);
  963. // Krishna sez the most derived class is *always* the last array element...
  964. csClass = Column.pADsValues[Column.dwNumValues - 1].CaseIgnoreString;
  965. spDsSearch->FreeColumn(&Column);
  966. //
  967. // Get the object userAccountControl.
  968. //
  969. hr = spDsSearch->GetColumn(hSrch, g_wzUserAccountControl, &Column);
  970. if (S_OK == hr)
  971. {
  972. fDisabled = (Column.pADsValues->Integer & UF_ACCOUNTDISABLE) != 0;
  973. spDsSearch->FreeColumn(&Column);
  974. }
  975. if ((iIndex = GetIndex(csDN, ulStart, ulEnd)) == -1)
  976. {
  977. dspAssert(FALSE && "list entry not found!");
  978. return E_FAIL;
  979. }
  980. LV_ITEM lvi = {0};
  981. lvi.mask = LVIF_IMAGE;
  982. lvi.iSubItem = IDX_NAME_COL;
  983. lvi.iItem = iIndex;
  984. lvi.iImage = g_ClassIconCache.GetClassIconIndex(csClass, fDisabled);
  985. if (lvi.iImage == -1)
  986. {
  987. lvi.iImage = g_ClassIconCache.AddClassIcon(csClass, fDisabled);
  988. }
  989. ListView_SetItem(m_hList, &lvi);
  990. hr = spDsSearch->GetNextRow(hSrch);
  991. }
  992. dspDebugOut((DEB_USER14 | DEB_ITRACE, "Members updated with icons.\n"));
  993. spDsSearch->CloseSearchHandle(hSrch);
  994. if (ulEnd != (ulStart + g_ulMemberFilterCount))
  995. {
  996. // EOL, stop processing.
  997. //
  998. break;
  999. }
  1000. ulStart = ulEnd;
  1001. csFilter = L"(|";
  1002. }
  1003. #endif // defined (DSADMIN)
  1004. return hr;
  1005. }
  1006. //+----------------------------------------------------------------------------
  1007. //
  1008. // Class: CMemberListItem
  1009. //
  1010. // Purpose: Item data for the reverse membership list.
  1011. //
  1012. //-----------------------------------------------------------------------------
  1013. //+----------------------------------------------------------------------------
  1014. //
  1015. // Method: CMemberListItem::Copy
  1016. //
  1017. // Synopsis: Return a copy of the original element.
  1018. //
  1019. //-----------------------------------------------------------------------------
  1020. CMemberListItem *
  1021. CMemberListItem::Copy(void)
  1022. {
  1023. CMemberListItem * pItem = new CMemberListItem;
  1024. CHECK_NULL(pItem, return NULL);
  1025. if (this->m_pwzDN)
  1026. {
  1027. if (!AllocWStr(this->m_pwzDN, &pItem->m_pwzDN))
  1028. {
  1029. delete pItem;
  1030. return NULL;
  1031. }
  1032. }
  1033. if (this->m_ptzName)
  1034. {
  1035. if (!AllocTStr(this->m_ptzName, &pItem->m_ptzName))
  1036. {
  1037. delete pItem;
  1038. return NULL;
  1039. }
  1040. }
  1041. if (this->m_pSid)
  1042. {
  1043. if (!pItem->SetSid(this->m_pSid))
  1044. {
  1045. delete pItem;
  1046. return NULL;
  1047. }
  1048. }
  1049. pItem->m_fIsPrimary = this->m_fIsPrimary;
  1050. pItem->m_ulScopeType = this->m_ulScopeType;
  1051. pItem->m_fSidSet = this->m_fSidSet;
  1052. pItem->m_fCanBePrimarySet = this->m_fCanBePrimarySet;
  1053. pItem->m_fCanBePrimary = this->m_fCanBePrimary;
  1054. pItem->m_fIsAlreadyMember = this->m_fIsAlreadyMember;
  1055. pItem->m_fIsExternal = this->m_fIsExternal;
  1056. return pItem;
  1057. }
  1058. //+----------------------------------------------------------------------------
  1059. //
  1060. // Method: CMemberListItem::SetSid
  1061. //
  1062. // Synopsis: Copy and store the passed in SID.
  1063. //
  1064. //-----------------------------------------------------------------------------
  1065. BOOL
  1066. CMemberListItem::SetSid(PSID pSid)
  1067. {
  1068. int cb = GetLengthSid(pSid);
  1069. dspAssert(cb);
  1070. this->m_pSid = new BYTE[cb];
  1071. CHECK_NULL(this->m_pSid, return FALSE);
  1072. memcpy(this->m_pSid, pSid, cb);
  1073. m_fSidSet = TRUE;
  1074. return TRUE;
  1075. }
  1076. //+----------------------------------------------------------------------------
  1077. //
  1078. // Function: ConvertSidToPath
  1079. //
  1080. // Synopsis: Converts the binary SID to a string LDAP path.
  1081. //
  1082. //-----------------------------------------------------------------------------
  1083. void
  1084. ConvertSidToPath(PSID pObjSID, CStrW &strSIDname)
  1085. {
  1086. strSIDname = g_wzSidPathPrefix;
  1087. //
  1088. // Convert the bytes of the sid to hex chars.
  1089. //
  1090. PBYTE pbSid = (PBYTE)pObjSID;
  1091. ULONG i;
  1092. PUCHAR pcSubAuth = NULL;
  1093. pcSubAuth = GetSidSubAuthorityCount(pObjSID);
  1094. dspAssert(pcSubAuth);
  1095. ULONG cbSid = GetSidLengthRequired(*pcSubAuth);
  1096. dspAssert(cbSid);
  1097. dspAssert(cbSid == (*pcSubAuth - 1) * (sizeof(DWORD)) + sizeof(SID));
  1098. for (i = 0; i < cbSid; i++)
  1099. {
  1100. WCHAR wzCur[3];
  1101. wsprintfW(wzCur, L"%02x", *pbSid);
  1102. pbSid++;
  1103. strSIDname += wzCur;
  1104. }
  1105. strSIDname += g_wzSidPathSuffix;
  1106. }
  1107. //+----------------------------------------------------------------------------
  1108. //
  1109. // Method: CClassIconCache::CClassIconCache
  1110. //
  1111. //-----------------------------------------------------------------------------
  1112. CClassIconCache::CClassIconCache(void) :
  1113. m_fInitialized(FALSE),
  1114. m_prgcce(NULL),
  1115. m_hImageList(NULL)
  1116. {
  1117. TRACE(CClassIconCache,CClassIconCache);
  1118. m_nImageCount = 0;
  1119. }
  1120. //+----------------------------------------------------------------------------
  1121. //
  1122. // Method: CClassIconCache::~CClassIconCache
  1123. //
  1124. //-----------------------------------------------------------------------------
  1125. CClassIconCache::~CClassIconCache(void)
  1126. {
  1127. TRACE(CClassIconCache,~CClassIconCache);
  1128. ClearAll();
  1129. }
  1130. //+----------------------------------------------------------------------------
  1131. //
  1132. // Method: CClassIconCache::ClearAll
  1133. //
  1134. //-----------------------------------------------------------------------------
  1135. void CClassIconCache::ClearAll(void)
  1136. {
  1137. if (m_hImageList != NULL)
  1138. {
  1139. ImageList_RemoveAll(m_hImageList);
  1140. ImageList_Destroy(m_hImageList);
  1141. m_hImageList = NULL;
  1142. }
  1143. if (m_prgcce != NULL)
  1144. {
  1145. delete[] m_prgcce;
  1146. m_prgcce = NULL;
  1147. m_nImageCount = 0;
  1148. }
  1149. m_fInitialized = FALSE;
  1150. }
  1151. //+----------------------------------------------------------------------------
  1152. //
  1153. // Method: CClassIconCache::GetClassIconIndex
  1154. //
  1155. //-----------------------------------------------------------------------------
  1156. int CClassIconCache::GetClassIconIndex(PCWSTR pwzClass, BOOL fDisabled)
  1157. {
  1158. int iIcon = -1;
  1159. dspAssert(pwzClass);
  1160. Initialize();
  1161. if (m_prgcce != NULL && m_nImageCount > 0)
  1162. {
  1163. for (UINT i = 0; i < m_nImageCount; i++)
  1164. {
  1165. if (_wcsicmp(pwzClass, m_prgcce[i].wzClass) == 0)
  1166. {
  1167. iIcon = (fDisabled) ? m_prgcce[i].iDisabledIcon : m_prgcce[i].iIcon;
  1168. break;
  1169. }
  1170. }
  1171. }
  1172. dspDebugOut((DEB_USER14, "CClassIconCache::GetClassIconIndex returning %d\n", iIcon));
  1173. return iIcon;
  1174. }
  1175. //+----------------------------------------------------------------------------
  1176. //
  1177. // Method: CClassIconCache::AddClassIcon
  1178. //
  1179. //-----------------------------------------------------------------------------
  1180. int CClassIconCache::AddClassIcon(PCWSTR pwzClass, BOOL fDisabled)
  1181. {
  1182. //
  1183. // Retrieves the icon for the class from the DisplaySpecifiers and puts it
  1184. // in the image list
  1185. //
  1186. HICON hIcon = NULL;
  1187. HICON hDisabledIcon = NULL;
  1188. hIcon = DsGetIcon(DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON, const_cast<PWSTR>(pwzClass), 16, 16);
  1189. if (!hIcon)
  1190. {
  1191. DBG_OUT("CClassIconCache::AddClassIcon failed in DsGetIcon for normal icon");
  1192. return E_OUTOFMEMORY;
  1193. }
  1194. hDisabledIcon = DsGetIcon(DSGIF_ISDISABLED | DSGIF_GETDEFAULTICON, const_cast<PWSTR>(pwzClass), 16, 16);
  1195. if (!hDisabledIcon)
  1196. {
  1197. DBG_OUT("CClassIconCache::AddClassIcon failed in DsGetIcon for disabled icon");
  1198. hDisabledIcon = hIcon;
  1199. }
  1200. if (m_prgcce != NULL)
  1201. {
  1202. CLASS_CACHE_ENTRY* pNewList = new CLASS_CACHE_ENTRY[m_nImageCount + 1];
  1203. if (pNewList == NULL)
  1204. {
  1205. return -1;
  1206. }
  1207. memcpy(pNewList, m_prgcce, sizeof(CLASS_CACHE_ENTRY) * m_nImageCount);
  1208. delete[] m_prgcce;
  1209. m_prgcce = pNewList;
  1210. m_prgcce[m_nImageCount].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
  1211. if (hDisabledIcon == hIcon)
  1212. {
  1213. m_prgcce[m_nImageCount].iDisabledIcon = m_prgcce[m_nImageCount].iIcon;
  1214. }
  1215. else
  1216. {
  1217. m_prgcce[m_nImageCount].iDisabledIcon = ImageList_AddIcon(m_hImageList, hDisabledIcon);
  1218. }
  1219. m_nImageCount++;
  1220. }
  1221. DestroyIcon(hIcon);
  1222. if (hDisabledIcon != hIcon)
  1223. {
  1224. DestroyIcon(hDisabledIcon);
  1225. }
  1226. return (fDisabled) ? m_prgcce[m_nImageCount - 1].iDisabledIcon : m_prgcce[m_nImageCount - 1].iIcon;
  1227. }
  1228. //+----------------------------------------------------------------------------
  1229. //
  1230. // Method: CClassIconCache::Initialize
  1231. //
  1232. //-----------------------------------------------------------------------------
  1233. HRESULT CClassIconCache::Initialize(void)
  1234. {
  1235. if (m_fInitialized)
  1236. {
  1237. return S_OK;
  1238. }
  1239. if (m_prgcce != NULL)
  1240. {
  1241. delete[] m_prgcce;
  1242. m_prgcce = NULL;
  1243. m_nImageCount = 0;
  1244. }
  1245. m_nImageCount = ICON_CACHE_NUM_CLASSES;
  1246. m_prgcce = new CLASS_CACHE_ENTRY[m_nImageCount];
  1247. if (m_prgcce == NULL)
  1248. {
  1249. m_nImageCount = 0;
  1250. return -1;
  1251. }
  1252. memset(m_prgcce, 0, sizeof(CLASS_CACHE_ENTRY) * m_nImageCount);
  1253. dspAssert(m_prgcce != NULL);
  1254. TRACE(CClassIconCache,Initialize);
  1255. m_hImageList = ImageList_Create(16, 16, ILC_COLOR | ILC_MASK, 1, 1);
  1256. if (NULL == m_hImageList)
  1257. {
  1258. DBG_OUT("ImageList_Create failed");
  1259. return E_OUTOFMEMORY;
  1260. }
  1261. HICON hIcon;
  1262. //
  1263. // Default
  1264. //
  1265. hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MEMBER));
  1266. if (!hIcon)
  1267. {
  1268. DBG_OUT("DsGetIcon failed for member icon");
  1269. return E_OUTOFMEMORY;
  1270. }
  1271. m_prgcce[0].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
  1272. wcscpy(m_prgcce[0].wzClass, L"default");
  1273. m_prgcce[0].iDisabledIcon = m_prgcce[0].iIcon;
  1274. //
  1275. // User
  1276. //
  1277. hIcon = DsGetIcon(DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON, g_wzUser, 16, 16);
  1278. if (!hIcon)
  1279. {
  1280. DBG_OUT("DsGetIcon failed for user icon");
  1281. return E_OUTOFMEMORY;
  1282. }
  1283. m_prgcce[1].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
  1284. DestroyIcon(hIcon);
  1285. hIcon = DsGetIcon(DSGIF_ISDISABLED | DSGIF_GETDEFAULTICON, g_wzUser, 16, 16);
  1286. if (!hIcon)
  1287. {
  1288. DBG_OUT("DsGetIcon failed for user disable icon");
  1289. return E_OUTOFMEMORY;
  1290. }
  1291. m_prgcce[1].iDisabledIcon = ImageList_AddIcon(m_hImageList, hIcon);
  1292. DestroyIcon(hIcon);
  1293. wcscpy(m_prgcce[1].wzClass, g_wzUser);
  1294. //
  1295. // Computer
  1296. //
  1297. hIcon = DsGetIcon(DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON, g_wzComputer, 16, 16);
  1298. if (!hIcon)
  1299. {
  1300. DBG_OUT("DsGetIcon failed for computer icon");
  1301. return E_OUTOFMEMORY;
  1302. }
  1303. m_prgcce[2].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
  1304. DestroyIcon(hIcon);
  1305. hIcon = DsGetIcon(DSGIF_ISDISABLED | DSGIF_GETDEFAULTICON, g_wzComputer, 16, 16);
  1306. if (!hIcon)
  1307. {
  1308. DBG_OUT("DsGetIcon failed for computer disable icon");
  1309. return E_OUTOFMEMORY;
  1310. }
  1311. m_prgcce[2].iDisabledIcon = ImageList_AddIcon(m_hImageList, hIcon);
  1312. DestroyIcon(hIcon);
  1313. wcscpy(m_prgcce[2].wzClass, g_wzComputer);
  1314. //
  1315. // Contact
  1316. //
  1317. hIcon = DsGetIcon(DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON, g_wzContact, 16, 16);
  1318. if (!hIcon)
  1319. {
  1320. DBG_OUT("DsGetIcon failed for contact icon");
  1321. return E_OUTOFMEMORY;
  1322. }
  1323. m_prgcce[3].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
  1324. DestroyIcon(hIcon);
  1325. m_prgcce[3].iDisabledIcon = -1;
  1326. wcscpy(m_prgcce[3].wzClass, g_wzContact);
  1327. //
  1328. // Group
  1329. //
  1330. hIcon = DsGetIcon(DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON, g_wzGroup, 16, 16);
  1331. if (!hIcon)
  1332. {
  1333. DBG_OUT("DsGetIcon failed for group icon");
  1334. return E_OUTOFMEMORY;
  1335. }
  1336. m_prgcce[4].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
  1337. DestroyIcon(hIcon);
  1338. m_prgcce[4].iDisabledIcon = -1;
  1339. wcscpy(m_prgcce[4].wzClass, g_wzGroup);
  1340. //
  1341. // FPO
  1342. //
  1343. hIcon = DsGetIcon(DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON, g_wzFPO, 16, 16);
  1344. if (!hIcon)
  1345. {
  1346. DBG_OUT("DsGetIcon failed for fpo icon");
  1347. return E_OUTOFMEMORY;
  1348. }
  1349. m_prgcce[5].iIcon = ImageList_AddIcon(m_hImageList, hIcon);
  1350. DestroyIcon(hIcon);
  1351. m_prgcce[5].iDisabledIcon = -1;
  1352. wcscpy(m_prgcce[5].wzClass, g_wzFPO);
  1353. m_fInitialized = TRUE;
  1354. return S_OK;
  1355. }
  1356. //+----------------------------------------------------------------------------
  1357. //
  1358. // Method: CClassIconCache::GetImageList
  1359. //
  1360. //-----------------------------------------------------------------------------
  1361. HIMAGELIST CClassIconCache::GetImageList(void)
  1362. {
  1363. if (FAILED(Initialize()))
  1364. {
  1365. return NULL;
  1366. }
  1367. return m_hImageList;
  1368. }