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.

2009 lines
63 KiB

  1. #include "pch.h"
  2. #pragma hdrstop
  3. /*-----------------------------------------------------------------------------
  4. / Local functions / data
  5. /----------------------------------------------------------------------------*/
  6. #define CCLV_CHECKED 0x00002000
  7. #define CCLV_UNCHECKED 0x00001000
  8. #define DLU_EDGE 6
  9. #define DLU_SEPERATOR 2
  10. #define DLU_FIXEDELEMENT 80
  11. #define CLID_OTHER 1 // other...
  12. #define CLID_FIRST 2
  13. static TCHAR c_szItems[] = TEXT("Items");
  14. static TCHAR c_szObjectClassN[] = TEXT("ObjectClass%d");
  15. static TCHAR c_szProperty[] = TEXT("Property%d");
  16. static TCHAR c_szCondition[] = TEXT("Condition%d");
  17. static TCHAR c_szValue[] = TEXT("Value%d");
  18. static COLUMNINFO columns[] =
  19. {
  20. 0, 0, IDS_CN, 0, c_szName,
  21. 0, 0, IDS_OBJECTCLASS, DSCOLUMNPROP_OBJECTCLASS, NULL,
  22. 0, DEFAULT_WIDTH_DESCRIPTION, IDS_DESCRIPTION, 0, c_szDescription,
  23. };
  24. static struct
  25. {
  26. DWORD dwPropertyType;
  27. BOOL fNoValue;
  28. INT iFilter;
  29. INT idsFilter;
  30. }
  31. conditions[] =
  32. {
  33. PROPERTY_ISUNKNOWN, 0, FILTER_IS, IDS_IS,
  34. PROPERTY_ISUNKNOWN, 0, FILTER_ISNOT, IDS_ISNOT,
  35. PROPERTY_ISUNKNOWN, 1, FILTER_DEFINED, IDS_DEFINED,
  36. PROPERTY_ISUNKNOWN, 1, FILTER_UNDEFINED, IDS_NOTDEFINED,
  37. PROPERTY_ISSTRING, 0, FILTER_STARTSWITH, IDS_STARTSWITH,
  38. PROPERTY_ISSTRING, 0, FILTER_ENDSWITH, IDS_ENDSWITH,
  39. PROPERTY_ISSTRING, 0, FILTER_IS, IDS_IS,
  40. PROPERTY_ISSTRING, 0, FILTER_ISNOT, IDS_ISNOT,
  41. PROPERTY_ISSTRING, 1, FILTER_DEFINED, IDS_DEFINED,
  42. PROPERTY_ISSTRING, 1, FILTER_UNDEFINED, IDS_NOTDEFINED,
  43. PROPERTY_ISNUMBER, 0, FILTER_LESSEQUAL, IDS_LESSTHAN,
  44. PROPERTY_ISNUMBER, 0, FILTER_GREATEREQUAL, IDS_GREATERTHAN,
  45. PROPERTY_ISNUMBER, 0, FILTER_IS, IDS_IS,
  46. PROPERTY_ISNUMBER, 0, FILTER_ISNOT, IDS_ISNOT,
  47. PROPERTY_ISNUMBER, 1, FILTER_DEFINED, IDS_DEFINED,
  48. PROPERTY_ISNUMBER, 1, FILTER_UNDEFINED, IDS_NOTDEFINED,
  49. PROPERTY_ISBOOL, 1, FILTER_ISTRUE, IDS_ISTRUE,
  50. PROPERTY_ISBOOL, 1, FILTER_ISFALSE, IDS_ISFALSE,
  51. PROPERTY_ISBOOL, 1, FILTER_DEFINED, IDS_DEFINED,
  52. PROPERTY_ISBOOL, 1, FILTER_UNDEFINED, IDS_NOTDEFINED,
  53. };
  54. static struct
  55. {
  56. INT cx;
  57. INT fmt;
  58. }
  59. view_columns[] =
  60. {
  61. 128, LVCFMT_LEFT,
  62. 128, LVCFMT_LEFT,
  63. 128, LVCFMT_LEFT,
  64. };
  65. // Class list used for building the property chooser menu
  66. typedef struct
  67. {
  68. LPWSTR pName;
  69. LPTSTR pDisplayName;
  70. INT cReferences;
  71. } CLASSENTRY, * LPCLASSENTRY;
  72. // State maintained by the property well view
  73. typedef struct
  74. {
  75. LPCLASSENTRY pClassEntry; // class entry reference
  76. LPWSTR pProperty;
  77. LPWSTR pValue; // can be NULL
  78. INT iCondition;
  79. } PROPERTYWELLITEM, * LPPROPERTYWELLITEM;
  80. typedef struct
  81. {
  82. LPCQPAGE pQueryPage;
  83. HDPA hdpaItems;
  84. HDSA hdsaClasses;
  85. INT cxEdge;
  86. INT cyEdge;
  87. HWND hwnd;
  88. HWND hwndProperty;
  89. HWND hwndPropertyLabel;
  90. HWND hwndCondition;
  91. HWND hwndConditionLabel;
  92. HWND hwndValue;
  93. HWND hwndValueLabel;
  94. HWND hwndAdd;
  95. HWND hwndRemove;
  96. HWND hwndList;
  97. LPCLASSENTRY pClassEntry;
  98. LPWSTR pPropertyName;
  99. IDsDisplaySpecifier *pdds;
  100. } PROPERTYWELL, * LPPROPERTYWELL;
  101. BOOL PropertyWell_OnInitDialog(HWND hwnd, LPCQPAGE pQueryPage);
  102. BOOL PropertyWell_OnNCDestroy(LPPROPERTYWELL ppw);
  103. BOOL PropertyWell_OnSize(LPPROPERTYWELL ppw, INT cxWindow, INT cyWindow);
  104. VOID PropertyWell_OnDrawItem(LPPROPERTYWELL ppw, LPDRAWITEMSTRUCT pDrawItem);
  105. VOID PropertyWell_OnChooseProperty(LPPROPERTYWELL ppw);
  106. HRESULT PropertyWell_GetClassList(LPPROPERTYWELL ppw);
  107. VOID PropertyWell_FreeClassList(LPPROPERTYWELL ppw);
  108. LPCLASSENTRY PropertyWell_FindClassEntry(LPPROPERTYWELL ppw, LPWSTR pObjectClass);
  109. HRESULT PropertyWell_AddItem(LPPROPERTYWELL ppw, LPCLASSENTRY pClassEntry, LPWSTR pProperty, INT iCondition, LPWSTR pValue);
  110. VOID PropertyWell_RemoveItem(LPPROPERTYWELL ppw, INT iItem, BOOL fDeleteItem);
  111. VOID PropertyWell_EditItem(LPPROPERTYWELL ppw, INT iItem);
  112. HRESULT PropertyWell_EditProperty(LPPROPERTYWELL ppw, LPCLASSENTRY pClassEntry, LPWSTR pPropertyName, INT iCondition);
  113. VOID PropertyWell_ClearControls(LPPROPERTYWELL ppw);
  114. BOOL PropertyWell_EnableControls(LPPROPERTYWELL ppw, BOOL fEnable);
  115. VOID PropertyWell_SetColumnWidths(LPPROPERTYWELL ppw);
  116. HRESULT PropertyWell_GetQuery(LPPROPERTYWELL ppw, LPWSTR* ppQuery);
  117. HRESULT PropertyWell_Persist(LPPROPERTYWELL ppw, IPersistQuery* pPersistQuery, BOOL fRead);
  118. #define CONDITION_FROM_COMBO(hwnd) \
  119. (int)ComboBox_GetItemData(hwnd, ComboBox_GetCurSel(hwnd))
  120. //
  121. // Control help meppings
  122. //
  123. static DWORD const aFormHelpIDs[] =
  124. {
  125. IDC_PROPERTYLABEL, IDH_FIELD,
  126. IDC_PROPERTY, IDH_FIELD,
  127. IDC_CONDITIONLABEL, IDH_CONDITION,
  128. IDC_CONDITION, IDH_CONDITION,
  129. IDC_VALUELABEL, IDH_VALUE,
  130. IDC_VALUE, IDH_VALUE,
  131. IDC_ADD, IDH_ADD,
  132. IDC_REMOVE, IDH_REMOVE,
  133. IDC_CONDITIONLIST, IDH_CRITERIA,
  134. 0, 0,
  135. };
  136. /*-----------------------------------------------------------------------------
  137. / PageProc_PropertyWell
  138. / ---------------------
  139. / PageProc for handling the messages for this object.
  140. /
  141. / In:
  142. / pPage -> instance data for this form
  143. / hwnd = window handle for the form dialog
  144. / uMsg, wParam, lParam = message parameters
  145. /
  146. / Out:
  147. / HRESULT (E_NOTIMPL) if not handled
  148. /----------------------------------------------------------------------------*/
  149. HRESULT CALLBACK PageProc_PropertyWell(LPCQPAGE pPage, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  150. {
  151. HRESULT hr = S_OK;
  152. LPPROPERTYWELL ppw = (LPPROPERTYWELL)GetWindowLongPtr(hwnd, DWLP_USER);
  153. LPWSTR pQuery = NULL;
  154. USES_CONVERSION;
  155. TraceEnter(TRACE_FORMS, "PageProc_PropertyWell");
  156. // Only handle page messages if we have a property well object,
  157. // which is created when the PropWell dlg is init'd.
  158. if (ppw)
  159. {
  160. switch ( uMsg )
  161. {
  162. case CQPM_INITIALIZE:
  163. case CQPM_RELEASE:
  164. break;
  165. case CQPM_GETPARAMETERS:
  166. {
  167. LPDSQUERYPARAMS* ppDsQueryParams = (LPDSQUERYPARAMS*)lParam;
  168. // if the add button is enabled then we must prompt the user and see if they
  169. // want to add the current criteria to the query
  170. if ( IsWindowEnabled(ppw->hwndAdd) )
  171. {
  172. TCHAR szProperty[MAX_PATH];
  173. TCHAR szValue[MAX_PATH];
  174. INT id;
  175. LoadString(GLOBAL_HINSTANCE, IDS_WINDOWTITLE, szProperty, ARRAYSIZE(szProperty));
  176. LoadString(GLOBAL_HINSTANCE, IDS_ENTERCRITERIA, szValue, ARRAYSIZE(szValue));
  177. id = MessageBox(hwnd, szValue, szProperty, MB_YESNOCANCEL|MB_ICONWARNING);
  178. Trace(TEXT("MessageBox returned %08x"), id);
  179. if ( id == IDCANCEL )
  180. {
  181. ExitGracefully(hr, S_FALSE, "*** Aborting query ****");
  182. }
  183. else if ( id == IDYES )
  184. {
  185. GetWindowText(ppw->hwndValue, szValue, ARRAYSIZE(szValue));
  186. id = CONDITION_FROM_COMBO(ppw->hwndCondition);
  187. hr = PropertyWell_AddItem(ppw, ppw->pClassEntry, ppw->pPropertyName, id, T2W(szValue));
  188. FailGracefully(hr, "Failed to add the item to the current query");
  189. }
  190. }
  191. // zap anything in these fields and ensure the controls reflect the new state
  192. PropertyWell_ClearControls(ppw);
  193. if ( SUCCEEDED(PropertyWell_GetQuery(ppw, &pQuery)) && pQuery )
  194. {
  195. if ( !*ppDsQueryParams )
  196. hr = QueryParamsAlloc(ppDsQueryParams, pQuery, GLOBAL_HINSTANCE, ARRAYSIZE(columns), columns);
  197. else
  198. hr = QueryParamsAddQueryString(ppDsQueryParams, pQuery);
  199. LocalFreeStringW(&pQuery);
  200. }
  201. break;
  202. }
  203. case CQPM_ENABLE:
  204. PropertyWell_EnableControls(ppw, (BOOL)wParam);
  205. break;
  206. case CQPM_CLEARFORM:
  207. ListView_DeleteAllItems(ppw->hwndList);
  208. PropertyWell_ClearControls(ppw);
  209. break;
  210. case CQPM_PERSIST:
  211. hr = PropertyWell_Persist(ppw, (IPersistQuery*)lParam, (BOOL)wParam);
  212. break;
  213. case CQPM_SETDEFAULTPARAMETERS:
  214. {
  215. LPOPENQUERYWINDOW poqw = (LPOPENQUERYWINDOW)lParam;
  216. //
  217. // if we recieve this message we should ensure that we have the IDsDsiplaySpecifier
  218. // object and then we can set the credential information.
  219. //
  220. if ( ppw && poqw->pHandlerParameters )
  221. {
  222. LPDSQUERYINITPARAMS pdqip = (LPDSQUERYINITPARAMS)poqw->pHandlerParameters;
  223. if ( pdqip->dwFlags & DSQPF_HASCREDENTIALS )
  224. {
  225. Trace(TEXT("pUserName : %s"), pdqip->pUserName ? W2T(pdqip->pUserName):TEXT("<not specified>"));
  226. Trace(TEXT("pServer : %s"), pdqip->pServer ? W2T(pdqip->pServer):TEXT("<not specified>"));
  227. hr = ppw->pdds->SetServer(pdqip->pServer, pdqip->pUserName, pdqip->pPassword, DSSSF_DSAVAILABLE);
  228. FailGracefully(hr, "Failed to set the server information");
  229. }
  230. }
  231. break;
  232. }
  233. case DSQPM_GETCLASSLIST:
  234. {
  235. DWORD cbStruct, offset;
  236. LPDSQUERYCLASSLIST pDsQueryClassList = NULL;
  237. INT i;
  238. if ( wParam & DSQPM_GCL_FORPROPERTYWELL )
  239. {
  240. TraceMsg("Property well calling property well, ignore!");
  241. break;
  242. }
  243. if ( !lParam )
  244. ExitGracefully(hr, E_FAIL, "lParam == NULL, not supported");
  245. // Get the list of classes that the user can/has selected properties from,
  246. // having done this we can then can then generate a suitable query.
  247. hr = PropertyWell_GetClassList(ppw);
  248. FailGracefully(hr, "Failed to get the class list");
  249. cbStruct = SIZEOF(DSQUERYCLASSLIST) + (DSA_GetItemCount(ppw->hdsaClasses)*SIZEOF(DWORD));
  250. offset = cbStruct;
  251. for ( i = 0 ; i < DSA_GetItemCount(ppw->hdsaClasses) ; i++ )
  252. {
  253. LPCLASSENTRY pCE = (LPCLASSENTRY)DSA_GetItemPtr(ppw->hdsaClasses, i);
  254. TraceAssert(pCE);
  255. cbStruct += StringByteSizeW(pCE->pName);
  256. }
  257. // Allocate the blob we need to pass out and fill it.
  258. Trace(TEXT("Allocating class structure %d"), cbStruct);
  259. pDsQueryClassList = (LPDSQUERYCLASSLIST)CoTaskMemAlloc(cbStruct);
  260. TraceAssert(pDsQueryClassList);
  261. if ( !pDsQueryClassList )
  262. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate class list structure");
  263. Trace(TEXT("pDsQueryClassList %08x"), pDsQueryClassList);
  264. pDsQueryClassList->cbStruct = cbStruct;
  265. pDsQueryClassList->cClasses = DSA_GetItemCount(ppw->hdsaClasses);
  266. for ( i = 0 ; i < DSA_GetItemCount(ppw->hdsaClasses) ; i++ )
  267. {
  268. LPCLASSENTRY pCE = (LPCLASSENTRY)DSA_GetItemPtr(ppw->hdsaClasses, i);
  269. TraceAssert(pCE);
  270. Trace(TEXT("Adding class: %s"), W2T(pCE->pName));
  271. pDsQueryClassList->offsetClass[i] = offset;
  272. StringByteCopyW(pDsQueryClassList, offset, pCE->pName);
  273. offset += StringByteSizeW(pCE->pName);
  274. }
  275. TraceAssert(pDsQueryClassList);
  276. *((LPDSQUERYCLASSLIST*)lParam) = pDsQueryClassList;
  277. break;
  278. }
  279. case CQPM_HELP:
  280. {
  281. LPHELPINFO pHelpInfo = (LPHELPINFO)lParam;
  282. WinHelp((HWND)pHelpInfo->hItemHandle,
  283. DSQUERY_HELPFILE,
  284. HELP_WM_HELP,
  285. (DWORD_PTR)aFormHelpIDs);
  286. break;
  287. }
  288. case DSQPM_HELPTOPICS:
  289. {
  290. HWND hwndFrame = (HWND)lParam;
  291. HtmlHelp(hwndFrame, TEXT("omc.chm"), HH_HELP_FINDER, 0);
  292. break;
  293. }
  294. default:
  295. hr = E_NOTIMPL;
  296. break;
  297. }
  298. }
  299. exit_gracefully:
  300. TraceLeaveResult(hr);
  301. }
  302. /*-----------------------------------------------------------------------------
  303. / Dialog helper functions
  304. /----------------------------------------------------------------------------*/
  305. /*-----------------------------------------------------------------------------
  306. / DlgProc_PropertyWell
  307. / --------------------
  308. / Standard dialog proc for the form, handle any special buttons and other
  309. / such nastyness we must here.
  310. /
  311. / In:
  312. / hwnd, uMsg, wParam, lParam = standard parameters
  313. /
  314. / Out:
  315. / INT_PTR
  316. /----------------------------------------------------------------------------*/
  317. INT_PTR CALLBACK DlgProc_PropertyWell(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  318. {
  319. INT_PTR fResult = FALSE;
  320. LPPROPERTYWELL ppw = NULL;
  321. USES_CONVERSION;
  322. if ( uMsg == WM_INITDIALOG )
  323. {
  324. fResult = PropertyWell_OnInitDialog(hwnd, (LPCQPAGE)lParam);
  325. }
  326. else
  327. {
  328. ppw = (LPPROPERTYWELL)GetWindowLongPtr(hwnd, DWLP_USER);
  329. switch ( uMsg )
  330. {
  331. case WM_NCDESTROY:
  332. PropertyWell_OnNCDestroy(ppw);
  333. break;
  334. case WM_COMMAND:
  335. {
  336. switch ( LOWORD(wParam) )
  337. {
  338. case IDC_PROPERTYLABEL:
  339. {
  340. if ( HIWORD(wParam) == BN_CLICKED )
  341. PropertyWell_OnChooseProperty(ppw);
  342. break;
  343. }
  344. case IDC_PROPERTY:
  345. case IDC_CONDITION:
  346. case IDC_VALUE:
  347. {
  348. if ( (HIWORD(wParam) == EN_CHANGE) || (HIWORD(wParam) == CBN_SELCHANGE) )
  349. PropertyWell_EnableControls(ppw, TRUE);
  350. break;
  351. }
  352. case IDC_ADD:
  353. {
  354. TCHAR szProperty[MAX_PATH] = { TEXT('\0') };
  355. TCHAR szValue[MAX_PATH] = { TEXT('\0') };
  356. INT iCondition;
  357. iCondition = CONDITION_FROM_COMBO(ppw->hwndCondition);
  358. if ( IsWindowEnabled(ppw->hwndValue) )
  359. GetWindowText(ppw->hwndValue, szValue, ARRAYSIZE(szValue));
  360. PropertyWell_AddItem(ppw, ppw->pClassEntry, ppw->pPropertyName, iCondition, T2W(szValue));
  361. break;
  362. }
  363. case IDC_REMOVE:
  364. {
  365. INT item = ListView_GetNextItem(ppw->hwndList, -1, LVNI_ALL|LVNI_SELECTED);
  366. PropertyWell_RemoveItem(ppw, item, TRUE);
  367. }
  368. }
  369. break;
  370. }
  371. case WM_DRAWITEM:
  372. PropertyWell_OnDrawItem(ppw, (LPDRAWITEMSTRUCT)lParam);
  373. break;
  374. case WM_NOTIFY:
  375. {
  376. LPNMHDR pNotify = (LPNMHDR)lParam;
  377. switch ( pNotify->code )
  378. {
  379. case LVN_DELETEITEM:
  380. {
  381. NM_LISTVIEW* pNotify = (NM_LISTVIEW*)lParam;
  382. PropertyWell_RemoveItem(ppw, pNotify->iItem, FALSE);
  383. break;
  384. }
  385. case LVN_ITEMCHANGED:
  386. {
  387. PropertyWell_EnableControls(ppw, TRUE);
  388. break;
  389. }
  390. case NM_DBLCLK:
  391. {
  392. INT item = ListView_GetNextItem(ppw->hwndList, -1, LVNI_ALL|LVNI_SELECTED);
  393. PropertyWell_EditItem(ppw, item);
  394. break;
  395. }
  396. case LVN_GETEMPTYTEXT:
  397. {
  398. NMLVDISPINFO* pNotify = (NMLVDISPINFO*)lParam;
  399. if ( pNotify->item.mask & LVIF_TEXT )
  400. {
  401. LoadString(GLOBAL_HINSTANCE, IDS_CRITERIAEMPTY, pNotify->item.pszText, pNotify->item.cchTextMax);
  402. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
  403. fResult = TRUE;
  404. }
  405. break;
  406. }
  407. }
  408. break;
  409. }
  410. case WM_SIZE:
  411. return PropertyWell_OnSize(ppw, LOWORD(lParam), HIWORD(lParam));
  412. case WM_CONTEXTMENU:
  413. WinHelp((HWND)wParam, DSQUERY_HELPFILE, HELP_CONTEXTMENU, (DWORD_PTR)aFormHelpIDs);
  414. fResult = TRUE;
  415. break;
  416. }
  417. }
  418. return fResult;
  419. }
  420. /*-----------------------------------------------------------------------------
  421. / PropertyWell_OnInitDlg
  422. / ----------------------
  423. / Initialize the dialog, constructing the property DPA so that we can
  424. / build the store the query.
  425. /
  426. / In:
  427. / hwnd = window handle being initialized
  428. / pDsQuery -> CDsQuery object to associate with
  429. /
  430. / Out:
  431. / BOOL
  432. /----------------------------------------------------------------------------*/
  433. BOOL PropertyWell_OnInitDialog(HWND hwnd, LPCQPAGE pQueryPage)
  434. {
  435. HRESULT hr;
  436. LPPROPERTYWELL ppw;
  437. TCHAR szBuffer[MAX_PATH];
  438. LV_COLUMN lvc;
  439. INT i;
  440. TraceEnter(TRACE_PWELL, "PropertyWell_OnInitDialog");
  441. // Allocate the state structure and fill it
  442. ppw = (LPPROPERTYWELL)LocalAlloc(LPTR, SIZEOF(PROPERTYWELL));
  443. if ( !ppw )
  444. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to alloc PROPERTYWELL struct");
  445. Trace(TEXT("ppw = %08x"), ppw);
  446. SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)ppw);
  447. // now initialize the structure
  448. ppw->pQueryPage = pQueryPage;
  449. //ppw->hdpaItems = NULL;
  450. //ppw->hdsaClasses = NULL;
  451. ppw->cxEdge = GetSystemMetrics(SM_CXEDGE);
  452. ppw->cyEdge = GetSystemMetrics(SM_CYEDGE);
  453. ppw->hwnd = hwnd;
  454. ppw->hwndProperty = GetDlgItem(hwnd, IDC_PROPERTY);
  455. ppw->hwndPropertyLabel = GetDlgItem(hwnd, IDC_PROPERTYLABEL);
  456. ppw->hwndCondition = GetDlgItem(hwnd, IDC_CONDITION);
  457. ppw->hwndConditionLabel = GetDlgItem(hwnd, IDC_CONDITIONLABEL);
  458. ppw->hwndValue = GetDlgItem(hwnd, IDC_VALUE);
  459. ppw->hwndValueLabel = GetDlgItem(hwnd, IDC_VALUELABEL);
  460. ppw->hwndAdd = GetDlgItem(hwnd, IDC_ADD);
  461. ppw->hwndRemove = GetDlgItem(hwnd, IDC_REMOVE);
  462. ppw->hwndList = GetDlgItem(hwnd, IDC_CONDITIONLIST);
  463. ppw->hdpaItems = DPA_Create(16);
  464. if ( !ppw->hdpaItems )
  465. ExitGracefully(hr, E_FAIL, "Failed to create DPA");
  466. // ppw->pClassItem = NULL;
  467. // ppw->pPropertyName = NULL;
  468. hr = CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (void **)&ppw->pdds);
  469. FailGracefully(hr, "Failed to CoCreate the IDsDisplaySpecifier object");
  470. ListView_SetExtendedListViewStyle(ppw->hwndList, LVS_EX_FULLROWSELECT|LVS_EX_LABELTIP);
  471. // Add the conditions to the condition picker, then add the columns to the
  472. // condition list.
  473. for ( i = 0 ; i < ARRAYSIZE(view_columns) ; i++ )
  474. {
  475. lvc.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT;
  476. lvc.fmt = view_columns[i].fmt;
  477. lvc.cx = view_columns[i].cx;
  478. lvc.pszText = TEXT("Bla");
  479. ListView_InsertColumn(ppw->hwndList, i, &lvc);
  480. }
  481. Edit_LimitText(ppw->hwndValue, MAX_PATH);
  482. PropertyWell_EnableControls(ppw, TRUE);
  483. exit_gracefully:
  484. TraceLeaveValue(TRUE);
  485. }
  486. /*-----------------------------------------------------------------------------
  487. / PropertyWell_OnNCDestroy
  488. / ------------------------
  489. / The dialog is being nuked, therefore remove our reference to the CDsQuery
  490. / and free any allocations we have with this window.
  491. /
  492. / In:
  493. / ppw -> window defn to use
  494. /
  495. / Out:
  496. / BOOL
  497. /----------------------------------------------------------------------------*/
  498. BOOL PropertyWell_OnNCDestroy(LPPROPERTYWELL ppw)
  499. {
  500. BOOL fResult = TRUE;
  501. TraceEnter(TRACE_PWELL, "PropertyWell_OnNCDestroy");
  502. if ( ppw )
  503. {
  504. if ( ppw->hdpaItems )
  505. {
  506. TraceAssert(0 == DPA_GetPtrCount(ppw->hdpaItems));
  507. DPA_Destroy(ppw->hdpaItems);
  508. }
  509. PropertyWell_FreeClassList(ppw);
  510. LocalFreeStringW(&ppw->pPropertyName);
  511. DoRelease(ppw->pdds);
  512. SetWindowLongPtr(ppw->hwnd, DWLP_USER, (LONG_PTR)NULL);
  513. LocalFree((HLOCAL)ppw);
  514. }
  515. TraceLeaveValue(fResult);
  516. }
  517. /*-----------------------------------------------------------------------------
  518. / PropertyWell_OnSize
  519. / -------------------
  520. / The property well dialog is being sized, therefore lets move the
  521. / controls around within it to reflect the new size.
  522. /
  523. / In:
  524. / ppw -> property well to size
  525. / cx, cy = new size
  526. /
  527. / Out:
  528. / BOOL
  529. /----------------------------------------------------------------------------*/
  530. BOOL PropertyWell_OnSize(LPPROPERTYWELL ppw, INT cxWindow, INT cyWindow)
  531. {
  532. RECT rect;
  533. SIZE size;
  534. INT x, cx;
  535. INT xProperty, xCondition, xValue;
  536. INT iSeperator, iEdge, iElement, iFixedElement;
  537. TraceEnter(TRACE_PWELL, "PropertyWell_OnSize");
  538. Trace(TEXT("New size cxWindow %d, cyWindow %d"), cxWindow, cyWindow);
  539. iSeperator = (DLU_SEPERATOR * LOWORD(GetDialogBaseUnits())) / 4;
  540. iEdge = (DLU_EDGE * LOWORD(GetDialogBaseUnits())) / 4;
  541. iFixedElement = (DLU_FIXEDELEMENT * LOWORD(GetDialogBaseUnits())) / 4;
  542. x = cxWindow - (iEdge*2) - (iSeperator*2);
  543. iElement = x / 3;
  544. iFixedElement = min(iElement, iFixedElement);
  545. iElement = x - (iFixedElement*2);
  546. // Move the controls around accordingly
  547. xProperty = iEdge;
  548. GetRealWindowInfo(ppw->hwndProperty, &rect, &size);
  549. SetWindowPos(ppw->hwndProperty, NULL, xProperty, rect.top, iFixedElement, size.cy, SWP_NOZORDER);
  550. GetRealWindowInfo(ppw->hwndPropertyLabel, &rect, &size);
  551. SetWindowPos(ppw->hwndPropertyLabel, NULL, xProperty, rect.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
  552. xCondition = iEdge + iFixedElement + iSeperator;
  553. GetRealWindowInfo(ppw->hwndCondition, &rect, &size);
  554. SetWindowPos(ppw->hwndCondition, NULL, xCondition, rect.top, iFixedElement, size.cy, SWP_NOZORDER);
  555. GetRealWindowInfo(ppw->hwndConditionLabel, &rect, &size);
  556. SetWindowPos(ppw->hwndConditionLabel, NULL, xCondition, rect.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
  557. xValue = cxWindow - iEdge - iElement;
  558. GetRealWindowInfo(ppw->hwndValue, &rect, &size);
  559. SetWindowPos(ppw->hwndValue, NULL, xValue, rect.top, iElement, size.cy, SWP_NOZORDER);
  560. GetRealWindowInfo(ppw->hwndValueLabel, &rect, &size);
  561. SetWindowPos(ppw->hwndValueLabel, NULL, xValue, rect.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
  562. // Move the add / remove buttons
  563. GetRealWindowInfo(ppw->hwndRemove, &rect, &size);
  564. x = cxWindow - iEdge - size.cx;
  565. SetWindowPos(ppw->hwndRemove, NULL, x, rect.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
  566. GetRealWindowInfo(ppw->hwndAdd, &rect, &size);
  567. x -= size.cx + iSeperator;
  568. SetWindowPos(ppw->hwndAdd, NULL, x, rect.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
  569. // Move the list view control + size accordingly
  570. GetRealWindowInfo(ppw->hwndList, &rect, &size);
  571. SetWindowPos(ppw->hwndList, NULL, iEdge, rect.top, cxWindow - (iEdge*2), size.cy, SWP_NOZORDER);
  572. PropertyWell_SetColumnWidths(ppw);
  573. TraceLeaveValue(FALSE);
  574. }
  575. /*-----------------------------------------------------------------------------
  576. / PropertyWell_OnDrawItem
  577. / -----------------------
  578. / The property button is owner drawn, therefore lets handle rendering that
  579. / we assume that the base implementation (eg. the button control) is
  580. / handling storing the text, font and other interesting information we
  581. / will just render the face as required.
  582. /
  583. / In:
  584. / ppw -> property well to size
  585. / pDrawItem -> DRAWITEMSTRUCT used for rendering
  586. /
  587. / Out:
  588. / void
  589. /----------------------------------------------------------------------------*/
  590. VOID PropertyWell_OnDrawItem(LPPROPERTYWELL ppw, LPDRAWITEMSTRUCT pDrawItem)
  591. {
  592. SIZE thin = { ppw->cxEdge / 2, ppw->cyEdge / 2 };
  593. RECT rc = pDrawItem->rcItem;
  594. HDC hdc = pDrawItem->hDC;
  595. BOOL fDisabled = pDrawItem->itemState & ODS_DISABLED;
  596. BOOL fSelected = pDrawItem->itemState & ODS_SELECTED;
  597. BOOL fFocus = (pDrawItem->itemState & ODS_FOCUS)
  598. #if (_WIN32_WINNT >= 0x0500)
  599. && !(pDrawItem->itemState & ODS_NOFOCUSRECT)
  600. #endif
  601. && !(pDrawItem->itemState & ODS_DISABLED);
  602. TCHAR szBuffer[64];
  603. HBRUSH hbr;
  604. INT i, x, y;
  605. SIZE sz;
  606. UINT fuFlags = DST_PREFIXTEXT;
  607. TraceEnter(TRACE_PWELL, "PropertyWell_OnDrawItem");
  608. if ( pDrawItem->CtlID != IDC_PROPERTYLABEL )
  609. goto exit_gracefully;
  610. // render the button edges (assumes that we have an NT4 look)
  611. thin.cx = max(thin.cx, 1);
  612. thin.cy = max(thin.cy, 1);
  613. if ( fSelected )
  614. {
  615. DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT|BF_ADJUST);
  616. OffsetRect(&rc, 1, 1);
  617. }
  618. else
  619. {
  620. DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT|BF_ADJUST);
  621. }
  622. FillRect(hdc, &rc, GetSysColorBrush(COLOR_3DFACE));
  623. // put the focus rect in if we are focused...
  624. if ( fFocus )
  625. {
  626. InflateRect(&rc, -thin.cx, -thin.cy);
  627. DrawFocusRect(hdc, &rc);
  628. InflateRect(&rc, thin.cx, thin.cy);
  629. }
  630. InflateRect(&rc, 1-thin.cx, -ppw->cyEdge);
  631. rc.left += ppw->cxEdge*2;
  632. // paint the arrow to the right of the control
  633. x = rc.right - ppw->cxEdge - 13;
  634. y = rc.top + ((rc.bottom - rc.top)/2) - 2;
  635. if ( fDisabled )
  636. {
  637. hbr = (HBRUSH)GetSysColorBrush(COLOR_3DHILIGHT);
  638. hbr = (HBRUSH)SelectObject(hdc, hbr);
  639. x++;
  640. y++;
  641. PatBlt(hdc, x+1, y, 7, 1, PATCOPY);
  642. PatBlt(hdc, x+2, y+1, 5, 1, PATCOPY);
  643. PatBlt(hdc, x+3, y+2, 3, 1, PATCOPY);
  644. PatBlt(hdc, x+4, y+3, 1, 1, PATCOPY);
  645. SelectObject(hdc, hbr);
  646. x--;
  647. y--;
  648. }
  649. hbr = (HBRUSH)GetSysColorBrush(fDisabled ? COLOR_3DSHADOW : COLOR_BTNTEXT);
  650. hbr = (HBRUSH)SelectObject(hdc, hbr);
  651. PatBlt(hdc, x, y+1, 7, 1, PATCOPY);
  652. PatBlt(hdc, x+1, y+2, 5, 1, PATCOPY);
  653. PatBlt(hdc, x+2, y+3, 3, 1, PATCOPY);
  654. PatBlt(hdc, x+3, y+4, 1, 1, PATCOPY);
  655. SelectObject(hdc, hbr);
  656. rc.right = x;
  657. // render the label in the remaining area (clipped accordingly)
  658. i = GetWindowText(ppw->hwndPropertyLabel, szBuffer, ARRAYSIZE(szBuffer));
  659. GetTextExtentPoint(hdc, szBuffer, i, &sz);
  660. x = rc.left+(((rc.right-rc.left)-sz.cx)/2);
  661. if ( fDisabled )
  662. fuFlags |= DSS_DISABLED;
  663. #if (_WIN32_WINNT >= 0x0500)
  664. if ( pDrawItem->itemState & ODS_NOACCEL )
  665. fuFlags |= DSS_HIDEPREFIX;
  666. #endif
  667. DrawState(hdc, NULL, NULL,
  668. (LPARAM)szBuffer, (WPARAM)0,
  669. x, rc.top, sz.cx, sz.cy,
  670. fuFlags);
  671. exit_gracefully:
  672. TraceLeave();
  673. }
  674. /*-----------------------------------------------------------------------------
  675. / PropertyWell_OnChooseProperty
  676. / -----------------------------
  677. / Display the class / property list and build the menu from it, this calls on
  678. / several helper functions.
  679. /
  680. / In:
  681. / ppw -> property well to size
  682. /
  683. / Out:
  684. / void
  685. /----------------------------------------------------------------------------*/
  686. //
  687. // call the property enumerator and populate the our DPA
  688. //
  689. typedef struct
  690. {
  691. UINT wID;
  692. HDPA hdpaAttributes;
  693. INT iClass;
  694. HMENU hMenu;
  695. } PROPENUMSTRUCT, * LPPROPENUMSTRUCT;
  696. HRESULT CALLBACK _FillMenuCB(LPARAM lParam, LPCWSTR pAttributeName, LPCWSTR pDisplayName, DWORD dwFlags)
  697. {
  698. HRESULT hres = S_OK;
  699. PROPENUMSTRUCT *ppes = (PROPENUMSTRUCT *)lParam;
  700. MENUITEMINFO mii = { 0 };
  701. UINT_PTR iProperty = 0;
  702. USES_CONVERSION;
  703. TraceEnter(TRACE_PWELL, "_FillMenuCB");
  704. if ( !(dwFlags & DSECAF_NOTLISTED) )
  705. {
  706. hres = StringDPA_AppendStringW(ppes->hdpaAttributes, pAttributeName, &iProperty);
  707. FailGracefully(hres, "Failed to add the attribute to the DPA");
  708. mii.cbSize = SIZEOF(mii);
  709. mii.fMask = MIIM_TYPE|MIIM_ID|MIIM_DATA;
  710. mii.dwItemData = MAKELPARAM(ppes->iClass, iProperty);
  711. mii.fType = MFT_STRING;
  712. mii.wID = ppes->wID++;
  713. mii.dwTypeData = (LPTSTR)W2CT(pDisplayName);
  714. mii.cch = lstrlenW(pDisplayName);
  715. if ( !InsertMenuItem(ppes->hMenu, 0x7fff, TRUE, &mii) )
  716. ExitGracefully(hres, E_FAIL, "Failed to add the item to the menu");
  717. }
  718. else
  719. {
  720. TraceMsg("Property marked as hidden, so not appending to the DPA");
  721. }
  722. hres = S_OK;
  723. exit_gracefully:
  724. TraceLeaveResult(hres);
  725. }
  726. VOID PropertyWell_OnChooseProperty(LPPROPERTYWELL ppw)
  727. {
  728. HRESULT hr;
  729. HMENU hMenuToTrack, hMenu = NULL;
  730. PROPENUMSTRUCT pes = { 0 };
  731. RECT rcItem;
  732. LPCLASSENTRY pCE;
  733. LPWSTR pszAttribute;
  734. UINT uID;
  735. INT iItem, iClass;
  736. MENUITEMINFO mii = { 0 };
  737. DECLAREWAITCURSOR;
  738. USES_CONVERSION;
  739. TraceEnter(TRACE_PWELL, "PropertyWell_OnChooseProperty");
  740. SetWaitCursor();
  741. // construct a menu, and populate with the elements from teh class list,
  742. // which we store in a DSA assocaited with this query form
  743. hr = PropertyWell_GetClassList(ppw);
  744. FailGracefully(hr, "Failed to get the class list");
  745. pes.wID = CLID_FIRST;
  746. pes.hdpaAttributes = DPA_Create(4);
  747. if ( !pes.hdpaAttributes )
  748. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate string DPA");
  749. hMenuToTrack = hMenu = CreatePopupMenu();
  750. TraceAssert(hMenu);
  751. if ( !hMenu )
  752. ExitGracefully(hr, E_FAIL, "Failed to create class menu");
  753. for ( pes.iClass = 0; pes.iClass < DSA_GetItemCount(ppw->hdsaClasses); pes.iClass++ )
  754. {
  755. pCE = (LPCLASSENTRY)DSA_GetItemPtr(ppw->hdsaClasses, pes.iClass);
  756. TraceAssert(pCE);
  757. // Create the sub-menu for this entry in the cache and populate it with the list of
  758. // properties we picked from the schema.
  759. pes.hMenu = CreatePopupMenu();
  760. TraceAssert(pes.hMenu);
  761. if ( !pes.hMenu )
  762. ExitGracefully(hr, E_FAIL, "Failed when creating the sub menu for the property list");
  763. if ( FAILED(EnumClassAttributes(ppw->pdds, pCE->pName, _FillMenuCB, (LPARAM)&pes)) )
  764. {
  765. DestroyMenu(pes.hMenu);
  766. ExitGracefully(hr, E_FAIL, "Failed when building the property menu");
  767. }
  768. // Now add that sub-menu to the main menu with a caption that reflects the name of
  769. // the class we are picking from.
  770. mii.cbSize = SIZEOF(mii);
  771. mii.fMask = MIIM_SUBMENU|MIIM_TYPE;
  772. mii.fType = MFT_STRING;
  773. mii.hSubMenu = pes.hMenu;
  774. mii.dwTypeData = pCE->pDisplayName;
  775. mii.cch = MAX_PATH;
  776. if ( !InsertMenuItem(hMenu, 0x7fff, TRUE, &mii) )
  777. {
  778. DestroyMenu(pes.hMenu);
  779. ExitGracefully(hr, E_FAIL, "Failed when building the class menu");
  780. }
  781. }
  782. ResetWaitCursor();
  783. // having constructed the menu lets display it just below the button
  784. // we are invoked from, if the user selects something then lets put
  785. // it into the edit line which will enable the rest of the UI.
  786. GetWindowRect(ppw->hwndPropertyLabel, &rcItem);
  787. if ( GetMenuItemCount(hMenu) == 1 )
  788. {
  789. TraceMsg("Single class in menu, therefore just showing properties");
  790. hMenuToTrack = GetSubMenu(hMenu, 0);
  791. TraceAssert(hMenuToTrack);
  792. }
  793. uID = TrackPopupMenu(hMenuToTrack,
  794. TPM_TOPALIGN|TPM_RETURNCMD,
  795. rcItem.left, rcItem.bottom,
  796. 0, ppw->hwnd, NULL);
  797. if ( !uID )
  798. {
  799. TraceMsg("Menu canceled nothing selected");
  800. }
  801. else
  802. {
  803. mii.cbSize = SIZEOF(mii);
  804. mii.fMask = MIIM_DATA;
  805. if ( !GetMenuItemInfo(hMenu, uID, FALSE, &mii) )
  806. ExitGracefully(hr, E_FAIL, "Failed to get item data");
  807. // unpick the item data and get the iClass and iProperty of the item
  808. // we have selected, that way we can then populate the control
  809. // with the property name.
  810. pCE = (LPCLASSENTRY)DSA_GetItemPtr(ppw->hdsaClasses, LOWORD(mii.dwItemData));
  811. TraceAssert(pCE);
  812. pszAttribute = StringDPA_GetStringW(pes.hdpaAttributes, HIWORD(mii.dwItemData));
  813. Trace(TEXT("Attribute selected : %s"), W2T(pszAttribute));
  814. hr = PropertyWell_EditProperty(ppw, pCE, pszAttribute, -1);
  815. FailGracefully(hr, "Failed to set edit property");
  816. }
  817. hr = S_OK; // success
  818. exit_gracefully:
  819. if ( hMenu )
  820. DestroyMenu(hMenu);
  821. StringDPA_Destroy(&pes.hdpaAttributes);
  822. ResetWaitCursor();
  823. TraceLeave();
  824. }
  825. /*-----------------------------------------------------------------------------
  826. / Class/Property maps
  827. /----------------------------------------------------------------------------*/
  828. /*-----------------------------------------------------------------------------
  829. / PropertyWell_GetClassList
  830. / -------------------------
  831. / Obtain the list of visible classes for the for this user. If the
  832. / list is already present then just return S_OK.
  833. /
  834. / In:
  835. / ppw -> property well structure
  836. /
  837. / Out:
  838. / HRESULT
  839. /----------------------------------------------------------------------------*/
  840. //
  841. // Return all display specifiers who have a class display name and a list of
  842. // attributes to be displayed in the UI.
  843. //
  844. WCHAR c_szQuery[] = L"(&(classDisplayName=*)(attributeDisplayNames=*))";
  845. LPWSTR pProperties[] =
  846. {
  847. L"name",
  848. L"classDisplayName",
  849. };
  850. #define PAGE_SIZE 128
  851. HRESULT PropertyWell_GetClassList(LPPROPERTYWELL ppw)
  852. {
  853. HRESULT hr;
  854. IQueryFrame* pQueryFrame = NULL;
  855. IDirectorySearch* pds = NULL;
  856. ADS_SEARCH_COLUMN column;
  857. ADS_SEARCHPREF_INFO prefInfo[3];
  858. ADS_SEARCH_HANDLE hSearch = NULL;
  859. CLASSENTRY ce;
  860. LPDSQUERYCLASSLIST pDsQueryClassList = NULL;
  861. LPWSTR pName = NULL;
  862. LPWSTR pDisplayName = NULL;
  863. WCHAR szBufferW[MAX_PATH];
  864. INT i;
  865. DECLAREWAITCURSOR;
  866. USES_CONVERSION;
  867. TraceEnter(TRACE_PWELL, "PropertyWell_GetClassList");
  868. SetWaitCursor();
  869. if ( !ppw->hdsaClasses )
  870. {
  871. // Construct a DSA for us to store the class information we need.
  872. ppw->hdsaClasses = DSA_Create(SIZEOF(CLASSENTRY), 4);
  873. TraceAssert(ppw->hdsaClasses);
  874. if ( !ppw->hdsaClasses )
  875. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to create class DSA");
  876. // Call the query form we are part of to see if they want to declare any classes
  877. // for us to show in the drop down. We use the CQFWM_GETFRAME to get the
  878. // IQueryFrame interface from the form and then call all the forms
  879. // with a magic bit so we (the property well) ignore the
  880. // request for the class list.
  881. if ( SendMessage(GetParent(ppw->hwnd), CQFWM_GETFRAME, 0, (LPARAM)&pQueryFrame) )
  882. {
  883. if ( SUCCEEDED(pQueryFrame->CallForm(NULL, DSQPM_GETCLASSLIST,
  884. DSQPM_GCL_FORPROPERTYWELL, (LPARAM)&pDsQueryClassList)) )
  885. {
  886. if ( pDsQueryClassList )
  887. {
  888. for ( i = 0 ; i < pDsQueryClassList->cClasses ; i++ )
  889. {
  890. LPWSTR pObjectClass = (LPWSTR)ByteOffset(pDsQueryClassList, pDsQueryClassList->offsetClass[i]);
  891. TraceAssert(pObjectClass);
  892. TraceAssert(ppw->pdds != NULL);
  893. ppw->pdds->GetFriendlyClassName(pObjectClass, szBufferW, ARRAYSIZE(szBufferW));
  894. ce.pName = NULL;
  895. ce.pDisplayName = NULL;
  896. ce.cReferences = 0;
  897. if ( FAILED(LocalAllocStringW(&ce.pName, pObjectClass)) ||
  898. FAILED(LocalAllocStringW2T(&ce.pDisplayName, szBufferW)) ||
  899. ( -1 == DSA_AppendItem(ppw->hdsaClasses, &ce)) )
  900. {
  901. LocalFreeStringW(&ce.pName);
  902. LocalFreeString(&ce.pDisplayName);
  903. }
  904. }
  905. }
  906. }
  907. }
  908. // if we didn't get anything from the form we are hosted on then let us
  909. // troll around in the display specifier container collecting all the
  910. // objects from there.
  911. if ( DSA_GetItemCount(ppw->hdsaClasses) == 0 )
  912. {
  913. // Set the query prefernece to single level scope, and async retrevial rather
  914. // than waiting for all objects
  915. TraceAssert(ppw->pdds);
  916. hr = ppw->pdds->GetDisplaySpecifier(NULL, IID_IDirectorySearch, (LPVOID*)&pds);
  917. FailGracefully(hr, "Failed to get IDsSearch on the display-spec container");
  918. prefInfo[0].dwSearchPref = ADS_SEARCHPREF_SEARCH_SCOPE;
  919. prefInfo[0].vValue.dwType = ADSTYPE_INTEGER;
  920. prefInfo[0].vValue.Integer = ADS_SCOPE_ONELEVEL;
  921. prefInfo[1].dwSearchPref = ADS_SEARCHPREF_ASYNCHRONOUS;
  922. prefInfo[1].vValue.dwType = ADSTYPE_BOOLEAN;
  923. prefInfo[1].vValue.Boolean = TRUE;
  924. prefInfo[2].dwSearchPref = ADS_SEARCHPREF_PAGESIZE; // paged results
  925. prefInfo[2].vValue.dwType = ADSTYPE_INTEGER;
  926. prefInfo[2].vValue.Integer = PAGE_SIZE;
  927. hr = pds->SetSearchPreference(prefInfo, ARRAYSIZE(prefInfo));
  928. FailGracefully(hr, "Failed to set search preferences");
  929. hr = pds->ExecuteSearch(c_szQuery, pProperties, ARRAYSIZE(pProperties), &hSearch);
  930. FailGracefully(hr, "Failed in ExecuteSearch");
  931. while ( TRUE )
  932. {
  933. LocalFreeStringW(&pName);
  934. LocalFreeStringW(&pDisplayName);
  935. // Get the next row from the result set, it consists of
  936. // two columns. The first column is the class name of
  937. // the object (<className-Display>) and the second
  938. // is the friendly name of the class we are trying
  939. // to display.
  940. hr = pds->GetNextRow(hSearch);
  941. FailGracefully(hr, "Failed to get the next row");
  942. if ( hr == S_ADS_NOMORE_ROWS )
  943. {
  944. TraceMsg("No more results, no more rows");
  945. break;
  946. }
  947. if ( SUCCEEDED(pds->GetColumn(hSearch, pProperties[0], &column)) )
  948. {
  949. hr = StringFromSearchColumn(&column, &pName);
  950. pds->FreeColumn(&column);
  951. FailGracefully(hr, "Failed to get the name object");
  952. if (!pName)
  953. {
  954. break;
  955. }
  956. }
  957. if ( SUCCEEDED(pds->GetColumn(hSearch, pProperties[1], &column)) )
  958. {
  959. hr = StringFromSearchColumn(&column, &pDisplayName);
  960. pds->FreeColumn(&column);
  961. FailGracefully(hr, "Failed to get the display name from the object");
  962. }
  963. Trace(TEXT("Display name %s for class %s"), W2T(pDisplayName), W2T(pName));
  964. // now allocate an item and put it into the menu so we can
  965. // allow the user to select an object from the class.
  966. TraceAssert(pName);
  967. TraceAssert(wcschr(pName, TEXT('-')) != NULL);
  968. *wcschr(pName, TEXT('-')) = L'\0'; // truncate at the - to give the class name
  969. ce.pName = NULL;
  970. ce.pDisplayName = NULL;
  971. ce.cReferences = 0;
  972. if ( *pName )
  973. {
  974. if ( FAILED(LocalAllocStringW(&ce.pName, pName)) ||
  975. FAILED(LocalAllocStringW2T(&ce.pDisplayName, pDisplayName)) ||
  976. ( -1 == DSA_AppendItem(ppw->hdsaClasses, &ce)) )
  977. {
  978. LocalFreeStringW(&ce.pName);
  979. LocalFreeString(&ce.pDisplayName);
  980. }
  981. }
  982. }
  983. }
  984. }
  985. hr = S_OK;
  986. exit_gracefully:
  987. LocalFreeStringW(&pName);
  988. LocalFreeStringW(&pDisplayName);
  989. if ( pDsQueryClassList )
  990. CoTaskMemFree(pDsQueryClassList);
  991. if ( hSearch )
  992. pds->CloseSearchHandle(hSearch);
  993. DoRelease(pQueryFrame);
  994. DoRelease(pds);
  995. PropertyWell_EnableControls(ppw, TRUE);
  996. ResetWaitCursor();
  997. TraceLeaveResult(hr);
  998. }
  999. /*-----------------------------------------------------------------------------
  1000. / PropertyWell_FreeClassList
  1001. / --------------------------
  1002. / Tidy up the class list by walking the DSA if we have one allocated
  1003. / and release all dangling elements.
  1004. /
  1005. / In:
  1006. / ppw -> property well structure
  1007. /
  1008. / Out:
  1009. / HRESULT
  1010. /----------------------------------------------------------------------------*/
  1011. INT _FreeClassListCB(LPVOID pItem, LPVOID pData)
  1012. {
  1013. LPCLASSENTRY pCE = (LPCLASSENTRY)pItem;
  1014. LocalFreeStringW(&pCE->pName);
  1015. LocalFreeString(&pCE->pDisplayName);
  1016. return 1;
  1017. }
  1018. VOID PropertyWell_FreeClassList(LPPROPERTYWELL ppw)
  1019. {
  1020. HRESULT hr;
  1021. TraceEnter(TRACE_PWELL, "PropertyWell_FreeClassList");
  1022. if ( ppw->hdsaClasses )
  1023. DSA_DestroyCallback(ppw->hdsaClasses, _FreeClassListCB, NULL);
  1024. ppw->hdsaClasses = NULL;
  1025. TraceLeave();
  1026. }
  1027. /*-----------------------------------------------------------------------------
  1028. / PropertyWell_FindClass
  1029. / ----------------------
  1030. / Find the class the caller wants. They give us a property well
  1031. / and a class name, we return them a class entry structure or NULL.
  1032. /
  1033. / In:
  1034. / ppw -> property well structure
  1035. / pObjectClass = class to locate
  1036. /
  1037. / Out:
  1038. / LPCLASSETNRY
  1039. /----------------------------------------------------------------------------*/
  1040. LPCLASSENTRY PropertyWell_FindClassEntry(LPPROPERTYWELL ppw, LPWSTR pObjectClass)
  1041. {
  1042. LPCLASSENTRY pResult = NULL;
  1043. INT i;
  1044. TraceEnter(TRACE_PWELL, "PropertyWell_FindClass");
  1045. if ( SUCCEEDED(PropertyWell_GetClassList(ppw)) )
  1046. {
  1047. for ( i = 0 ; i < DSA_GetItemCount(ppw->hdsaClasses) ; i++ )
  1048. {
  1049. LPCLASSENTRY pClassEntry = (LPCLASSENTRY)DSA_GetItemPtr(ppw->hdsaClasses, i);
  1050. TraceAssert(pClassEntry);
  1051. if ( !StrCmpIW(pClassEntry->pName, pObjectClass) )
  1052. {
  1053. pResult = pClassEntry;
  1054. break;
  1055. }
  1056. }
  1057. }
  1058. TraceLeaveValue(pResult);
  1059. }
  1060. /*-----------------------------------------------------------------------------
  1061. / Rule list helper functions
  1062. /----------------------------------------------------------------------------*/
  1063. /*-----------------------------------------------------------------------------
  1064. / PropertyWell_AddItem
  1065. / --------------------
  1066. / Add an item to the list of rules.
  1067. /
  1068. / In:
  1069. / ppw -> window defn to use
  1070. / pProperty = property name
  1071. / iCondition = id of condition to apply
  1072. / pValue = string value to compare against
  1073. /
  1074. / Out:
  1075. / HRESULT
  1076. /----------------------------------------------------------------------------*/
  1077. HRESULT PropertyWell_AddItem(LPPROPERTYWELL ppw, LPCLASSENTRY pClassEntry, LPWSTR pProperty, INT iCondition, LPWSTR pValue)
  1078. {
  1079. HRESULT hr;
  1080. INT item = -1;
  1081. LV_ITEM lvi;
  1082. LPPROPERTYWELLITEM pItem = NULL;
  1083. TCHAR szBuffer[80];
  1084. WCHAR szBufferW[80];
  1085. USES_CONVERSION;
  1086. TraceEnter(TRACE_PWELL, "PropertyWell_AddItem");
  1087. Trace(TEXT("Property: %s, Condition: %d, Value: %s"), W2T(pProperty), iCondition, W2T(pValue));
  1088. // Allocate an item structure to be stored into the list view DPA.
  1089. pItem = (LPPROPERTYWELLITEM)LocalAlloc(LPTR, SIZEOF(PROPERTYWELLITEM));
  1090. TraceAssert(pItem);
  1091. Trace(TEXT("pItem %0x8"), pItem);
  1092. if ( !pItem )
  1093. ExitGracefully(hr, E_OUTOFMEMORY, "Failed to allocate item");
  1094. pItem->pClassEntry = pClassEntry;
  1095. pClassEntry->cReferences += 1;
  1096. // pItem->pProperty = NULL;
  1097. // pItem->pValue = NULL;
  1098. pItem->iCondition = iCondition;
  1099. hr = LocalAllocStringW(&pItem->pProperty, pProperty);
  1100. FailGracefully(hr, "Failed to add property to DPA item");
  1101. if ( pValue && pValue[0] )
  1102. {
  1103. hr = LocalAllocStringW(&pItem->pValue, pValue);
  1104. FailGracefully(hr, "Failed to add value to DPA item");
  1105. }
  1106. // Add the item to the list view, lParam pItem structure we just allocated,
  1107. // therefore when calling delete we can tidy up accordingly
  1108. TraceAssert(ppw->pdds);
  1109. hr = GetFriendlyAttributeName(ppw->pdds, pClassEntry->pName, pProperty, szBufferW, ARRAYSIZE(szBufferW));
  1110. lvi.mask = LVIF_TEXT|LVIF_STATE|LVIF_PARAM;
  1111. lvi.iItem = 0x7fffffff;
  1112. lvi.iSubItem = 0;
  1113. lvi.state = LVIS_SELECTED;
  1114. lvi.stateMask = LVIS_SELECTED;
  1115. lvi.pszText = W2T(szBufferW);
  1116. lvi.lParam = (LPARAM)pItem;
  1117. item = ListView_InsertItem(ppw->hwndList, &lvi);
  1118. Trace(TEXT("item %d"), item);
  1119. if ( item < 0 )
  1120. ExitGracefully(hr, E_FAIL, "Failed to put item into list view");
  1121. LoadString(GLOBAL_HINSTANCE, conditions[iCondition].idsFilter, szBuffer, ARRAYSIZE(szBuffer));
  1122. ListView_SetItemText(ppw->hwndList, item, 1, szBuffer);
  1123. if ( pValue )
  1124. ListView_SetItemText(ppw->hwndList, item, 2, W2T(pValue));
  1125. DPA_InsertPtr(ppw->hdpaItems, item, pItem);
  1126. hr = S_OK; // succeeeded
  1127. exit_gracefully:
  1128. if ( FAILED(hr) && (item == -1) && pItem )
  1129. {
  1130. LocalFreeStringW(&pItem->pProperty);
  1131. LocalFreeStringW(&pItem->pValue);
  1132. LocalFree((HLOCAL)pItem);
  1133. }
  1134. if ( SUCCEEDED(hr) )
  1135. {
  1136. PropertyWell_ClearControls(ppw);
  1137. ListView_EnsureVisible(ppw->hwndList, item, FALSE);
  1138. PropertyWell_SetColumnWidths(ppw);
  1139. }
  1140. TraceLeaveResult(hr);
  1141. }
  1142. /*-----------------------------------------------------------------------------
  1143. / PropertyWell_RemoveItem
  1144. / -----------------------
  1145. / Remvoe the given item from the list. If fDeleteItem is true then we
  1146. / delete the list view entry, which in turn will call us again to
  1147. / remove the actual data from our DPA.
  1148. /
  1149. / In:
  1150. / ppw -> window defn to use
  1151. / iItem = item to be removed
  1152. / fDelelete = call ListView_DeleteItem
  1153. /
  1154. / Out:
  1155. / BOOL
  1156. /----------------------------------------------------------------------------*/
  1157. void PropertyWell_RemoveItem(LPPROPERTYWELL ppw, INT iItem, BOOL fDeleteItem)
  1158. {
  1159. INT item;
  1160. LV_ITEM lvi;
  1161. LPPROPERTYWELLITEM pItem;
  1162. TraceEnter(TRACE_PWELL, "PropertyWell_RemoveItem");
  1163. Trace(TEXT("iItem %d, fDeleteItem %s"), iItem, fDeleteItem ? TEXT("TRUE"):TEXT("FALSE"));
  1164. if ( ppw && (iItem >= 0) )
  1165. {
  1166. if ( fDeleteItem )
  1167. {
  1168. // Now delete the item from the view, note that as a result of this we will
  1169. // be called again (from the WM_NOTIFY handler) to tidy up the structure.
  1170. item = ListView_GetNextItem(ppw->hwndList, iItem, LVNI_BELOW);
  1171. if ( item == -1 )
  1172. item = ListView_GetNextItem(ppw->hwndList, iItem, LVNI_ABOVE);
  1173. if ( item != -1 )
  1174. {
  1175. ListView_SetItemState(ppw->hwndList, item, LVIS_SELECTED, LVIS_SELECTED);
  1176. ListView_EnsureVisible(ppw->hwndList, item, FALSE);
  1177. }
  1178. ListView_DeleteItem(ppw->hwndList, iItem);
  1179. PropertyWell_SetColumnWidths(ppw);
  1180. PropertyWell_EnableControls(ppw, TRUE);
  1181. }
  1182. else
  1183. {
  1184. // Get the item from that index in the DPA, release the memory that it
  1185. // owns and then release it.
  1186. pItem = (LPPROPERTYWELLITEM)DPA_FastGetPtr(ppw->hdpaItems, iItem);
  1187. TraceAssert(pItem);
  1188. if ( pItem )
  1189. {
  1190. pItem->pClassEntry->cReferences -= 1;
  1191. TraceAssert(pItem->pClassEntry->cReferences >= 0);
  1192. LocalFreeStringW(&pItem->pProperty);
  1193. LocalFreeStringW(&pItem->pValue);
  1194. LocalFree((HLOCAL)pItem);
  1195. DPA_DeletePtr(ppw->hdpaItems, iItem);
  1196. }
  1197. }
  1198. }
  1199. TraceLeave();
  1200. }
  1201. /*-----------------------------------------------------------------------------
  1202. / PropertyWell_EditItem
  1203. / ---------------------
  1204. / Edit the given item in the list. In doing so we remove from the list
  1205. / and populate the edit controls with data that represents this
  1206. / rule.
  1207. /
  1208. / In:
  1209. / ppw -> window defn to use
  1210. / iItem = item to edit
  1211. /
  1212. / Out:
  1213. / -
  1214. /----------------------------------------------------------------------------*/
  1215. void PropertyWell_EditItem(LPPROPERTYWELL ppw, INT iItem)
  1216. {
  1217. LPPROPERTYWELLITEM pItem;
  1218. USES_CONVERSION;
  1219. TraceEnter(TRACE_PWELL, "PropertyWell_EditItem");
  1220. if ( ppw && (iItem >= 0) )
  1221. {
  1222. LPPROPERTYWELLITEM pItem = (LPPROPERTYWELLITEM)DPA_FastGetPtr(ppw->hdpaItems, iItem);
  1223. TraceAssert(pItem);
  1224. PropertyWell_EditProperty(ppw, pItem->pClassEntry, pItem->pProperty, pItem->iCondition);
  1225. if ( pItem->pValue )
  1226. SetWindowText(ppw->hwndValue, W2T(pItem->pValue));
  1227. PropertyWell_RemoveItem(ppw, iItem, TRUE);
  1228. PropertyWell_EnableControls(ppw, TRUE);
  1229. }
  1230. TraceLeave();
  1231. }
  1232. /*-----------------------------------------------------------------------------
  1233. / PropertyWell_EditProperty
  1234. / -------------------------
  1235. / Set the property edit control and reflect that change into the
  1236. / other controls in the dialog (the conditions and editor).
  1237. /
  1238. / In:
  1239. / ppw -> property well
  1240. / pClassEntry -> class entry structure
  1241. / pPropertyName -> property name to edit
  1242. / iCondition = condition to select
  1243. /
  1244. / Out:
  1245. / void
  1246. /----------------------------------------------------------------------------*/
  1247. HRESULT PropertyWell_EditProperty(LPPROPERTYWELL ppw, LPCLASSENTRY pClassEntry, LPWSTR pPropertyName, INT iCondition)
  1248. {
  1249. HRESULT hr;
  1250. TCHAR szBuffer[MAX_PATH];
  1251. WCHAR szBufferW[MAX_PATH];
  1252. INT i, iItem, iCurSel = 0;
  1253. DWORD dwPropertyType;
  1254. USES_CONVERSION;
  1255. TraceEnter(TRACE_PWELL, "PropertyWell_EditProperty");
  1256. Trace(TEXT("Property name '%s', iCondition %d"), W2T(pPropertyName), iCondition);
  1257. // set the property name for this value, then look it up in the cache to get
  1258. // information about the operators we can apply.
  1259. ppw->pClassEntry = pClassEntry; // set state for the item we are editing
  1260. LocalFreeStringW(&ppw->pPropertyName);
  1261. hr = LocalAllocStringW(&ppw->pPropertyName, pPropertyName);
  1262. FailGracefully(hr, "Failed to alloc the property name");
  1263. TraceAssert(ppw->pdds);
  1264. GetFriendlyAttributeName(ppw->pdds, pClassEntry->pName, pPropertyName, szBufferW, ARRAYSIZE(szBufferW));
  1265. SetWindowText(ppw->hwndProperty, W2T(szBufferW));
  1266. ComboBox_ResetContent(ppw->hwndCondition);
  1267. SetWindowText(ppw->hwndValue, TEXT(""));
  1268. dwPropertyType = PropertyIsFromAttribute(pPropertyName, ppw->pdds);
  1269. for ( i = 0 ; i < ARRAYSIZE(conditions); i++ )
  1270. {
  1271. if ( conditions[i].dwPropertyType == dwPropertyType )
  1272. {
  1273. LoadString(GLOBAL_HINSTANCE, conditions[i].idsFilter, szBuffer, ARRAYSIZE(szBuffer));
  1274. iItem = ComboBox_AddString(ppw->hwndCondition, szBuffer);
  1275. if ( iItem >= 0 )
  1276. {
  1277. ComboBox_SetItemData(ppw->hwndCondition, iItem, i); // i == condition index
  1278. if ( i == iCondition )
  1279. {
  1280. Trace(TEXT("Setting current selection to %d"), iItem);
  1281. iCurSel = iItem;
  1282. }
  1283. }
  1284. }
  1285. }
  1286. ComboBox_SetCurSel(ppw->hwndCondition, iCurSel);
  1287. SetWindowText(ppw->hwndValue, TEXT(""));
  1288. hr = S_OK;
  1289. exit_gracefully:
  1290. TraceLeaveResult(hr);
  1291. }
  1292. /*-----------------------------------------------------------------------------
  1293. / PropertyWell_EnableControls
  1294. / ---------------------------
  1295. / Check the controls within the view and determine what controls
  1296. / should be enabled within it. If fDisable == TRUE then disable all the
  1297. / controls in the dialog regardless of the dependancies on other controls.
  1298. /
  1299. / The return value indicates if the control sare in a state whereby
  1300. / we can add the criteria to the query.
  1301. /
  1302. / In:
  1303. / ppw -> window defn to use
  1304. / fEnable = FALSE then disable all controls in dialog
  1305. /
  1306. / Out:
  1307. / BOOL
  1308. /----------------------------------------------------------------------------*/
  1309. BOOL PropertyWell_EnableControls(LPPROPERTYWELL ppw, BOOL fEnable)
  1310. {
  1311. BOOL fEnableCondition = FALSE;
  1312. BOOL fEnableValue = FALSE;
  1313. BOOL fEnableAdd = FALSE;
  1314. BOOL fEnableRemove = FALSE;
  1315. INT iCondition;
  1316. DWORD dwButtonStyle;
  1317. HWND hWndParent;
  1318. TraceEnter(TRACE_PWELL, "PropertyWell_EnableControls");
  1319. EnableWindow(ppw->hwndPropertyLabel, fEnable);
  1320. EnableWindow(ppw->hwndProperty, fEnable);
  1321. EnableWindow(ppw->hwndList, fEnable);
  1322. if ( fEnable )
  1323. {
  1324. fEnableCondition = (ppw->pPropertyName != NULL);
  1325. if ( fEnableCondition )
  1326. {
  1327. iCondition = CONDITION_FROM_COMBO(ppw->hwndCondition);
  1328. fEnableValue = !conditions[iCondition].fNoValue;
  1329. if ( !fEnableValue || GetWindowTextLength(ppw->hwndValue) )
  1330. fEnableAdd = TRUE;
  1331. }
  1332. if ( ListView_GetSelectedCount(ppw->hwndList) &&
  1333. ( -1 != ListView_GetNextItem(ppw->hwndList, -1, LVNI_SELECTED|LVNI_ALL)) )
  1334. {
  1335. fEnableRemove = TRUE;
  1336. }
  1337. }
  1338. if ( !fEnableAdd && !fEnableValue )
  1339. {
  1340. dwButtonStyle = (DWORD) GetWindowLong(ppw->hwndAdd, GWL_STYLE);
  1341. if (dwButtonStyle & BS_DEFPUSHBUTTON)
  1342. {
  1343. SendMessage(ppw->hwndAdd, BM_SETSTYLE, MAKEWPARAM(BS_PUSHBUTTON, 0), MAKELPARAM(TRUE, 0));
  1344. hWndParent = GetParent(ppw->hwnd);
  1345. if (hWndParent)
  1346. {
  1347. SendDlgItemMessage(hWndParent, CQID_FINDNOW, BM_SETSTYLE, MAKEWPARAM(BS_DEFPUSHBUTTON, 0), MAKELPARAM(TRUE, 0));
  1348. SetFocus(GetDlgItem(hWndParent, CQID_FINDNOW));
  1349. }
  1350. }
  1351. }
  1352. if (!fEnableRemove) {
  1353. dwButtonStyle = (DWORD) GetWindowLong(ppw->hwndRemove, GWL_STYLE);
  1354. if (dwButtonStyle & BS_DEFPUSHBUTTON) {
  1355. SendMessage(
  1356. ppw->hwndRemove,
  1357. BM_SETSTYLE,
  1358. MAKEWPARAM(BS_PUSHBUTTON, 0),
  1359. MAKELPARAM(TRUE, 0)
  1360. );
  1361. hWndParent = GetParent(ppw->hwnd);
  1362. if (hWndParent) {
  1363. SendDlgItemMessage(
  1364. hWndParent,
  1365. CQID_FINDNOW,
  1366. BM_SETSTYLE,
  1367. MAKEWPARAM(BS_DEFPUSHBUTTON, 0),
  1368. MAKELPARAM(TRUE, 0)
  1369. );
  1370. SetFocus(GetDlgItem(hWndParent, CQID_FINDNOW));
  1371. }
  1372. }
  1373. }
  1374. EnableWindow(ppw->hwndConditionLabel, fEnableCondition);
  1375. EnableWindow(ppw->hwndCondition, fEnableCondition);
  1376. EnableWindow(ppw->hwndValueLabel, fEnableValue);
  1377. EnableWindow(ppw->hwndValue, fEnableValue);
  1378. EnableWindow(ppw->hwndAdd, fEnableAdd);
  1379. EnableWindow(ppw->hwndRemove, fEnableRemove);
  1380. if ( fEnableAdd )
  1381. SetDefButton(ppw->hwnd, IDC_ADD);
  1382. TraceLeaveValue(fEnableAdd);
  1383. }
  1384. /*-----------------------------------------------------------------------------
  1385. / PropertyWell_ClearControls
  1386. / --------------------------
  1387. / Zap the contents of the edit controls.
  1388. /
  1389. / In:
  1390. / ppw -> window defn to use
  1391. /
  1392. / Out:
  1393. / BOOL
  1394. /----------------------------------------------------------------------------*/
  1395. VOID PropertyWell_ClearControls(LPPROPERTYWELL ppw)
  1396. {
  1397. TraceEnter(TRACE_PWELL, "PropertyWell_ClearControls");
  1398. LocalFreeStringW(&ppw->pPropertyName);
  1399. SetWindowText(ppw->hwndProperty, TEXT(""));
  1400. ComboBox_ResetContent(ppw->hwndCondition);
  1401. SetWindowText(ppw->hwndValue, TEXT(""));
  1402. PropertyWell_EnableControls(ppw, TRUE);
  1403. TraceLeave();
  1404. }
  1405. /*-----------------------------------------------------------------------------
  1406. / PropertyWell_SetColumnWidths
  1407. / ----------------------------
  1408. / Fix the widths of the columns in the list view section of the property
  1409. / well so that the most is visible.
  1410. /
  1411. / In:
  1412. / ppw -> window defn to use
  1413. /
  1414. / Out:
  1415. / -
  1416. /----------------------------------------------------------------------------*/
  1417. VOID PropertyWell_SetColumnWidths(LPPROPERTYWELL ppw)
  1418. {
  1419. RECT rect2;
  1420. INT cx;
  1421. TraceEnter(TRACE_PWELL, "PropertyWell_SetColumnWidths");
  1422. GetClientRect(ppw->hwndList, &rect2);
  1423. InflateRect(&rect2, -GetSystemMetrics(SM_CXBORDER)*2, 0);
  1424. cx = MulDiv((rect2.right - rect2.left), 20, 100);
  1425. ListView_SetColumnWidth(ppw->hwndList, 0, cx);
  1426. ListView_SetColumnWidth(ppw->hwndList, 1, cx);
  1427. ListView_SetColumnWidth(ppw->hwndList, 2, rect2.right - (cx*2));
  1428. TraceLeave();
  1429. }
  1430. /*-----------------------------------------------------------------------------
  1431. / PropertyWell_GetQuery
  1432. / ---------------------
  1433. / Take the items in the property well and construct a query from them,
  1434. / the query is an AND of all the fields present in the list. The conditon
  1435. / table in lists the prefix, condition and postfix for each of the possible
  1436. / conditions in the combo box.
  1437. /
  1438. / In:
  1439. / ppw -> property well to construct from
  1440. / ppQuery -> receives the query string
  1441. /
  1442. / Out:
  1443. / HRESULT
  1444. /----------------------------------------------------------------------------*/
  1445. static void _GetQuery(LPPROPERTYWELL ppw, LPWSTR pQuery, UINT* pLen)
  1446. {
  1447. INT i;
  1448. USES_CONVERSION;
  1449. TraceEnter(TRACE_PWELL, "_GetQuery");
  1450. if ( pQuery )
  1451. *pQuery = TEXT('\0');
  1452. TraceAssert(ppw->hdsaClasses);
  1453. TraceAssert(ppw->hdpaItems);
  1454. for ( i = 0 ; i < DSA_GetItemCount(ppw->hdsaClasses); i++ )
  1455. {
  1456. LPCLASSENTRY pClassEntry = (LPCLASSENTRY)DSA_GetItemPtr(ppw->hdsaClasses, i);
  1457. TraceAssert(pClassEntry);
  1458. if ( pClassEntry->cReferences )
  1459. {
  1460. Trace(TEXT("Class %s referenced %d times"), W2T(pClassEntry->pName), pClassEntry->cReferences);
  1461. GetFilterString(pQuery, pLen, FILTER_IS, L"objectCategory", pClassEntry->pName);
  1462. }
  1463. }
  1464. for ( i = 0 ; i < DPA_GetPtrCount(ppw->hdpaItems); i++ )
  1465. {
  1466. LPPROPERTYWELLITEM pItem = (LPPROPERTYWELLITEM)DPA_FastGetPtr(ppw->hdpaItems, i);
  1467. TraceAssert(pItem);
  1468. GetFilterString(pQuery, pLen, conditions[pItem->iCondition].iFilter, pItem->pProperty, pItem->pValue);
  1469. }
  1470. TraceLeave();
  1471. }
  1472. HRESULT PropertyWell_GetQuery(LPPROPERTYWELL ppw, LPWSTR* ppQuery)
  1473. {
  1474. HRESULT hr;
  1475. UINT cchQuery = 0;
  1476. USES_CONVERSION;
  1477. TraceEnter(TRACE_PWELL, "PropertyWell_GetQuery");
  1478. *ppQuery = NULL;
  1479. hr = PropertyWell_GetClassList(ppw);
  1480. FailGracefully(hr, "Failed to get the class list");
  1481. _GetQuery(ppw, NULL, &cchQuery);
  1482. Trace(TEXT("cchQuery %d"), cchQuery);
  1483. if ( cchQuery )
  1484. {
  1485. hr = LocalAllocStringLenW(ppQuery, cchQuery);
  1486. FailGracefully(hr, "Failed to allocate buffer for query string");
  1487. _GetQuery(ppw, *ppQuery, NULL);
  1488. Trace(TEXT("Resulting query is %s"), W2T(*ppQuery));
  1489. }
  1490. hr = S_OK;
  1491. exit_gracefully:
  1492. TraceLeaveResult(hr);
  1493. }
  1494. /*-----------------------------------------------------------------------------
  1495. / PropertyWell_Persist
  1496. / --------------------
  1497. / Persist the contents of the property well, either read them or write
  1498. / them depending on the given flag.
  1499. /
  1500. / In:
  1501. / ppw -> property well to work with
  1502. / pPersistQuery -> IPersistQuery structure to work with
  1503. / fRead = read or write
  1504. /
  1505. / Out:
  1506. / HRESULT
  1507. /----------------------------------------------------------------------------*/
  1508. HRESULT PropertyWell_Persist(LPPROPERTYWELL ppw, IPersistQuery* pPersistQuery, BOOL fRead)
  1509. {
  1510. HRESULT hr;
  1511. LPPROPERTYWELLITEM pItem;
  1512. TCHAR szBuffer[80];
  1513. INT iItems;
  1514. INT i;
  1515. USES_CONVERSION;
  1516. TraceEnter(TRACE_PWELL, "PropertyWell_Persist");
  1517. if ( !pPersistQuery )
  1518. ExitGracefully(hr, E_INVALIDARG, "No persist object");
  1519. if ( fRead )
  1520. {
  1521. // Read the items from the IPersistQuery object, first get the number of items
  1522. // we need to get back. Then loop through them all getting the property, condition
  1523. // and value.
  1524. hr = pPersistQuery->ReadInt(c_szMsPropertyWell, c_szItems, &iItems);
  1525. FailGracefully(hr, "Failed to get item count");
  1526. Trace(TEXT("Attempting to read %d items"), iItems);
  1527. for ( i = 0 ; i < iItems ; i++ )
  1528. {
  1529. LPCLASSENTRY pClassEntry;
  1530. TCHAR szObjectClass[MAX_PATH];
  1531. TCHAR szProperty[MAX_PATH];
  1532. TCHAR szValue[MAX_PATH];
  1533. INT iCondition;
  1534. wsprintf(szBuffer, c_szObjectClassN, i);
  1535. hr = pPersistQuery->ReadString(c_szMsPropertyWell, szBuffer, szObjectClass, ARRAYSIZE(szObjectClass));
  1536. FailGracefully(hr, "Failed to read object class");
  1537. pClassEntry = PropertyWell_FindClassEntry(ppw, T2W(szObjectClass));
  1538. TraceAssert(pClassEntry);
  1539. if ( !pClassEntry )
  1540. ExitGracefully(hr, E_FAIL, "Failed to get objectClass / map to available class");
  1541. wsprintf(szBuffer, c_szProperty, i);
  1542. hr = pPersistQuery->ReadString(c_szMsPropertyWell, szBuffer, szProperty, ARRAYSIZE(szProperty));
  1543. FailGracefully(hr, "Failed to read property");
  1544. wsprintf(szBuffer, c_szCondition, i);
  1545. hr = pPersistQuery->ReadInt(c_szMsPropertyWell, szBuffer, &iCondition);
  1546. FailGracefully(hr, "Failed to write condition");
  1547. wsprintf(szBuffer, c_szValue, i);
  1548. if ( FAILED(pPersistQuery->ReadString(c_szMsPropertyWell, szBuffer, szValue, ARRAYSIZE(szValue))) )
  1549. {
  1550. TraceMsg("No value defined in incoming stream");
  1551. szValue[0] = TEXT('\0');
  1552. }
  1553. hr = PropertyWell_AddItem(ppw, pClassEntry, T2W(szProperty), iCondition, T2W(szValue));
  1554. FailGracefully(hr, "Failed to add search criteria to query");
  1555. }
  1556. }
  1557. else
  1558. {
  1559. // Write the content of the property well out, store the items then for
  1560. // each store Condition%d, Value%d, Property%d.
  1561. iItems = DPA_GetPtrCount(ppw->hdpaItems);
  1562. Trace(TEXT("Attempting to store %d items"), iItems);
  1563. hr = pPersistQuery->WriteInt(c_szMsPropertyWell, c_szItems, iItems);
  1564. FailGracefully(hr, "Failed to write item count");
  1565. for ( i = 0 ; i < iItems ; i++ )
  1566. {
  1567. pItem = (LPPROPERTYWELLITEM)DPA_FastGetPtr(ppw->hdpaItems, i);
  1568. wsprintf(szBuffer, c_szObjectClassN, i);
  1569. hr = pPersistQuery->WriteString(c_szMsPropertyWell, szBuffer, W2T(pItem->pClassEntry->pName));
  1570. FailGracefully(hr, "Failed to write property");
  1571. wsprintf(szBuffer, c_szProperty, i);
  1572. hr = pPersistQuery->WriteString(c_szMsPropertyWell, szBuffer, W2T(pItem->pProperty));
  1573. FailGracefully(hr, "Failed to write property");
  1574. wsprintf(szBuffer, c_szCondition, i);
  1575. hr = pPersistQuery->WriteInt(c_szMsPropertyWell, szBuffer, pItem->iCondition);
  1576. FailGracefully(hr, "Failed to write condition");
  1577. if ( pItem->pValue )
  1578. {
  1579. wsprintf(szBuffer, c_szValue, i);
  1580. hr = pPersistQuery->WriteString(c_szMsPropertyWell, szBuffer, W2T(pItem->pValue));
  1581. FailGracefully(hr, "Failed to write value");
  1582. }
  1583. }
  1584. }
  1585. hr = S_OK;
  1586. exit_gracefully:
  1587. TraceLeaveResult(hr);
  1588. }