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.

585 lines
17 KiB

  1. #include "pch.h"
  2. #include "stddef.h"
  3. #pragma hdrstop
  4. /*----------------------------------------------------------------------------
  5. / MergeMenu
  6. / ---------
  7. / Merge two menus together, taking the first popup menu and merging it into
  8. / the target. We use the caption from the pop-up menu as the caption
  9. / for the target.
  10. /
  11. / In:
  12. / hMenu = handle of menu to merge into
  13. / hMenuToInsert = handle of menu to get the popup from
  14. / iIndex = index to insert at
  15. /
  16. / Out:
  17. / -
  18. /----------------------------------------------------------------------------*/
  19. VOID MergeMenu(HMENU hMenu, HMENU hMenuToInsert, INT iIndex)
  20. {
  21. TCHAR szBuffer[MAX_PATH];
  22. HMENU hPopupMenu = NULL;
  23. TraceEnter(TRACE_HANDLER|TRACE_VIEW, "MergeMenu");
  24. hPopupMenu = CreatePopupMenu();
  25. if ( hPopupMenu )
  26. {
  27. GetMenuString(hMenuToInsert, 0, szBuffer, ARRAYSIZE(szBuffer), MF_BYPOSITION);
  28. InsertMenu(hMenu, iIndex, MF_BYPOSITION|MF_POPUP, (UINT_PTR)hPopupMenu, szBuffer);
  29. Shell_MergeMenus(hPopupMenu, GetSubMenu(hMenuToInsert, 0), 0x0, 0x0, 0x7fff, 0);
  30. }
  31. TraceLeave();
  32. }
  33. /*-----------------------------------------------------------------------------
  34. / GetColumnHandlerFromProperty
  35. / ----------------------------
  36. / Given a COLUMN structure allocate the property name appending the
  37. / CLSID of the handler if we have one.
  38. /
  39. / In:
  40. / pColumn -> column value to decode
  41. / pProperty -> property value parse
  42. /
  43. / Out:
  44. / HRESULT
  45. /----------------------------------------------------------------------------*/
  46. HRESULT GetColumnHandlerFromProperty(LPCOLUMN pColumn, LPWSTR pProperty)
  47. {
  48. HRESULT hres;
  49. LPWSTR pPropertyTemp;
  50. LPWSTR pColumnHandlerCLSID;
  51. TraceEnter(TRACE_VIEW, "GetColumnHandlerFromProperty");
  52. Trace(TEXT("pProperty is: %s"), pProperty);
  53. if ( !pProperty )
  54. pProperty = pColumn->pProperty;
  55. // if we find a ',' then we must parse the GUID as it may be a CLSID for a column handler.
  56. pColumnHandlerCLSID = wcschr(pProperty, L',');
  57. if ( pColumnHandlerCLSID )
  58. {
  59. // attempt to extract the CLSID form the property name
  60. *pColumnHandlerCLSID++ = L'\0'; // terminate the property name
  61. if ( GetGUIDFromString(pColumnHandlerCLSID, &pColumn->clsidColumnHandler) )
  62. {
  63. TraceGUID("CLSID for handler is:", pColumn->clsidColumnHandler);
  64. pColumn->fHasColumnHandler = TRUE;
  65. }
  66. else
  67. {
  68. TraceMsg("**** Failed to parse CLSID from property name ****");
  69. }
  70. // we truncated the string, so lets re-alloc the buffer with the
  71. // new string value.
  72. if ( SUCCEEDED(LocalAllocStringW(&pPropertyTemp, pProperty)) )
  73. {
  74. LocalFreeStringW(&pColumn->pProperty);
  75. pColumn->pProperty = pPropertyTemp;
  76. }
  77. Trace(TEXT("Property name is now: %s"), pColumn->pProperty);
  78. }
  79. else
  80. {
  81. // now CLSID, so just allocate the property string if we need to.
  82. if ( pColumn->pProperty != pProperty )
  83. {
  84. if ( SUCCEEDED(LocalAllocStringW(&pPropertyTemp, pProperty)) )
  85. {
  86. LocalFreeStringW(&pColumn->pProperty);
  87. pColumn->pProperty = pPropertyTemp;
  88. }
  89. }
  90. }
  91. TraceLeaveResult(S_OK);
  92. }
  93. /*-----------------------------------------------------------------------------
  94. / GetPropertyFromColumn
  95. / ---------------------
  96. / Given a COLUMN structure allocate the property name appending the
  97. / CLSID of the handler if we have one.
  98. /
  99. / In:
  100. / ppProperty -> receives a pointer to the property string
  101. / pColumn -> column value to decode
  102. /
  103. / Out:
  104. / HRESULT
  105. /----------------------------------------------------------------------------*/
  106. HRESULT GetPropertyFromColumn(LPWSTR* ppProperty, LPCOLUMN pColumn)
  107. {
  108. HRESULT hres;
  109. TCHAR szGUID[GUIDSTR_MAX+1];
  110. TraceEnter(TRACE_VIEW, "GetPropertyFromColumn");
  111. if ( !pColumn->fHasColumnHandler )
  112. {
  113. hres = LocalAllocStringW(ppProperty, pColumn->pProperty);
  114. FailGracefully(hres, "Failed to allocate property");
  115. }
  116. else
  117. {
  118. int cchProperty = lstrlenW(pColumn->pProperty)+ GUIDSTR_MAX + 1; // 1 for seperator
  119. hres = LocalAllocStringLenW(ppProperty, cchProperty);
  120. FailGracefully(hres, "Failed to allocate buffer for property + GUID");
  121. GetStringFromGUID(pColumn->clsidColumnHandler, szGUID, ARRAYSIZE(szGUID));
  122. wnsprintf(*ppProperty, cchProperty, TEXT("%s,%s"), pColumn->pProperty, szGUID);
  123. }
  124. hres = S_OK;
  125. exit_gracefully:
  126. TraceLeaveResult(hres);
  127. }
  128. /*-----------------------------------------------------------------------------
  129. / FreeColumn / FreeColumnValue
  130. / ----------------------------
  131. / A column consists of the header and filter information including the underlying
  132. / property value.
  133. /
  134. / A COLUMNVALUE is the typed information for the column which must be freed
  135. / based the iPropertyType value.
  136. /
  137. / In:
  138. / pColumn -> LPCOLUMN structure to released
  139. / or
  140. / pColumnValue ->LPCOLUMNVALUE structure to be released
  141. /
  142. / Out:
  143. / -
  144. /----------------------------------------------------------------------------*/
  145. VOID FreeColumnValue(LPCOLUMNVALUE pColumnValue)
  146. {
  147. TraceEnter(TRACE_VIEW, "FreeColumnValue");
  148. switch ( pColumnValue->iPropertyType )
  149. {
  150. case PROPERTY_ISUNDEFINED:
  151. case PROPERTY_ISBOOL:
  152. case PROPERTY_ISNUMBER:
  153. break;
  154. case PROPERTY_ISUNKNOWN:
  155. case PROPERTY_ISSTRING:
  156. case PROPERTY_ISDNSTRING:
  157. LocalFreeString(&pColumnValue->pszText);
  158. break;
  159. default:
  160. Trace(TEXT("iPropertyValue is %d"), pColumnValue->iPropertyType);
  161. TraceAssert(FALSE);
  162. break;
  163. }
  164. pColumnValue->iPropertyType = PROPERTY_ISUNDEFINED; // no value
  165. TraceLeave();
  166. }
  167. INT FreeColumnCB(LPVOID pItem, LPVOID pData)
  168. {
  169. FreeColumn((LPCOLUMN)pItem);
  170. return 1;
  171. }
  172. VOID FreeColumn(LPCOLUMN pColumn)
  173. {
  174. TraceEnter(TRACE_VIEW, "FreeQueryResult");
  175. if ( pColumn )
  176. {
  177. LocalFreeStringW(&pColumn->pProperty);
  178. LocalFreeString(&pColumn->pHeading);
  179. FreeColumnValue(&pColumn->filter);
  180. DoRelease(pColumn->pColumnHandler);
  181. }
  182. TraceLeave();
  183. }
  184. /*-----------------------------------------------------------------------------
  185. / FreeQueryResult
  186. / ---------------
  187. / Given a QUERYRESULT structure free the elements within it
  188. /
  189. / In:
  190. / pResult -> result blob to be released
  191. / cColumns = number of columns to be released
  192. /
  193. / Out:
  194. / -
  195. /----------------------------------------------------------------------------*/
  196. INT FreeQueryResultCB(LPVOID pItem, LPVOID pData)
  197. {
  198. FreeQueryResult((LPQUERYRESULT)pItem, PtrToUlong(pData));
  199. return 1;
  200. }
  201. VOID FreeQueryResult(LPQUERYRESULT pResult, INT cColumns)
  202. {
  203. INT i;
  204. TraceEnter(TRACE_VIEW, "FreeQueryResult");
  205. if ( pResult )
  206. {
  207. LocalFreeStringW(&pResult->pObjectClass);
  208. LocalFreeStringW(&pResult->pPath);
  209. for ( i = 0 ; i < cColumns ; i++ )
  210. FreeColumnValue(&pResult->aColumn[i]);
  211. }
  212. TraceLeave();
  213. }
  214. /*-----------------------------------------------------------------------------
  215. / PropertyIsFromAttribute
  216. / -----------------------
  217. / Get the property is value from the specified attribute.
  218. /
  219. / In:
  220. / pszAttributeName -> attribute name
  221. / pdds -> IDsDisplaySpecifier
  222. /
  223. / Out:
  224. / DWORD dwType
  225. /----------------------------------------------------------------------------*/
  226. DWORD PropertyIsFromAttribute(LPCWSTR pszAttributeName, IDsDisplaySpecifier *pdds)
  227. {
  228. DWORD dwResult = PROPERTY_ISUNKNOWN;
  229. TraceEnter(TRACE_CORE, "PropertyIsFromAttribute");
  230. Trace(TEXT("Fetching attribute type for: %s"), pszAttributeName);
  231. switch ( pdds->GetAttributeADsType(pszAttributeName) )
  232. {
  233. case ADSTYPE_DN_STRING:
  234. TraceMsg("Property is a DN string");
  235. dwResult = PROPERTY_ISDNSTRING;
  236. break;
  237. case ADSTYPE_CASE_EXACT_STRING:
  238. case ADSTYPE_CASE_IGNORE_STRING:
  239. case ADSTYPE_PRINTABLE_STRING:
  240. case ADSTYPE_NUMERIC_STRING:
  241. TraceMsg("Property is a string");
  242. dwResult = PROPERTY_ISSTRING;
  243. break;
  244. case ADSTYPE_BOOLEAN:
  245. TraceMsg("Property is a BOOL");
  246. dwResult = PROPERTY_ISBOOL;
  247. break;
  248. case ADSTYPE_INTEGER:
  249. TraceMsg("Property is a number");
  250. dwResult = PROPERTY_ISNUMBER;
  251. break;
  252. default:
  253. TraceMsg("Property is UNKNOWN");
  254. break;
  255. }
  256. TraceLeaveValue(dwResult);
  257. }
  258. /*-----------------------------------------------------------------------------
  259. / MatchPattern
  260. / ------------
  261. / Given two strings, one a string the other a pattern match the two
  262. / using standard wildcarding "*" == any number of characters, "?" means
  263. / single character skip
  264. /
  265. / In:
  266. / pString = string to compare
  267. / pPattern = pattern to compare against
  268. /
  269. / Out:
  270. / HRESULT
  271. /----------------------------------------------------------------------------*/
  272. BOOL MatchPattern(LPTSTR pString, LPTSTR pPattern)
  273. {
  274. TCHAR c, p, l;
  275. for ( ;; )
  276. {
  277. switch (p = *pPattern++ )
  278. {
  279. case 0: // end of pattern
  280. return *pString ? FALSE : TRUE; // if end of pString TRUE
  281. case TEXT('*'):
  282. {
  283. while ( *pString )
  284. { // match zero or more char
  285. if ( MatchPattern(pString++, pPattern) )
  286. return TRUE;
  287. }
  288. return MatchPattern(pString, pPattern);
  289. }
  290. case TEXT('?'):
  291. {
  292. if (*pString++ == 0) // match any one char
  293. return FALSE; // not end of pString
  294. break;
  295. }
  296. default:
  297. {
  298. if ( *pString++ != p )
  299. return FALSE; // not a match
  300. break;
  301. }
  302. }
  303. }
  304. }
  305. /*-----------------------------------------------------------------------------
  306. / EnumClassAttrbutes
  307. / ------------------
  308. / This is a wrapper around the attribute enum functions exposed in
  309. / the IDsDisplaySpecifier interface.
  310. /
  311. / We read the attributes into a DPA, then sort them add in the
  312. / extra columns exposed from this UI.
  313. /
  314. / In:
  315. / pdds -> IDsDisplaySpecifier object
  316. / pszObjectClass = object class to enumerate
  317. / pcbEnum, lParam = enumeration callback
  318. /
  319. / Out:
  320. / HRESULT
  321. /----------------------------------------------------------------------------*/
  322. typedef struct
  323. {
  324. LPWSTR pszName;
  325. LPWSTR pszDisplayName;
  326. DWORD dwFlags;
  327. } CLASSATTRIBUTE, * LPCLASSATTRIBUTE;
  328. INT _FreeAttribute(LPCLASSATTRIBUTE pca)
  329. {
  330. LocalFreeStringW(&pca->pszName);
  331. LocalFreeStringW(&pca->pszDisplayName);
  332. LocalFree(pca);
  333. return 1;
  334. }
  335. INT _FreeAttributeCB(LPVOID pv1, LPVOID pv2)
  336. {
  337. return _FreeAttribute((LPCLASSATTRIBUTE)pv1);
  338. }
  339. HRESULT _AddAttribute(HDPA hdpa, LPCWSTR pszName, LPCWSTR pszDisplayName, DWORD dwFlags)
  340. {
  341. HRESULT hres;
  342. LPCLASSATTRIBUTE pca = NULL;
  343. TraceEnter(TRACE_CORE, "_AddAttribute");
  344. Trace(TEXT("Adding %s (%s)"), pszDisplayName, pszName);
  345. pca = (LPCLASSATTRIBUTE)LocalAlloc(LPTR, SIZEOF(CLASSATTRIBUTE));
  346. if ( !pca )
  347. ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate CLASSATTRIBUTE");
  348. // pca->pszName = NULL;
  349. // pca->pszDisplayName = NULL;
  350. pca->dwFlags = dwFlags;
  351. hres = LocalAllocStringW(&pca->pszName, pszName);
  352. FailGracefully(hres, "Failed to copy the name");
  353. hres = LocalAllocStringW(&pca->pszDisplayName, pszDisplayName);
  354. FailGracefully(hres, "Failed to copy the name");
  355. if ( -1 == DPA_AppendPtr(hdpa, pca) )
  356. ExitGracefully(hres, E_OUTOFMEMORY, "Failed to append the record to the DPA");
  357. hres = S_OK;
  358. exit_gracefully:
  359. if ( FAILED(hres) && pca )
  360. _FreeAttribute(pca);
  361. TraceLeaveResult(hres);
  362. }
  363. HRESULT _AddAttributeCB(LPARAM lParam, LPCWSTR pszName, LPCWSTR pszDisplayName, DWORD dwFlags)
  364. {
  365. return _AddAttribute((HDPA)lParam, pszName, pszDisplayName, dwFlags);
  366. }
  367. INT _CompareAttributeCB(LPVOID pv1, LPVOID pv2, LPARAM lParam)
  368. {
  369. LPCLASSATTRIBUTE pca1 = (LPCLASSATTRIBUTE)pv1;
  370. LPCLASSATTRIBUTE pca2 = (LPCLASSATTRIBUTE)pv2;
  371. return StrCmpIW(pca1->pszDisplayName, pca2->pszDisplayName);
  372. }
  373. // NTRAID#NTBUG9-627857-2002/05/24-artm
  374. // Add includeDNStrings parm to control if attributes of
  375. // type ADSTYPE_DN_STRING are included in enumerated attributes.
  376. HRESULT EnumClassAttributes(
  377. IDsDisplaySpecifier *pdds,
  378. LPCWSTR pszObjectClass,
  379. LPDSENUMATTRIBUTES pcbEnum,
  380. LPARAM lParam)
  381. {
  382. HRESULT hres;
  383. HDPA hdpaAttributes = NULL;
  384. WCHAR szBuffer[MAX_PATH];
  385. INT i;
  386. TraceEnter(TRACE_CORE, "EnumClassAttributes");
  387. hdpaAttributes = DPA_Create(16);
  388. if ( !hdpaAttributes )
  389. ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate the DPA");
  390. //
  391. // add the stock properties for objectClass and ADsPath
  392. //
  393. LoadStringW(GLOBAL_HINSTANCE, IDS_OBJECTCLASS, szBuffer, ARRAYSIZE(szBuffer));
  394. hres = _AddAttribute(hdpaAttributes, c_szObjectClassCH, szBuffer, DSECAF_NOTLISTED);
  395. FailGracefully(hres, "Failed to add the ObjectClass default property");
  396. LoadStringW(GLOBAL_HINSTANCE, IDS_ADSPATH, szBuffer, ARRAYSIZE(szBuffer));
  397. hres = _AddAttribute(hdpaAttributes, c_szADsPathCH, szBuffer, DSECAF_NOTLISTED);
  398. FailGracefully(hres, "Failed to add the ObjectClass default property");
  399. //
  400. // now call the IDsDisplaySpecifier object to enumerate the properites correctly
  401. //
  402. TraceMsg("Calling IDsDisplaySpecifier::EnumClassAttributes");
  403. hres = pdds->EnumClassAttributes(pszObjectClass, _AddAttributeCB, (LPARAM)hdpaAttributes);
  404. FailGracefully(hres, "Failed to add the attributes");
  405. //
  406. // now sort and return them all to the caller via their callback funtion
  407. //
  408. Trace(TEXT("Sorting %d attributes, to return to the caller"), DPA_GetPtrCount(hdpaAttributes));
  409. DPA_Sort(hdpaAttributes, _CompareAttributeCB, NULL);
  410. for ( i = 0 ; i < DPA_GetPtrCount(hdpaAttributes) ; i++ )
  411. {
  412. LPCLASSATTRIBUTE pca = (LPCLASSATTRIBUTE)DPA_FastGetPtr(hdpaAttributes, i);
  413. TraceAssert(pca);
  414. hres = pcbEnum(lParam, pca->pszName, pca->pszDisplayName, pca->dwFlags);
  415. FailGracefully(hres, "Failed in cb to original caller");
  416. }
  417. hres = S_OK;
  418. exit_gracefully:
  419. if ( hdpaAttributes )
  420. DPA_DestroyCallback(hdpaAttributes, _FreeAttributeCB, NULL);
  421. TraceLeaveResult(hres);
  422. }
  423. /*-----------------------------------------------------------------------------
  424. / GetFriendlyAttributeName
  425. / ------------------------
  426. / Trim the column handler information if needed, and call the
  427. / friendly attribute name functions.
  428. /
  429. / In:
  430. / pdds -> IDsDisplaySpecifier object
  431. / pszObjectClass, pszAttributeName => attribute info to look up
  432. / pszBuffer, chh => return buffer
  433. /
  434. / Out:
  435. / HRESULT
  436. /----------------------------------------------------------------------------*/
  437. HRESULT GetFriendlyAttributeName(IDsDisplaySpecifier *pdds, LPCWSTR pszObjectClass, LPCWSTR pszAttributeName, LPWSTR pszBuffer, UINT cch)
  438. {
  439. HRESULT hres = S_OK;
  440. WCHAR szAttributeName[MAX_PATH];
  441. TraceEnter(TRACE_CORE, "GetFriendlyAttributeName");
  442. //
  443. // trim off the attribute suffix if we have one (eg: the GUID for the column handler)
  444. //
  445. if ( wcschr(pszAttributeName, L',') )
  446. {
  447. TraceMsg("Has column handler information");
  448. StrCpyNW(szAttributeName, pszAttributeName, ARRAYSIZE(szAttributeName));
  449. LPWSTR pszSeperator = wcschr(szAttributeName, L',');
  450. if (pszSeperator)
  451. *pszSeperator = L'\0';
  452. pszAttributeName = szAttributeName;
  453. }
  454. //
  455. // pick off some special cases before passing onto the COM object to process
  456. //
  457. Trace(TEXT("Looking up name for: %s"), pszAttributeName);
  458. if ( !StrCmpIW(pszAttributeName, c_szADsPath) )
  459. {
  460. LoadStringW(GLOBAL_HINSTANCE, IDS_ADSPATH, pszBuffer, cch);
  461. }
  462. else if ( !StrCmpIW(pszAttributeName, c_szObjectClass) )
  463. {
  464. LoadStringW(GLOBAL_HINSTANCE, IDS_OBJECTCLASS, pszBuffer, cch);
  465. }
  466. else
  467. {
  468. hres = pdds->GetFriendlyAttributeName(pszObjectClass, pszAttributeName, pszBuffer, cch);
  469. }
  470. TraceLeaveResult(hres);
  471. }