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.

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