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.

1156 lines
35 KiB

  1. // DSColumn.cpp : Implementation of ds column routines and classes
  2. //+-------------------------------------------------------------------------
  3. //
  4. // Microsoft Windows
  5. // Copyright (C) Microsoft Corporation, 1992 - 1999
  6. //
  7. // File: DSColumn.cpp
  8. //
  9. // Contents: DS Column routines, classes, and static data
  10. //
  11. // History: 12-Mar-99 JeffJon Created
  12. //
  13. //
  14. //--------------------------------------------------------------------------
  15. #include "stdafx.h"
  16. #include "resource.h"
  17. #include "util.h"
  18. #include "DSColumn.h"
  19. #include "dscookie.h"
  20. #include "dscmn.h" // CrackName()
  21. #include "dsutil.h"
  22. BOOL ColumnExtractStringValue(
  23. OUT CString& strref,
  24. IN CDSCookie*,
  25. IN PADS_SEARCH_COLUMN pColumn,
  26. IN DWORD iValue)
  27. {
  28. if (pColumn == NULL || pColumn->dwNumValues <= iValue)
  29. {
  30. return FALSE;
  31. }
  32. switch (pColumn->dwADsType)
  33. {
  34. case ADSTYPE_CASE_IGNORE_STRING:
  35. strref = (LPCWSTR)pColumn->pADsValues[iValue].CaseIgnoreString;
  36. break;
  37. case ADSTYPE_DN_STRING:
  38. strref = (LPCWSTR)pColumn->pADsValues[iValue].DNString;
  39. break;
  40. default:
  41. return FALSE;
  42. }
  43. return TRUE;
  44. }
  45. BOOL ColumnExtractString(
  46. OUT CString& strref,
  47. IN CDSCookie* pCookie,
  48. IN PADS_SEARCH_COLUMN pColumn)
  49. {
  50. return ColumnExtractStringValue( strref, pCookie, pColumn, 0 );
  51. }
  52. BOOL ColumnExtractElementFromDN(
  53. OUT CString& strref,
  54. IN CDSCookie* pCookie,
  55. IN PADS_SEARCH_COLUMN pColumn,
  56. long lElement,
  57. IN DWORD iValue = 0);
  58. BOOL ColumnExtractElementFromDN(
  59. OUT CString& strref,
  60. IN CDSCookie* pCookie,
  61. IN PADS_SEARCH_COLUMN pColumn,
  62. long lElement,
  63. IN DWORD iValue)
  64. {
  65. if (pColumn == NULL)
  66. {
  67. return FALSE;
  68. }
  69. BOOL fRetval = FALSE;
  70. CString str;
  71. CComBSTR bstr;
  72. HRESULT hr = S_OK;
  73. do { // false loop
  74. if ( !ColumnExtractStringValue( str, pCookie, pColumn, iValue ) || str.IsEmpty() )
  75. {
  76. strref.Empty();
  77. fRetval = TRUE;
  78. break;
  79. }
  80. CPathCracker pathCracker;
  81. hr = pathCracker.Set(const_cast<BSTR>((LPCTSTR)str), ADS_SETTYPE_DN);
  82. if ( FAILED(hr) )
  83. break;
  84. // no need to reset this
  85. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  86. if ( FAILED(hr) )
  87. break;
  88. hr = pathCracker.put_EscapedMode(ADS_ESCAPEDMODE_OFF);
  89. if ( FAILED(hr) )
  90. break;
  91. hr = pathCracker.GetElement(lElement, &bstr);
  92. strref = bstr;
  93. fRetval = TRUE;
  94. } while (FALSE); // false loop
  95. return fRetval;
  96. }
  97. BOOL ColumnExtractLeafFromDN(
  98. OUT CString& strref,
  99. IN CDSCookie* pCookie,
  100. IN PADS_SEARCH_COLUMN pColumn)
  101. {
  102. return ColumnExtractElementFromDN( strref, pCookie, pColumn, 0 );
  103. }
  104. BOOL ColumnExtractParentFromDN(
  105. OUT CString& strref,
  106. IN CDSCookie* pCookie,
  107. IN PADS_SEARCH_COLUMN pColumn)
  108. {
  109. return ColumnExtractElementFromDN( strref, pCookie, pColumn, 1 );
  110. }
  111. BOOL ColumnExtractGreatGrandparentFromDN(
  112. OUT CString& strref,
  113. IN CDSCookie* pCookie,
  114. IN PADS_SEARCH_COLUMN pColumn)
  115. {
  116. return ColumnExtractElementFromDN( strref, pCookie, pColumn, 3 );
  117. }
  118. BOOL ColumnExtractConnectionDisplayName(
  119. OUT CString& strref,
  120. IN CDSCookie* pCookie,
  121. IN PADS_SEARCH_COLUMN pColumn)
  122. {
  123. if (pColumn == NULL)
  124. {
  125. return FALSE;
  126. }
  127. ADS_INTEGER adsint = 0;
  128. switch (pColumn->dwADsType)
  129. {
  130. case ADSTYPE_INTEGER:
  131. adsint = pColumn->pADsValues->Integer;
  132. break;
  133. default:
  134. // no value, let it stay 0
  135. break;
  136. }
  137. if (NTDSCONN_OPT_IS_GENERATED & adsint) {
  138. strref.LoadString (IDS_CONNECTION_KCC_GENERATED);
  139. } else {
  140. strref = pCookie->GetName();
  141. }
  142. return TRUE;
  143. }
  144. BOOL ColumnExtractAttribute(
  145. OUT CString& strref,
  146. IN CDSCookie*,
  147. IN PADS_SEARCH_COLUMN pColumn)
  148. {
  149. if (pColumn == NULL)
  150. {
  151. return FALSE;
  152. }
  153. switch (pColumn->dwADsType)
  154. {
  155. case ADSTYPE_DN_STRING :
  156. strref = pColumn->pADsValues->DNString;
  157. break;
  158. case ADSTYPE_CASE_EXACT_STRING :
  159. strref = pColumn->pADsValues->CaseExactString;
  160. break;
  161. case ADSTYPE_CASE_IGNORE_STRING:
  162. strref = pColumn->pADsValues->CaseIgnoreString;
  163. break;
  164. case ADSTYPE_PRINTABLE_STRING :
  165. strref = pColumn->pADsValues->PrintableString;
  166. break;
  167. case ADSTYPE_NUMERIC_STRING :
  168. strref = pColumn->pADsValues->NumericString;
  169. break;
  170. case ADSTYPE_OBJECT_CLASS :
  171. strref = pColumn->pADsValues->ClassName;
  172. break;
  173. case ADSTYPE_BOOLEAN :
  174. strref = ((DWORD)pColumn->pADsValues->Boolean) ? L"TRUE" : L"FALSE";
  175. break;
  176. case ADSTYPE_INTEGER :
  177. strref.Format(L"%d", (DWORD) pColumn->pADsValues->Integer);
  178. break;
  179. case ADSTYPE_OCTET_STRING :
  180. {
  181. CString sOctet = L"";
  182. BYTE b;
  183. for ( DWORD idx=0; idx<pColumn->pADsValues->OctetString.dwLength; idx++)
  184. {
  185. b = ((BYTE *)pColumn->pADsValues->OctetString.lpValue)[idx];
  186. sOctet.Format(L"0x%02x ", b);
  187. strref += sOctet;
  188. }
  189. }
  190. break;
  191. case ADSTYPE_UTC_TIME:
  192. {
  193. PTSTR ptszDate = NULL;
  194. int cchDate = 0;
  195. SYSTEMTIME st = {0};
  196. if (!SystemTimeToTzSpecificLocalTime(NULL, &pColumn->pADsValues->UTCTime, &st))
  197. {
  198. strref = L"";
  199. return TRUE;
  200. }
  201. cchDate = GetDateFormat(LOCALE_USER_DEFAULT, 0 ,
  202. &st, NULL,
  203. ptszDate, 0);
  204. ptszDate = (PTSTR)malloc(sizeof(TCHAR) * cchDate);
  205. if (GetDateFormat(LOCALE_USER_DEFAULT, 0,
  206. &st, NULL,
  207. ptszDate, cchDate))
  208. {
  209. strref = ptszDate;
  210. }
  211. else
  212. {
  213. strref = L"";
  214. }
  215. free(ptszDate);
  216. PTSTR ptszTime = NULL;
  217. cchDate = GetTimeFormat(LOCALE_USER_DEFAULT, 0 ,
  218. &st, NULL,
  219. ptszTime, 0);
  220. ptszTime = (PTSTR)malloc(sizeof(TCHAR) * cchDate);
  221. if (ptszTime != NULL)
  222. {
  223. if (GetTimeFormat(LOCALE_USER_DEFAULT, 0,
  224. &st, NULL,
  225. ptszTime, cchDate))
  226. {
  227. strref += _T(" ") + CString(ptszTime);
  228. }
  229. else
  230. {
  231. strref += _T("");
  232. }
  233. free(ptszTime);
  234. }
  235. else
  236. {
  237. strref = _T("");
  238. }
  239. }
  240. break;
  241. default :
  242. ASSERT(FALSE);
  243. break;
  244. }
  245. return TRUE;
  246. }
  247. BOOL _ColumnCrackDN(
  248. OUT CString& strref,
  249. IN LPCTSTR lpcszDN,
  250. IN CRACK_NAME_OPR RequestedOpr)
  251. {
  252. PWSTR pwzName = NULL;
  253. HRESULT hr = CrackName(const_cast<PTSTR>(lpcszDN),
  254. &pwzName,
  255. RequestedOpr,
  256. NULL);
  257. if (SUCCEEDED(hr))
  258. {
  259. if (GET_OBJ_CAN_NAME_EX == RequestedOpr)
  260. {
  261. LPTSTR ptzCanName = wcschr( pwzName, _T('\n') );
  262. if (NULL != ptzCanName)
  263. strref = ptzCanName+1;
  264. else
  265. strref.Empty();
  266. }
  267. else
  268. {
  269. strref = pwzName;
  270. }
  271. LocalFreeStringW(&pwzName);
  272. }
  273. else
  274. {
  275. strref.Empty();
  276. }
  277. return TRUE;
  278. }
  279. BOOL ColumnExtractNameFromSID(
  280. OUT CString& strref,
  281. IN CDSCookie* pCookie,
  282. IN PADS_SEARCH_COLUMN)
  283. {
  284. return _ColumnCrackDN( strref, pCookie->GetPath(), GET_OBJ_CAN_NAME );
  285. }
  286. BOOL ColumnExtractCanonicalNameFromDN(
  287. OUT CString& strref,
  288. IN CDSCookie* pCookie,
  289. IN PADS_SEARCH_COLUMN pColumn)
  290. {
  291. if (pColumn == NULL)
  292. {
  293. return FALSE;
  294. }
  295. CString str;
  296. if ( !ColumnExtractString( str, pCookie, pColumn ) || str.IsEmpty() )
  297. {
  298. strref.Empty();
  299. return TRUE;
  300. }
  301. return _ColumnCrackDN( strref, str, GET_OBJ_CAN_NAME_EX );
  302. }
  303. BOOL ColumnExtractDomainFromDN(
  304. OUT CString& strref,
  305. IN CDSCookie* pCookie,
  306. IN PADS_SEARCH_COLUMN pColumn)
  307. {
  308. if (pColumn == NULL)
  309. {
  310. return FALSE;
  311. }
  312. CString str;
  313. if ( !ColumnExtractString( str, pCookie, pColumn ) || str.IsEmpty() )
  314. {
  315. strref.Empty();
  316. return TRUE;
  317. }
  318. return _ColumnCrackDN( strref, str, GET_DNS_DOMAIN_NAME );
  319. }
  320. int _cdecl _qsort_CompareColumns(const void * elem1, const void * elem2)
  321. {
  322. PADSVALUE p1 = (PADSVALUE)elem1;
  323. PADSVALUE p2 = (PADSVALUE)elem2;
  324. if (!p1 || !p2 || !p1->DNString || !p2->DNString)
  325. return 0;
  326. return wcscmp( p1->DNString, p2->DNString );
  327. }
  328. BOOL ColumnExtractLeafList(
  329. OUT CString& strref,
  330. IN CDSCookie* pCookie,
  331. IN PADS_SEARCH_COLUMN pColumn)
  332. {
  333. if (pColumn == NULL)
  334. {
  335. return FALSE;
  336. }
  337. // alphabetical order
  338. qsort( pColumn->pADsValues,
  339. pColumn->dwNumValues,
  340. sizeof(ADSVALUE),
  341. _qsort_CompareColumns );
  342. CString strSeparator;
  343. strSeparator.LoadString(IDS_SEPARATOR);
  344. for (DWORD iValue = 0; iValue < pColumn->dwNumValues; iValue++)
  345. {
  346. CString strTransport;
  347. if ( !ColumnExtractElementFromDN(
  348. strTransport, pCookie, pColumn, 0, iValue) )
  349. return FALSE;
  350. if (0 < iValue)
  351. strref += strSeparator;
  352. strref += strTransport;
  353. }
  354. return TRUE;
  355. }
  356. BOOL _ColumnCrackFRS(
  357. OUT CString& strref,
  358. IN CDSCookie* pCookie,
  359. IN CRACK_NAME_OPR RequestedOpr)
  360. {
  361. CDSCookieInfoConnection* pExtraInfo = NULL;
  362. if ( NULL == pCookie
  363. || _wcsicmp( pCookie->GetClass(), L"nTDSConnection" )
  364. || NULL == (pExtraInfo = (CDSCookieInfoConnection*)pCookie->GetExtraInfo())
  365. || pExtraInfo->GetClass() != CDSCookieInfoBase::connection
  366. || pExtraInfo->m_strFRSComputerReference.IsEmpty()
  367. )
  368. {
  369. strref.Empty();
  370. return TRUE;
  371. }
  372. return _ColumnCrackDN( strref, pExtraInfo->m_strFRSComputerReference, RequestedOpr );
  373. }
  374. BOOL ColumnExtractFRSComputer(
  375. OUT CString& strref,
  376. IN CDSCookie* pCookie,
  377. IN PADS_SEARCH_COLUMN)
  378. {
  379. return _ColumnCrackFRS( strref, pCookie, GET_OBJ_CAN_NAME_EX );
  380. }
  381. BOOL ColumnExtractFRSDomain(
  382. OUT CString& strref,
  383. IN CDSCookie* pCookie,
  384. IN PADS_SEARCH_COLUMN)
  385. {
  386. return _ColumnCrackFRS( strref, pCookie, GET_DNS_DOMAIN_NAME );
  387. }
  388. ATTRIBUTE_COLUMN colName = { ATTR_COLTYPE_NAME,
  389. IDS_COLUMN_NAME, //column header
  390. 100, //col. width
  391. NULL, //ldap attr. name
  392. NULL }; //extract fn()
  393. ATTRIBUTE_COLUMN colClass= { ATTR_COLTYPE_CLASS,
  394. IDS_COLUMN_TYPE, //column header
  395. 100, //col. width
  396. NULL, //ldap attr. name
  397. NULL }; //extract fn()
  398. ATTRIBUTE_COLUMN colDesc = { ATTR_COLTYPE_DESC,
  399. IDS_COLUMN_DESCRIPTION, //column header
  400. 150, //col. width
  401. NULL, //ldap attr. name
  402. NULL }; //extract fn()
  403. ATTRIBUTE_COLUMN colSite = { ATTR_COLTYPE_SPECIAL,
  404. IDS_COLUMN_SITE, //column header
  405. 100, //col. width
  406. L"siteObject", //ldap attr. name
  407. ColumnExtractLeafFromDN }; //extract fn()
  408. ATTRIBUTE_COLUMN colLocation = { ATTR_COLTYPE_SPECIAL,
  409. IDS_COLUMN_LOCATION, //column header
  410. 150, //col. width
  411. L"location", //ldap attr. name
  412. NULL }; //extract fn()
  413. ATTRIBUTE_COLUMN colDomain = { ATTR_COLTYPE_SPECIAL,
  414. IDS_COLUMN_DOMAIN, //column header
  415. 150, //col. width
  416. L"serverReference", //ldap attr. name
  417. ColumnExtractDomainFromDN }; //extract fn()
  418. ATTRIBUTE_COLUMN colBridgehead = { ATTR_COLTYPE_SPECIAL,
  419. IDS_COLUMN_BRIDGEHEAD, //column header
  420. 150, //col. width
  421. L"bridgeheadTransportList", //ldap attr. name
  422. ColumnExtractLeafList }; //extract fn()
  423. ATTRIBUTE_COLUMN colReplicaComputer = { ATTR_COLTYPE_SPECIAL,
  424. IDS_COLUMN_COMPUTER, //column header
  425. 100, //col. width
  426. L"fRSComputerReference", //ldap attr. name
  427. ColumnExtractCanonicalNameFromDN }; //extract fn()
  428. ATTRIBUTE_COLUMN colReplicaDomain = { ATTR_COLTYPE_SPECIAL,
  429. IDS_COLUMN_DOMAIN, //column header
  430. 150, //col. width
  431. L"fRSComputerReference", //ldap attr. name
  432. ColumnExtractDomainFromDN }; //extract fn()
  433. ATTRIBUTE_COLUMN colFromFRSComputer = { ATTR_COLTYPE_SPECIAL,
  434. IDS_COLUMN_FROM_COMPUTER, //column header
  435. 100, //col. width
  436. L"fromServer", //ldap attr. name
  437. ColumnExtractFRSComputer }; //extract fn()
  438. ATTRIBUTE_COLUMN colFromFRSDomain = { ATTR_COLTYPE_SPECIAL,
  439. IDS_COLUMN_FROM_DOMAIN, //column header
  440. 150, //col. width
  441. L"fromServer", //ldap attr. name
  442. ColumnExtractFRSDomain }; //extract fn()
  443. ATTRIBUTE_COLUMN colConnectionName={ ATTR_COLTYPE_SPECIAL,
  444. IDS_COLUMN_NAME, //column header
  445. 150, //col. width
  446. L"options", //ldap attr. name
  447. ColumnExtractConnectionDisplayName}; //extract fn()
  448. ATTRIBUTE_COLUMN colFromServer={ ATTR_COLTYPE_SPECIAL,
  449. IDS_COLUMN_FROM_SERVER, //column header
  450. 100, //col. width
  451. L"fromServer", //ldap attr. name
  452. ColumnExtractParentFromDN }; //extract fn()
  453. ATTRIBUTE_COLUMN colFromSite={ ATTR_COLTYPE_SPECIAL,
  454. IDS_COLUMN_FROM_SITE, //column header
  455. 100, //col. width
  456. L"fromServer", //ldap attr. name
  457. ColumnExtractGreatGrandparentFromDN }; //extract fn()
  458. ATTRIBUTE_COLUMN colCost = { ATTR_COLTYPE_SPECIAL,
  459. IDS_COLUMN_COST, //column header
  460. 75, //col. width
  461. L"cost", //ldap attr. name
  462. ColumnExtractAttribute }; //extract fn()
  463. ATTRIBUTE_COLUMN colReplInterval = { ATTR_COLTYPE_SPECIAL,
  464. IDS_COLUMN_REPLINTERVAL, //column header
  465. 150, //col. width
  466. L"replInterval", //ldap attr. name
  467. ColumnExtractAttribute }; //extract fn()
  468. ATTRIBUTE_COLUMN colNameFromSID={ ATTR_COLTYPE_SPECIAL,
  469. IDS_COLUMN_READABLE_NAME, // column header
  470. 100, // column width
  471. L"container",
  472. ColumnExtractNameFromSID }; // extract fn()
  473. ATTRIBUTE_COLUMN colGenericSpecial={ ATTR_COLTYPE_SPECIAL,
  474. 0, // resource id 0 means load it from the special column array
  475. 50,
  476. NULL,
  477. ColumnExtractAttribute };
  478. ATTRIBUTE_COLUMN colModifiedTime={ ATTR_COLTYPE_MODIFIED_TIME,
  479. 0,
  480. 50,
  481. NULL,
  482. ColumnExtractAttribute };
  483. SPECIAL_COLUMN g_specialCols[] =
  484. {
  485. { IDS_COLUMN_BUSINESS_PHONE, L"telephoneNumber", 100 },
  486. { IDS_COLUMN_CITY, L"l", 150 },
  487. { IDS_COLUMN_COMPANY, L"company", 150 },
  488. { IDS_COLUMN_COUNTRY, L"c", AUTO_WIDTH }, // Default to the width of the header string
  489. { IDS_COLUMN_DEPARTMENT, L"department", 150 },
  490. { IDS_COLUMN_DISPLAY_NAME, L"displayName", 100 },
  491. { IDS_COLUMN_SAM_ACCOUNT_NAME, L"sAMAccountName", 120 },
  492. { IDS_COLUMN_MAIL, L"mail", 100 },
  493. { IDS_COLUMN_ALIAS_NAME, L"mailNickname", 175 },
  494. { IDS_COLUMN_HOME_MDB, L"homeMDB", 100 },
  495. { IDS_COLUMN_FIRST_NAME, L"givenName", 100 },
  496. { IDS_COLUMN_IMHOMEURL, L"msExchIMPhysicalURL", 170 },
  497. { IDS_COLUMN_IMURL, L"msExchIMMetaPhysicalURL", 140 },
  498. { IDS_COLUMN_LAST_NAME, L"sn", 100 },
  499. { IDS_COLUMN_MODIFIED, L"whenChanged", 130 },
  500. { IDS_COLUMN_OFFICE, L"physicalDeliveryOfficeName", 100 },
  501. { IDS_COLUMN_STATE, L"st", 100 },
  502. { IDS_COLUMN_TARGET_ADDRESS , L"targetAddress", 100 },
  503. { IDS_COLUMN_TITLE, L"title", 100 },
  504. { IDS_COLUMN_UPN, L"userPrincipalName", 200 },
  505. { IDS_COLUMN_TEXTENCODEORADDRESS, L"textEncodedORAddress", 130 },
  506. { IDS_COLUMN_ZIP_CODE, L"postalCode", 100 }
  507. };
  508. PATTRIBUTE_COLUMN colsSubnetContainer[6] = { &colName, &colSite, &colLocation, &colClass, &colDesc, NULL };
  509. PATTRIBUTE_COLUMN colsSitesContainer[5] = { &colName, &colLocation, &colClass, &colDesc, NULL };
  510. PATTRIBUTE_COLUMN colsServersContainer[6] = { &colName, &colDomain, &colBridgehead, &colClass, &colDesc, NULL };
  511. PATTRIBUTE_COLUMN colsNTDSDSA[6] = { &colConnectionName, &colFromServer, &colFromSite, &colClass, &colDesc, NULL };
  512. PATTRIBUTE_COLUMN colsInterSiteTransport[6] = { &colName, &colClass, &colDesc, &colCost, &colReplInterval, NULL };
  513. PATTRIBUTE_COLUMN colsFRSReplicaSet[6] = { &colName, &colReplicaComputer, &colReplicaDomain, &colClass, &colDesc, NULL };
  514. PATTRIBUTE_COLUMN colsFRSMember[6] = { &colConnectionName, &colFromFRSComputer, &colFromFRSDomain, &colClass, &colDesc, NULL };
  515. PATTRIBUTE_COLUMN colsFSP[5] = { &colName, &colClass, &colDesc, &colNameFromSID, NULL };
  516. PATTRIBUTE_COLUMN colsDefault[4] = { &colName, &colClass, &colDesc, NULL };
  517. // currently, any additional columns must be of string type
  518. COLUMNS_FOR_CLASS g_colarray[] = {
  519. { _T("subnetContainer"), _T("subnetContainer"), 5, colsSubnetContainer },
  520. { _T("sitesContainer"), _T("sitesContainer"), 4, colsSitesContainer},
  521. { _T("serversContainer"), _T("serversContainer"), 5, colsServersContainer},
  522. { _T("nTDSDSA"), _T("nTDSDSA"), 5, colsNTDSDSA },
  523. { _T("interSiteTransport"), _T("interSiteTransport"), 5, colsInterSiteTransport},
  524. { _T("nTFRSReplicaSet"), _T("nTFRSReplicaSet"), 5, colsFRSReplicaSet },
  525. { _T("nTFRSMember"), _T("nTFRSMember"), 5, colsFRSMember },
  526. { _T("ForeignSecurityPrincipals"), _T("ForeignSecurityPrincipals"), 4, colsFSP },
  527. { NULL, DEFAULT_COLUMN_SET, 3, colsDefault } // empty one at the end; must be here
  528. };
  529. /*
  530. COLUMNS_FOR_CLASS* GetColumnsForClass( LPCTSTR i_pcszLdapClassName )
  531. {
  532. if (NULL == i_pcszLdapClassName)
  533. i_pcszLdapClassName = L"";
  534. COLUMNS_FOR_CLASS* pColsForClass;
  535. for (pColsForClass = g_colarray; NULL != pColsForClass->pcszLdapClassName; pColsForClass++) {
  536. if ( 0 == _wcsicmp(i_pcszLdapClassName, pColsForClass->pcszLdapClassName) ) {
  537. break;
  538. }
  539. }
  540. ASSERT( NULL != pColsForClass );
  541. return pColsForClass;
  542. }
  543. */
  544. ////////////////////////////////////////////////////////////////////////////////////
  545. // CDSColumnSet
  546. CDSColumnSet* CDSColumnSet::CreateColumnSet(PCOLUMNS_FOR_CLASS pColsForClass, SnapinType snapinType)
  547. {
  548. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  549. // Using the class name as both the column id and the class name for the column set
  550. CDSColumnSet* pNewColumnSet = new CDSColumnSet(pColsForClass->pcszColumnID, pColsForClass->pcszLdapClassName);
  551. if (!pNewColumnSet)
  552. {
  553. TRACE(L"Unable to allocate memory for new column set\n");
  554. ASSERT(FALSE);
  555. return 0;
  556. }
  557. UINT nUserColCount = 0;
  558. for (int idx = 0; idx < pColsForClass->nColumns; idx ++)
  559. {
  560. CString cstrHeader;
  561. CDSColumn* pNewColumn;
  562. if (pColsForClass->apColumns[idx]->resid == 0)
  563. {
  564. // Don't add the exchange special columns in DSSite
  565. if (snapinType == SNAPINTYPE_SITE)
  566. continue;
  567. cstrHeader.LoadString(g_specialCols[nUserColCount].resid);
  568. pNewColumn = new CDSColumn((LPCWSTR)cstrHeader,
  569. LVCFMT_LEFT,
  570. g_specialCols[nUserColCount].iColumnWidth,
  571. idx,
  572. FALSE,
  573. g_specialCols[nUserColCount].ptszAttribute,
  574. pColsForClass->apColumns[idx]->coltype,
  575. pColsForClass->apColumns[idx]->pfnExtract);
  576. nUserColCount++;
  577. }
  578. else
  579. {
  580. cstrHeader.LoadString(pColsForClass->apColumns[idx]->resid);
  581. pNewColumn = new CDSColumn((LPCWSTR)cstrHeader,
  582. LVCFMT_LEFT,
  583. pColsForClass->apColumns[idx]->iColumnWidth,
  584. idx,
  585. TRUE,
  586. pColsForClass->apColumns[idx]->pcszAttribute,
  587. pColsForClass->apColumns[idx]->coltype,
  588. pColsForClass->apColumns[idx]->pfnExtract);
  589. }
  590. ASSERT(pNewColumn);
  591. if (pNewColumn)
  592. {
  593. pNewColumnSet->AddColumn(pNewColumn);
  594. }
  595. }
  596. return pNewColumnSet;
  597. }
  598. CDSColumnSet* CDSColumnSet::CreateColumnSetFromString(LPCWSTR lpszClassName, SnapinType snapinType)
  599. {
  600. COLUMNS_FOR_CLASS* pColsForClass;
  601. for (pColsForClass = g_colarray; pColsForClass->pcszLdapClassName != NULL; pColsForClass++)
  602. {
  603. if (lpszClassName != NULL && pColsForClass->pcszLdapClassName != NULL)
  604. {
  605. if (wcscmp(pColsForClass->pcszLdapClassName, lpszClassName) == 0)
  606. {
  607. break;
  608. }
  609. }
  610. }
  611. return CDSColumnSet::CreateColumnSet(pColsForClass, snapinType);
  612. }
  613. CDSColumnSet* CDSColumnSet::CreateDescriptionColumnSet()
  614. {
  615. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  616. CString szNameHeader;
  617. VERIFY(szNameHeader.LoadString(IDS_COLUMN_NAME));
  618. CColumn* pNameColumn = new CColumn(szNameHeader,
  619. LVCFMT_LEFT,
  620. 100,
  621. 0,
  622. TRUE);
  623. if (pNameColumn == NULL)
  624. {
  625. return NULL;
  626. }
  627. CString szDescriptionHeader;
  628. VERIFY(szDescriptionHeader.LoadString(IDS_COLUMN_DESCRIPTION));
  629. CColumn* pDescColumn = new CColumn(szDescriptionHeader,
  630. LVCFMT_LEFT,
  631. 150,
  632. 1,
  633. TRUE);
  634. if (pDescColumn == NULL)
  635. {
  636. return NULL;
  637. }
  638. CDSColumnSet* pDSColumnSet = new CDSColumnSet(L"***---Description Set---***", NULL);
  639. if (pDSColumnSet == NULL)
  640. {
  641. return NULL;
  642. }
  643. pDSColumnSet->AddColumn(pNameColumn);
  644. pDSColumnSet->AddColumn(pDescColumn);
  645. return pDSColumnSet;
  646. }
  647. CDSColumnSet* CDSColumnSet::CreateColumnSetFromDisplaySpecifiers(PCWSTR pszClassName, SnapinType snapinType, MyBasePathsInfo* pBasePathsInfo)
  648. {
  649. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  650. HRESULT hr = S_OK;
  651. CDSColumnSet* pNewColumnSet = NULL;
  652. BOOL bDefaultHardcodedSet = FALSE;
  653. //
  654. // Using the class name as both the column id and the class name for the column set
  655. //
  656. pNewColumnSet = new CDSColumnSet(pszClassName, pszClassName);
  657. if (pNewColumnSet != NULL)
  658. {
  659. //
  660. // Start with the hardcoded columns
  661. //
  662. COLUMNS_FOR_CLASS* pColsForClass;
  663. for (pColsForClass = g_colarray; pColsForClass->pcszLdapClassName != NULL; pColsForClass++)
  664. {
  665. if (pszClassName != NULL && pColsForClass->pcszLdapClassName != NULL)
  666. {
  667. if (wcscmp(pColsForClass->pcszLdapClassName, pszClassName) == 0)
  668. {
  669. break;
  670. }
  671. }
  672. }
  673. if (pColsForClass != NULL)
  674. {
  675. if (wcscmp(pColsForClass->pcszColumnID, DEFAULT_COLUMN_SET) == 0)
  676. {
  677. bDefaultHardcodedSet = TRUE;
  678. }
  679. UINT nUserColCount = 0;
  680. for (int idx = 0; idx < pColsForClass->nColumns; idx ++)
  681. {
  682. CString cstrHeader;
  683. CDSColumn* pNewColumn;
  684. if (pColsForClass->apColumns[idx]->resid == 0)
  685. {
  686. // Don't add the exchange special columns in DSSite
  687. if (snapinType == SNAPINTYPE_SITE)
  688. continue;
  689. cstrHeader.LoadString(g_specialCols[nUserColCount].resid);
  690. pNewColumn = new CDSColumn((LPCWSTR)cstrHeader,
  691. LVCFMT_LEFT,
  692. g_specialCols[nUserColCount].iColumnWidth,
  693. idx,
  694. FALSE,
  695. g_specialCols[nUserColCount].ptszAttribute,
  696. pColsForClass->apColumns[idx]->coltype,
  697. pColsForClass->apColumns[idx]->pfnExtract);
  698. nUserColCount++;
  699. }
  700. else
  701. {
  702. cstrHeader.LoadString(pColsForClass->apColumns[idx]->resid);
  703. pNewColumn = new CDSColumn((LPCWSTR)cstrHeader,
  704. LVCFMT_LEFT,
  705. pColsForClass->apColumns[idx]->iColumnWidth,
  706. idx,
  707. TRUE,
  708. pColsForClass->apColumns[idx]->pcszAttribute,
  709. pColsForClass->apColumns[idx]->coltype,
  710. pColsForClass->apColumns[idx]->pfnExtract);
  711. }
  712. pNewColumnSet->AddColumn(pNewColumn);
  713. }
  714. }
  715. //
  716. // Now add the DS extraColumns
  717. //
  718. CStringList strListColumns;
  719. hr = GetDisplaySpecifierProperty(pszClassName, L"extraColumns", pBasePathsInfo, strListColumns);
  720. if (FAILED(hr))
  721. {
  722. hr = GetDisplaySpecifierProperty(pszClassName, L"extraColumns", pBasePathsInfo, strListColumns, true);
  723. }
  724. if (SUCCEEDED(hr))
  725. {
  726. UINT nColCount = static_cast<UINT>(pNewColumnSet->GetCount());
  727. POSITION pos = strListColumns.GetHeadPosition();
  728. while (pos != NULL)
  729. {
  730. CDSColumn* pNewColumn = NULL;
  731. CString szExtraColumn = strListColumns.GetNext(pos);
  732. if (!szExtraColumn.IsEmpty())
  733. {
  734. //
  735. // Parse the 5-tuple to get the elements to make the column
  736. //
  737. CString szAttributeName;
  738. CString szColHeader;
  739. BOOL bVisible = TRUE;
  740. int iColumnWidth = 0;
  741. GUID guidCallbackInterface; // unused. Reserved for future callback interface
  742. PWSTR pszTemp = new WCHAR[szExtraColumn.GetLength() + 1];
  743. if (pszTemp != NULL)
  744. {
  745. wcscpy(pszTemp, (LPCWSTR)szExtraColumn);
  746. PWSTR pszVisible = NULL;
  747. PWSTR pszColumnWidth = NULL;
  748. PWSTR pszGuidCallback = NULL;
  749. PWSTR pszNextTuple = pszTemp;
  750. pszNextTuple = wcstok(pszTemp, L",");
  751. if (pszNextTuple != NULL)
  752. {
  753. szAttributeName = pszNextTuple;
  754. }
  755. pszNextTuple = wcstok(NULL, L",");
  756. if (pszNextTuple != NULL)
  757. {
  758. szColHeader = pszNextTuple;
  759. }
  760. pszNextTuple = wcstok(NULL, L",");
  761. if (pszNextTuple != NULL)
  762. {
  763. pszVisible = pszNextTuple;
  764. int i = _wtoi(pszVisible);
  765. if (i == 0)
  766. {
  767. bVisible = FALSE;
  768. }
  769. else
  770. {
  771. bVisible = TRUE;
  772. }
  773. }
  774. pszNextTuple = wcstok(NULL, L",");
  775. if (pszNextTuple != NULL)
  776. {
  777. pszColumnWidth = pszNextTuple;
  778. iColumnWidth = _wtoi(pszColumnWidth);
  779. }
  780. pszNextTuple = wcstok(NULL, L",");
  781. if (pszNextTuple != NULL)
  782. {
  783. pszGuidCallback = pszNextTuple;
  784. HRESULT hr2 = ::CLSIDFromString(pszGuidCallback, &guidCallbackInterface);
  785. if (FAILED(hr2))
  786. {
  787. memset(&guidCallbackInterface, 0, sizeof(GUID));
  788. }
  789. }
  790. //
  791. // Create the column with the retrieved data
  792. //
  793. pNewColumn = new CDSColumn((PCWSTR)szColHeader,
  794. LVCFMT_LEFT,
  795. iColumnWidth,
  796. nColCount++,
  797. bVisible,
  798. (PCWSTR)szAttributeName,
  799. ATTR_COLTYPE_SPECIAL,
  800. ColumnExtractAttribute); // this will be changed to the interface when that is implemented
  801. }
  802. delete[] pszTemp;
  803. }
  804. if (pNewColumn != NULL)
  805. {
  806. pNewColumnSet->AddColumn(pNewColumn);
  807. }
  808. }
  809. }
  810. }
  811. //
  812. // If we failed to retrieve columns from the display specifier
  813. // and we hit the default hardcoded set but we were not asking
  814. // for the default hardcoded set and the snapin isn't the sites snapin
  815. // Then we delete the column set and we will pickup the actual default
  816. // column set since we are returning NULL
  817. //
  818. if (FAILED(hr) &&
  819. bDefaultHardcodedSet &&
  820. _wcsicmp(pszClassName, DEFAULT_COLUMN_SET) != 0 &&
  821. snapinType != SNAPINTYPE_SITE)
  822. {
  823. delete pNewColumnSet;
  824. pNewColumnSet = NULL;
  825. }
  826. return pNewColumnSet;
  827. }
  828. HRESULT CColumnSet::Save(IStream* pStm)
  829. {
  830. // save the column set ID
  831. HRESULT hr = SaveStringHelper(GetColumnID(), pStm);
  832. if (FAILED(hr))
  833. return hr;
  834. // save the # of visible columns and
  835. // the indexes of the visible columns
  836. // NOTICE: we use MMC's MMC_VISIBLE_COLUMNS format to be consitent
  837. // and to be able to read back easily
  838. INT nTotalCols = GetNumCols();
  839. // allocate a bit more than needed (i.e. total # of columns)
  840. MMC_VISIBLE_COLUMNS* pVisibleColumns =
  841. (MMC_VISIBLE_COLUMNS*)new BYTE[sizeof(MMC_VISIBLE_COLUMNS) + (sizeof(INT)*(nTotalCols-1))];
  842. if (!pVisibleColumns)
  843. {
  844. return E_OUTOFMEMORY;
  845. }
  846. pVisibleColumns->nVisibleColumns = 0;
  847. int iIndex = 0;
  848. for (POSITION pos = GetHeadPosition(); (pos != NULL); )
  849. {
  850. CColumn* pCol = GetNext(pos);
  851. if (pCol->IsVisible())
  852. {
  853. pVisibleColumns->rgVisibleCols[pVisibleColumns->nVisibleColumns] = iIndex;
  854. (pVisibleColumns->nVisibleColumns)++;
  855. }
  856. iIndex++;
  857. }
  858. // save the right length of the struct
  859. ULONG nByteCount = sizeof(MMC_VISIBLE_COLUMNS) + (sizeof(INT)*(pVisibleColumns->nVisibleColumns-1));
  860. ULONG nBytesWritten;
  861. hr = pStm->Write((void*)pVisibleColumns, nByteCount, &nBytesWritten);
  862. if (SUCCEEDED(hr))
  863. {
  864. if (nBytesWritten < nByteCount)
  865. {
  866. hr = STG_E_CANTSAVE;
  867. }
  868. }
  869. delete[] pVisibleColumns;
  870. pVisibleColumns = 0;
  871. return hr;
  872. }
  873. HRESULT CColumnSet::Load(IStream* pStm)
  874. {
  875. // NOTICE: we already loaded the column set ID and
  876. // got a columns set that matches this
  877. // read the # of visible columns
  878. DWORD dwColCount = 0;
  879. INT nCountMax = GetNumCols();
  880. HRESULT hr = LoadDWordHelper(pStm, &dwColCount);
  881. if (FAILED(hr) || ((INT)dwColCount > nCountMax))
  882. return E_FAIL;
  883. // allocate some space for the array past the struct
  884. MMC_VISIBLE_COLUMNS* pVisibleColumns =
  885. (MMC_VISIBLE_COLUMNS*)new BYTE[sizeof(MMC_VISIBLE_COLUMNS) + (sizeof(INT)*(dwColCount-1))];
  886. if (!pVisibleColumns)
  887. {
  888. return E_OUTOFMEMORY;
  889. }
  890. pVisibleColumns->nVisibleColumns = (INT)dwColCount;
  891. // load the array of indexes of visible columns
  892. ULONG nBytesRead;
  893. ULONG nByteCount = sizeof(DWORD)*dwColCount;
  894. INT* pArr = pVisibleColumns->rgVisibleCols;
  895. hr = pStm->Read(pArr, nByteCount, &nBytesRead);
  896. if (SUCCEEDED(hr))
  897. {
  898. if (nBytesRead < nByteCount)
  899. {
  900. hr = E_FAIL;
  901. }
  902. else
  903. {
  904. // update columns
  905. AddVisibleColumns(pVisibleColumns);
  906. }
  907. }
  908. delete[] pVisibleColumns;
  909. pVisibleColumns = 0;
  910. return S_OK;
  911. }
  912. /////////////////////////////////////////////////////////////////////////////////////////
  913. // CColumnSetList
  914. void CColumnSetList::Initialize(SnapinType snapinType,
  915. MyBasePathsInfo* pBasePathsInfo)
  916. {
  917. m_pBasePathsInfo = pBasePathsInfo;
  918. m_snapinType = snapinType;
  919. }
  920. //
  921. // Find the column set given a column set ID
  922. //
  923. CColumnSet* CColumnSetList::FindColumnSet(LPCWSTR lpszColumnID)
  924. {
  925. POSITION pos = GetHeadPosition();
  926. while (pos != NULL)
  927. {
  928. CColumnSet* pTempSet = GetNext(pos);
  929. ASSERT(pTempSet != NULL);
  930. LPCWSTR lpszTempNodeID = pTempSet->GetColumnID();
  931. if (wcscmp(lpszTempNodeID, lpszColumnID) == 0)
  932. {
  933. return pTempSet;
  934. }
  935. }
  936. CColumnSet* pNewColSet = CDSColumnSet::CreateColumnSetFromDisplaySpecifiers(lpszColumnID,
  937. m_snapinType,
  938. m_pBasePathsInfo);
  939. if (pNewColSet != NULL)
  940. {
  941. AddTail(pNewColSet);
  942. return pNewColSet;
  943. }
  944. return GetDefaultColumnSet();
  945. }
  946. CColumnSet* CColumnSetList::GetDefaultColumnSet()
  947. {
  948. if (m_pDefaultColumnSet == NULL)
  949. {
  950. m_pDefaultColumnSet = CDSColumnSet::CreateColumnSetFromDisplaySpecifiers(DEFAULT_COLUMN_SET,
  951. m_snapinType,
  952. m_pBasePathsInfo);
  953. }
  954. return m_pDefaultColumnSet;
  955. }
  956. HRESULT CColumnSetList::Save(IStream* pStm)
  957. {
  958. // save # of items in the list
  959. DWORD dwCount = (DWORD)GetCount(); // list count plus default column set
  960. if (m_pDefaultColumnSet)
  961. {
  962. dwCount++;
  963. }
  964. HRESULT hr = SaveDWordHelper(pStm, dwCount);
  965. if (FAILED(hr))
  966. return hr;
  967. // save columnset list
  968. for (POSITION pos = GetHeadPosition(); pos != NULL; )
  969. {
  970. CColumnSet* pTempSet = GetNext(pos);
  971. if (pTempSet == NULL)
  972. {
  973. ASSERT(pTempSet != NULL);
  974. continue;
  975. }
  976. hr = pTempSet->Save(pStm);
  977. if (FAILED(hr))
  978. return hr;
  979. }
  980. // save default column set
  981. if (m_pDefaultColumnSet != NULL)
  982. {
  983. hr = m_pDefaultColumnSet->Save(pStm);
  984. }
  985. return hr;
  986. }
  987. HRESULT CColumnSetList::Load(IStream* pStm)
  988. {
  989. // load # of items in the list
  990. DWORD dwLoadCount;
  991. HRESULT hr = LoadDWordHelper(pStm, &dwLoadCount);
  992. if (FAILED(hr))
  993. return hr;
  994. // load column list
  995. CString szColumnID;
  996. for (DWORD iColSet = 0; iColSet< dwLoadCount; iColSet++)
  997. {
  998. // load the string with the name of the column set
  999. hr = LoadStringHelper(szColumnID, pStm);
  1000. if (FAILED(hr))
  1001. return hr;
  1002. ASSERT(!szColumnID.IsEmpty());
  1003. CColumnSet* pColumnSet = FindColumnSet(szColumnID);
  1004. if (pColumnSet != NULL)
  1005. {
  1006. hr = pColumnSet->Load(pStm);
  1007. if (FAILED(hr))
  1008. return hr;
  1009. }
  1010. }
  1011. return S_OK;
  1012. }