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.

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