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.

2065 lines
55 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // DS Administration MMC snapin.
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1999
  7. //
  8. // File: queryui.cpp
  9. //
  10. //--------------------------------------------------------------------------
  11. #include "stdafx.h"
  12. #include "resource.h"
  13. #include "queryui.h"
  14. #include "dssnap.h"
  15. #include "uiutil.h"
  16. #include <cmnquery.h> // DSFind
  17. #include <dsquery.h> // DSFind
  18. #include <dsclient.h> // BrowseForContainer
  19. #include <dsqueryp.h> // COLUMNINFO and QueryParamsAddQueryString, QueryParamsAlloc helpers
  20. #include <cmnquryp.h> // CQFF_ISNEVERLISTED
  21. #include <lmaccess.h> // UF_ACCOUNTDISABLE and UF_DONT_EXPIRE_PASSWD
  22. #include <ntldap.h> // LDAP_MATCHING_RULE_BIT_AND_W
  23. #include "ldaputil.h" // LdapEscape().
  24. #define DSQF_LAST_LOGON_QUERY 0x00000001
  25. #define DSQF_NON_EXPIRING_PWD_QUERY 0x00000004
  26. //
  27. // Used to set the maximum text length on fields in the new query dialog
  28. //
  29. #define MAX_QUERY_NAME_LENGTH 259
  30. #define MAX_QUERY_DESC_LENGTH 1024
  31. typedef struct
  32. {
  33. UINT nDisplayStringID;
  34. PWSTR pszFormatString;
  35. } QUERYSTRINGS, * PQUERYSTRINGS;
  36. QUERYSTRINGS g_pQueryStrings[] = {
  37. { IDS_STARTSWITH, L"(%s=%s*)" },
  38. { IDS_ENDSWITH, L"(%s=*%s)" },
  39. { IDS_ISEXACTLY, L"(%s=%s)" },
  40. { IDS_ISNOT, L"(!%s=%s)" },
  41. { IDS_PRESENT, L"(%s=%s*)" }, // NOTE: the second string needs to be NULL here
  42. { IDS_NOTPRESENT, L"(!%s=%s*)" }, // NOTE: the second string needs to be NULL here
  43. { 0, NULL }
  44. };
  45. static const CString g_szUserAccountCtrlQuery = L"(userAccountControl:" + CString(LDAP_MATCHING_RULE_BIT_AND_W) + L":=%u)";
  46. /*-----------------------------------------------------------------------------
  47. / QueryParamsAlloc
  48. / ----------------
  49. / Construct a block we can pass to the DS query handler which contains
  50. / all the parameters for the query.
  51. /
  52. / In:
  53. / ppDsQueryParams -> receives the parameter block
  54. / pQuery -> LDAP query string to be used
  55. / iColumns = number of columns
  56. / pColumnInfo -> column info structure to use
  57. /
  58. / Out:
  59. / HRESULT
  60. /----------------------------------------------------------------------------*/
  61. HRESULT QueryParamsAlloc(LPDSQUERYPARAMS* ppDsQueryParams, LPWSTR pQuery, LONG iColumns, LPCOLUMNINFO aColumnInfo)
  62. {
  63. HRESULT hr = S_OK;
  64. LPDSQUERYPARAMS pDsQueryParams = NULL;
  65. size_t cbStruct;
  66. LONG i;
  67. ASSERT(!*ppDsQueryParams);
  68. TRACE(L"QueryParamsAlloc");
  69. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  70. if ( !pQuery || !iColumns || !ppDsQueryParams )
  71. {
  72. return E_INVALIDARG;
  73. }
  74. //
  75. // Compute the size of the structure we need to be using
  76. //
  77. cbStruct = sizeof(DSQUERYPARAMS) + (sizeof(DSCOLUMN)*iColumns);
  78. cbStruct += (wcslen(pQuery) + 1) * sizeof(WCHAR);
  79. for (i = 0; i < iColumns; i++)
  80. {
  81. if (aColumnInfo[i].pPropertyName)
  82. {
  83. cbStruct += (wcslen(aColumnInfo[i].pPropertyName) + 1) * sizeof(WCHAR);
  84. }
  85. }
  86. pDsQueryParams = (LPDSQUERYPARAMS)CoTaskMemAlloc(cbStruct);
  87. if (!pDsQueryParams)
  88. {
  89. return E_OUTOFMEMORY;
  90. }
  91. //
  92. // Structure allocated so lets fill it with data
  93. //
  94. pDsQueryParams->cbStruct = static_cast<DWORD>(cbStruct);
  95. pDsQueryParams->dwFlags = 0;
  96. pDsQueryParams->hInstance = _Module.m_hInst;
  97. pDsQueryParams->iColumns = iColumns;
  98. pDsQueryParams->dwReserved = 0;
  99. cbStruct = sizeof(DSQUERYPARAMS) + (sizeof(DSCOLUMN)*iColumns);
  100. pDsQueryParams->offsetQuery = static_cast<LONG>(cbStruct);
  101. CopyMemory(&(((LPBYTE)pDsQueryParams)[cbStruct]), pQuery, (wcslen(pQuery) + 1) * sizeof(WCHAR));
  102. cbStruct += (wcslen(pQuery) + 1) * sizeof(WCHAR);
  103. for ( i = 0 ; i < iColumns ; i++ )
  104. {
  105. pDsQueryParams->aColumns[i].dwFlags = 0;
  106. pDsQueryParams->aColumns[i].fmt = aColumnInfo[i].fmt;
  107. pDsQueryParams->aColumns[i].cx = aColumnInfo[i].cx;
  108. pDsQueryParams->aColumns[i].idsName = aColumnInfo[i].idsName;
  109. pDsQueryParams->aColumns[i].dwReserved = 0;
  110. if ( aColumnInfo[i].pPropertyName )
  111. {
  112. pDsQueryParams->aColumns[i].offsetProperty = static_cast<LONG>(cbStruct);
  113. CopyMemory(&(((LPBYTE)pDsQueryParams)[cbStruct]), aColumnInfo[i].pPropertyName, (wcslen(aColumnInfo[i].pPropertyName) + 1) * sizeof(WCHAR));
  114. cbStruct += (wcslen(aColumnInfo[i].pPropertyName) + 1) * sizeof(WCHAR);
  115. }
  116. else
  117. {
  118. pDsQueryParams->aColumns[i].offsetProperty = aColumnInfo[i].iPropertyIndex;
  119. }
  120. }
  121. *ppDsQueryParams = pDsQueryParams;
  122. return hr;
  123. }
  124. /*-----------------------------------------------------------------------------
  125. / QueryParamsAddQueryString
  126. / -------------------------
  127. / Given an existing DS query block appened the given LDAP query string into
  128. / it. We assume that the query block has been allocated by IMalloc (or CoTaskMemAlloc).
  129. /
  130. / In:
  131. / ppDsQueryParams -> receives the parameter block
  132. / pQuery -> LDAP query string to be appended
  133. /
  134. / Out:
  135. / HRESULT
  136. /----------------------------------------------------------------------------*/
  137. HRESULT QueryParamsAddQueryString(LPDSQUERYPARAMS* ppDsQueryParams, LPWSTR pQuery)
  138. {
  139. HRESULT hr = S_OK;
  140. LPWSTR pOriginalQuery = NULL;
  141. LPDSQUERYPARAMS pDsQuery = *ppDsQueryParams;
  142. size_t cbQuery;
  143. LONG i;
  144. LPVOID pv;
  145. //NTRAID#NTBUG9-567482-2002/03/10-jmessec Assertion not backed up by code (well, sorta is below in checking pDsQuery, but not obvious)
  146. ASSERT(*ppDsQueryParams);
  147. TRACE(_T("QueryParamsAddQueryString"));
  148. if ( pQuery )
  149. {
  150. if (!pDsQuery)
  151. {
  152. return E_INVALIDARG;
  153. }
  154. // Work out the size of the bits we are adding, take a copy of the
  155. // query string and finally re-alloc the query block (which may cause it
  156. // to move).
  157. cbQuery = ((wcslen(pQuery) + 1) * sizeof(WCHAR));
  158. TRACE(_T("DSQUERYPARAMS being resized by %d bytes"));
  159. i = static_cast<LONG>((wcslen((LPWSTR)ByteOffset(pDsQuery, pDsQuery->offsetQuery)) + 1) * sizeof(WCHAR));
  160. pOriginalQuery = (WCHAR*) new BYTE[i];
  161. if (!pOriginalQuery)
  162. {
  163. return E_OUTOFMEMORY;
  164. }
  165. lstrcpyW(pOriginalQuery, (LPWSTR)ByteOffset(pDsQuery, pDsQuery->offsetQuery));
  166. pv = CoTaskMemRealloc(*ppDsQueryParams, pDsQuery->cbStruct+cbQuery);
  167. if ( pv == NULL )
  168. {
  169. delete[] pOriginalQuery;
  170. pOriginalQuery = 0;
  171. return E_OUTOFMEMORY;
  172. }
  173. *ppDsQueryParams = (LPDSQUERYPARAMS) pv;
  174. pDsQuery = *ppDsQueryParams; // if may have moved
  175. // Now move everything above the query string up, and fix all the
  176. // offsets that reference those items (probably the property table),
  177. // finally adjust the size to reflect the change
  178. MoveMemory(ByteOffset(pDsQuery, pDsQuery->offsetQuery+cbQuery),
  179. ByteOffset(pDsQuery, pDsQuery->offsetQuery),
  180. (pDsQuery->cbStruct - pDsQuery->offsetQuery));
  181. for ( i = 0 ; i < pDsQuery->iColumns ; i++ )
  182. {
  183. if ( pDsQuery->aColumns[i].offsetProperty > pDsQuery->offsetQuery )
  184. {
  185. pDsQuery->aColumns[i].offsetProperty += static_cast<LONG>(cbQuery);
  186. }
  187. }
  188. //NTRAID#NTBUG9-572009-2002/03/10-jmessec It appears that your struct is one sizeof(WCHAR) too large now, since
  189. //you allocated enough extra for a whole other string, including terminating NULL,
  190. //but you are appending the strings, thus eating a NULL; could this fowl up later
  191. //struct size calculations and offsets?
  192. wcscpy((LPWSTR)ByteOffset(pDsQuery, pDsQuery->offsetQuery), pOriginalQuery);
  193. wcscat((LPWSTR)ByteOffset(pDsQuery, pDsQuery->offsetQuery), pQuery);
  194. pDsQuery->cbStruct += static_cast<DWORD>(cbQuery);
  195. delete[] pOriginalQuery;
  196. pOriginalQuery = 0;
  197. }
  198. return hr;
  199. }
  200. ///////////////////////////////////////////////////////////////////////////////
  201. // AddQueryUnitWithModifier
  202. HRESULT AddQueryUnitWithModifier(UINT nModifierStringID,
  203. PCWSTR pszAttrName,
  204. PCWSTR pszValue,
  205. CString& szFilter)
  206. {
  207. HRESULT hr = S_OK;
  208. ASSERT(pszAttrName != NULL);
  209. if (pszAttrName == NULL)
  210. {
  211. return E_INVALIDARG;
  212. }
  213. // Escape special characters used in LDAP from the value the
  214. // user entered.
  215. wstring escapedValue;
  216. LdapEscape(
  217. pszValue != NULL ? pszValue : L"",
  218. escapedValue);
  219. CString szNewFilter;
  220. PQUERYSTRINGS pQueryStrings = g_pQueryStrings;
  221. PWSTR pszFormatString = NULL;
  222. while (pQueryStrings->nDisplayStringID != 0)
  223. {
  224. if (nModifierStringID == pQueryStrings->nDisplayStringID)
  225. {
  226. pszFormatString = pQueryStrings->pszFormatString;
  227. break;
  228. }
  229. pQueryStrings++;
  230. }
  231. if (pszFormatString != NULL)
  232. {
  233. szNewFilter.Format(pszFormatString, pszAttrName, escapedValue.c_str());
  234. szFilter += szNewFilter;
  235. }
  236. else
  237. {
  238. hr = E_INVALIDARG;
  239. }
  240. return hr;
  241. }
  242. ///////////////////////////////////////////////////////////////////////////////
  243. // CQueryPageBase
  244. BEGIN_MESSAGE_MAP(CQueryPageBase, CHelpDialog)
  245. END_MESSAGE_MAP()
  246. ///////////////////////////////////////////////////////////////////////////////
  247. // CStdQueryPage
  248. #define FILTER_PREFIX_USER L"(objectCategory=person)(objectClass=user)"
  249. #define FILTER_PREFIX_COMPUTER L"(objectCategory=computer)"
  250. #define FILTER_PREFIX_GROUP L"(objectCategory=group)"
  251. #define ATTR_COL_NAME L"name"
  252. #define ATTR_COL_DESC L"description"
  253. COLUMNINFO UserColumn[] =
  254. {
  255. { 0, 40, IDS_QUERY_COL_NAME, 0, ATTR_COL_NAME },
  256. { 0, 40, IDS_QUERY_COL_DESC, 0, ATTR_COL_DESC }
  257. };
  258. int cUserColumns = 2;
  259. BEGIN_MESSAGE_MAP(CStdQueryPage, CQueryPageBase)
  260. ON_CBN_SELCHANGE(IDC_NAME_COMBO, OnNameComboChange)
  261. ON_CBN_SELCHANGE(IDC_DESCRIPTION_COMBO, OnDescriptionComboChange)
  262. END_MESSAGE_MAP()
  263. void CStdQueryPage::DoContextHelp(HWND hWndControl)
  264. {
  265. if (hWndControl)
  266. {
  267. ::WinHelp(hWndControl,
  268. DSADMIN_CONTEXT_HELP_FILE,
  269. HELP_WM_HELP,
  270. (DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_QUERY_STD_PAGE);
  271. }
  272. }
  273. BOOL CStdQueryPage::OnInitDialog()
  274. {
  275. CHelpDialog::OnInitDialog();
  276. PQUERYSTRINGS pQueryStrings = g_pQueryStrings;
  277. ASSERT(pQueryStrings != NULL);
  278. //
  279. // Fill in the combo boxes
  280. //
  281. while (pQueryStrings->nDisplayStringID != 0)
  282. {
  283. CString szComboString;
  284. VERIFY(szComboString.LoadString(pQueryStrings->nDisplayStringID));
  285. //
  286. // Fill in the Name combo
  287. //
  288. LRESULT lRes = SendDlgItemMessage(IDC_NAME_COMBO, CB_ADDSTRING, 0, (LPARAM)(PCWSTR)szComboString);
  289. if (lRes != CB_ERR)
  290. {
  291. lRes = SendDlgItemMessage(IDC_NAME_COMBO, CB_SETITEMDATA, (WPARAM)lRes, (LPARAM)pQueryStrings->nDisplayStringID);
  292. ASSERT(lRes != CB_ERR);
  293. }
  294. //
  295. // Fill in the Description combo
  296. //
  297. lRes = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_ADDSTRING, 0, (LPARAM)(PCWSTR)szComboString);
  298. if (lRes != CB_ERR)
  299. {
  300. lRes = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_SETITEMDATA, (WPARAM)lRes, (LPARAM)pQueryStrings->nDisplayStringID);
  301. ASSERT(lRes != CB_ERR);
  302. }
  303. pQueryStrings++;
  304. }
  305. //
  306. // Insert an empty so that there is a way to undo changes
  307. //
  308. LRESULT lBlankName = SendDlgItemMessage(IDC_NAME_COMBO, CB_ADDSTRING, 0, (LPARAM)L"");
  309. if (lBlankName != CB_ERR)
  310. {
  311. SendDlgItemMessage(IDC_NAME_COMBO, CB_SETITEMDATA, (WPARAM)lBlankName, (LPARAM)0);
  312. }
  313. //
  314. // Insert an empty so that there is a way to undo changes
  315. //
  316. LRESULT lBlankDesc = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_ADDSTRING, 0, (LPARAM)L"");
  317. if (lBlankDesc != CB_ERR)
  318. {
  319. SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_SETITEMDATA, (WPARAM)lBlankDesc, (LPARAM)0);
  320. }
  321. //
  322. // Force the UI to enable and disable controls related to the combo boxes
  323. //
  324. OnNameComboChange();
  325. OnDescriptionComboChange();
  326. return FALSE;
  327. }
  328. void CStdQueryPage::OnNameComboChange()
  329. {
  330. LRESULT lRes = SendDlgItemMessage(IDC_NAME_COMBO, CB_GETCURSEL, 0, 0);
  331. if (lRes != CB_ERR)
  332. {
  333. LRESULT lData = SendDlgItemMessage(IDC_NAME_COMBO, CB_GETITEMDATA, lRes, 0);
  334. if (lData != CB_ERR)
  335. {
  336. if (lData == IDS_PRESENT || lData == IDS_NOTPRESENT || lData == 0)
  337. {
  338. GetDlgItem(IDC_NAME_EDIT)->EnableWindow(FALSE);
  339. SetDlgItemText(IDC_NAME_EDIT, L"");
  340. }
  341. else
  342. {
  343. GetDlgItem(IDC_NAME_EDIT)->EnableWindow(TRUE);
  344. }
  345. }
  346. }
  347. else
  348. {
  349. GetDlgItem(IDC_NAME_EDIT)->EnableWindow(FALSE);
  350. }
  351. }
  352. void CStdQueryPage::OnDescriptionComboChange()
  353. {
  354. LRESULT lRes = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_GETCURSEL, 0, 0);
  355. if (lRes != CB_ERR)
  356. {
  357. LRESULT lData = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_GETITEMDATA, lRes, 0);
  358. if (lData != CB_ERR)
  359. {
  360. if (lData == IDS_PRESENT || lData == IDS_NOTPRESENT || lData == 0)
  361. {
  362. GetDlgItem(IDC_DESCRIPTION_EDIT)->EnableWindow(FALSE);
  363. SetDlgItemText(IDC_DESCRIPTION_EDIT, L"");
  364. }
  365. else
  366. {
  367. GetDlgItem(IDC_DESCRIPTION_EDIT)->EnableWindow(TRUE);
  368. }
  369. }
  370. }
  371. else
  372. {
  373. GetDlgItem(IDC_DESCRIPTION_EDIT)->EnableWindow(FALSE);
  374. }
  375. }
  376. void CStdQueryPage::Init()
  377. {
  378. //
  379. // Clear all controls
  380. //
  381. SetDlgItemText(IDC_NAME_EDIT, L"");
  382. SetDlgItemText(IDC_DESCRIPTION_EDIT, L"");
  383. //
  384. // Reselect the blank string in the combo boxes
  385. //
  386. LRESULT lRes = SendDlgItemMessage(IDC_NAME_COMBO, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)L"");
  387. if (lRes != CB_ERR)
  388. {
  389. SendDlgItemMessage(IDC_NAME_COMBO, CB_SETCURSEL, lRes, 0);
  390. }
  391. lRes = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)L"");
  392. if (lRes != CB_ERR)
  393. {
  394. SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_SETCURSEL, lRes, 0);
  395. }
  396. }
  397. HRESULT CStdQueryPage::GetQueryParams(LPDSQUERYPARAMS* ppDsQueryParams)
  398. {
  399. HRESULT hr = S_OK;
  400. //
  401. // Build the filter string here
  402. //
  403. CString szFilter;
  404. CString szName;
  405. CString szDescription;
  406. GetDlgItemText(IDC_NAME_EDIT, szName);
  407. GetDlgItemText(IDC_DESCRIPTION_EDIT, szDescription);
  408. //
  409. // Get the selection of the modifier combo
  410. //
  411. LRESULT lSel = SendDlgItemMessage(IDC_NAME_COMBO, CB_GETCURSEL, 0, 0);
  412. if (lSel != CB_ERR)
  413. {
  414. //
  415. // Retrieve the associated string ID
  416. //
  417. LRESULT lData = SendDlgItemMessage(IDC_NAME_COMBO, CB_GETITEMDATA, lSel, 0);
  418. if (lData != CB_ERR)
  419. {
  420. if (!szName.IsEmpty() || lData == IDS_PRESENT || lData == IDS_NOTPRESENT)
  421. {
  422. AddQueryUnitWithModifier(static_cast<UINT>(lData),
  423. ATTR_COL_NAME,
  424. szName,
  425. szFilter);
  426. }
  427. }
  428. }
  429. //
  430. // Get the selection of the modifier combo
  431. //
  432. lSel = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_GETCURSEL, 0, 0);
  433. if (lSel != CB_ERR)
  434. {
  435. //
  436. // Retrieve the associated string ID
  437. //
  438. LRESULT lData = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_GETITEMDATA, lSel, 0);
  439. if (lData != CB_ERR)
  440. {
  441. if (!szDescription.IsEmpty() || lData == IDS_PRESENT || lData == IDS_NOTPRESENT)
  442. {
  443. AddQueryUnitWithModifier(static_cast<UINT>(lData),
  444. ATTR_COL_DESC,
  445. szDescription,
  446. szFilter);
  447. }
  448. }
  449. }
  450. if (!szFilter.IsEmpty())
  451. {
  452. szFilter = m_szFilterPrefix + szFilter;
  453. hr = BuildQueryParams(ppDsQueryParams, (LPWSTR)(LPCWSTR)szFilter);
  454. }
  455. return hr;
  456. }
  457. HRESULT CStdQueryPage::BuildQueryParams(LPDSQUERYPARAMS* ppDsQueryParams, LPWSTR pQuery)
  458. {
  459. ASSERT(pQuery);
  460. if(*ppDsQueryParams)
  461. {
  462. return QueryParamsAddQueryString(ppDsQueryParams, pQuery);
  463. }
  464. return QueryParamsAlloc(ppDsQueryParams, pQuery, cUserColumns, UserColumn);
  465. }
  466. HRESULT CStdQueryPage::Persist(IPersistQuery* pPersistQuery, BOOL fRead)
  467. {
  468. HRESULT hr = S_OK;
  469. if (pPersistQuery == NULL)
  470. {
  471. ASSERT(FALSE);
  472. return E_INVALIDARG;
  473. }
  474. if (fRead)
  475. {
  476. //
  477. // Read the Name combo value
  478. //
  479. int iData = 0;
  480. hr = pPersistQuery->ReadInt(m_szFilterPrefix, L"NameCombo", &iData);
  481. if (FAILED(hr))
  482. {
  483. TRACE(_T("Failed to read int \"NameCombo\" from stream: 0x%x\n"), hr);
  484. ASSERT(FALSE);
  485. return hr;
  486. }
  487. //
  488. // Select the appropriate list box item
  489. //
  490. SelectComboAssociatedWithData(IDC_NAME_COMBO, iData);
  491. if (iData != 0 && iData != IDS_PRESENT && iData != IDS_NOTPRESENT)
  492. {
  493. //
  494. // Read the name edit value
  495. //
  496. WCHAR szBuf[MAX_PATH] = {0};
  497. hr = pPersistQuery->ReadString(m_szFilterPrefix, L"NameEdit", szBuf, MAX_PATH);
  498. if (FAILED(hr))
  499. {
  500. TRACE(_T("Failed to read string \"NameEdit\" from stream: 0x%x\n"), hr);
  501. ASSERT(FALSE);
  502. return hr;
  503. }
  504. if (szBuf != NULL)
  505. {
  506. SetDlgItemText(IDC_NAME_EDIT, szBuf);
  507. }
  508. }
  509. else
  510. {
  511. GetDlgItem(IDC_NAME_EDIT)->EnableWindow(FALSE);
  512. }
  513. //
  514. // Read the Description combo value
  515. //
  516. iData = 0;
  517. hr = pPersistQuery->ReadInt(m_szFilterPrefix, L"DescCombo", &iData);
  518. if (FAILED(hr))
  519. {
  520. TRACE(_T("Failed to read int \"DescCombo\" from stream: 0x%x\n"), hr);
  521. ASSERT(FALSE);
  522. return hr;
  523. }
  524. //
  525. // Select the appropriate list box item
  526. //
  527. SelectComboAssociatedWithData(IDC_DESCRIPTION_COMBO, iData);
  528. if (iData != 0 && iData != IDS_PRESENT && iData != IDS_NOTPRESENT)
  529. {
  530. //
  531. // Read the name edit value
  532. //
  533. WCHAR szBuf[MAX_PATH] = {0};
  534. hr = pPersistQuery->ReadString(m_szFilterPrefix, L"DescEdit", szBuf, MAX_PATH);
  535. if (FAILED(hr))
  536. {
  537. TRACE(_T("Failed to read string \"DescEdit\" from stream: 0x%x\n"), hr);
  538. ASSERT(FALSE);
  539. return hr;
  540. }
  541. if (szBuf != NULL)
  542. {
  543. SetDlgItemText(IDC_DESCRIPTION_EDIT, szBuf);
  544. }
  545. }
  546. else
  547. {
  548. GetDlgItem(IDC_DESCRIPTION_EDIT)->EnableWindow(FALSE);
  549. }
  550. OnNameComboChange();
  551. OnDescriptionComboChange();
  552. }
  553. else // write
  554. {
  555. //
  556. // Write out the name info
  557. //
  558. LRESULT lSel = SendDlgItemMessage(IDC_NAME_COMBO, CB_GETCURSEL, 0, 0);
  559. if (lSel != CB_ERR)
  560. {
  561. //
  562. // Retrieve the associated string ID
  563. //
  564. LRESULT lData = SendDlgItemMessage(IDC_NAME_COMBO, CB_GETITEMDATA, lSel, 0);
  565. if (lData != CB_ERR)
  566. {
  567. hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"NameCombo", static_cast<int>(lData));
  568. if (FAILED(hr))
  569. {
  570. ASSERT(FALSE);
  571. return hr;
  572. }
  573. if (lData != 0 && lData != IDS_PRESENT && lData != IDS_NOTPRESENT)
  574. {
  575. CString szName;
  576. GetDlgItemText(IDC_NAME_EDIT, szName);
  577. hr = pPersistQuery->WriteString(m_szFilterPrefix, L"NameEdit", szName);
  578. if (FAILED(hr))
  579. {
  580. ASSERT(FALSE);
  581. return hr;
  582. }
  583. }
  584. }
  585. }
  586. else
  587. {
  588. //
  589. // If there hasn't been a selection, write in the empty string value
  590. //
  591. hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"NameCombo", 0);
  592. }
  593. //
  594. // Write out the description info
  595. //
  596. lSel = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_GETCURSEL, 0, 0);
  597. if (lSel != CB_ERR)
  598. {
  599. //
  600. // Retrieve the associated string ID
  601. //
  602. LRESULT lData = SendDlgItemMessage(IDC_DESCRIPTION_COMBO, CB_GETITEMDATA, lSel, 0);
  603. if (lData != CB_ERR)
  604. {
  605. hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"DescCombo", static_cast<int>(lData));
  606. if (FAILED(hr))
  607. {
  608. ASSERT(FALSE);
  609. return hr;
  610. }
  611. if (lData != 0 && lData != IDS_PRESENT && lData != IDS_NOTPRESENT)
  612. {
  613. CString szDescription;
  614. GetDlgItemText(IDC_DESCRIPTION_EDIT, szDescription);
  615. hr = pPersistQuery->WriteString(m_szFilterPrefix, L"DescEdit", szDescription);
  616. if (FAILED(hr))
  617. {
  618. ASSERT(FALSE);
  619. return hr;
  620. }
  621. }
  622. }
  623. }
  624. else
  625. {
  626. //
  627. // If there hasn't been a selection, write in the empty string value
  628. //
  629. hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"DescCombo", 0);
  630. }
  631. }
  632. return hr;
  633. }
  634. void CStdQueryPage::SelectComboAssociatedWithData(UINT nCtrlID, LRESULT lData)
  635. {
  636. //
  637. // Selects the item with the associated data in a combo box
  638. //
  639. LRESULT lRes = SendDlgItemMessage(nCtrlID, CB_GETCOUNT, 0, 0);
  640. if (lRes != CB_ERR)
  641. {
  642. for (int idx = 0; idx < static_cast<int>(lRes); idx++)
  643. {
  644. LRESULT lRetData = SendDlgItemMessage(nCtrlID, CB_GETITEMDATA, (WPARAM)idx, 0);
  645. if (lRetData != CB_ERR)
  646. {
  647. if (lRetData == lData)
  648. {
  649. SendDlgItemMessage(nCtrlID, CB_SETCURSEL, (WPARAM)idx, 0);
  650. break;
  651. }
  652. }
  653. }
  654. }
  655. }
  656. ///////////////////////////////////////////////////////////////////////////////
  657. // CUserComputerQueryPage
  658. BEGIN_MESSAGE_MAP(CUserComputerQueryPage, CStdQueryPage)
  659. END_MESSAGE_MAP()
  660. BOOL CUserComputerQueryPage::OnInitDialog()
  661. {
  662. return CStdQueryPage::OnInitDialog();
  663. }
  664. void CUserComputerQueryPage::DoContextHelp(HWND hWndControl)
  665. {
  666. if (hWndControl)
  667. {
  668. ::WinHelp(hWndControl,
  669. DSADMIN_CONTEXT_HELP_FILE,
  670. HELP_WM_HELP,
  671. (DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_QUERY_USER_PAGE);
  672. }
  673. }
  674. void CUserComputerQueryPage::Init()
  675. {
  676. //
  677. // Clear all controls
  678. //
  679. CStdQueryPage::Init();
  680. }
  681. HRESULT CUserComputerQueryPage::GetQueryParams(LPDSQUERYPARAMS* ppDsQueryParams)
  682. {
  683. HRESULT hr = S_OK;
  684. //
  685. // Build the filter string here
  686. //
  687. hr = CStdQueryPage::GetQueryParams(ppDsQueryParams);
  688. CString szFilter;
  689. BOOL bDisabledAccounts = FALSE;
  690. //
  691. // Get disabled accounts check
  692. //
  693. LRESULT lRes = SendDlgItemMessage(IDC_DISABLED_ACCOUNTS_CHECK, BM_GETCHECK, 0, 0);
  694. if (lRes == BST_CHECKED)
  695. {
  696. bDisabledAccounts = TRUE;
  697. }
  698. if (bDisabledAccounts)
  699. {
  700. szFilter.Format(g_szUserAccountCtrlQuery, UF_ACCOUNTDISABLE);
  701. szFilter = m_szFilterPrefix + szFilter;
  702. hr = BuildQueryParams(ppDsQueryParams, (LPWSTR)(LPCWSTR)szFilter);
  703. }
  704. return hr;
  705. }
  706. HRESULT CUserComputerQueryPage::Persist(IPersistQuery* pPersistQuery, BOOL fRead)
  707. {
  708. HRESULT hr = CStdQueryPage::Persist(pPersistQuery, fRead);
  709. if (FAILED(hr))
  710. {
  711. return hr;
  712. }
  713. if (pPersistQuery == NULL)
  714. {
  715. ASSERT(FALSE);
  716. return E_INVALIDARG;
  717. }
  718. if (fRead)
  719. {
  720. //
  721. // Read disabled accounts flag
  722. //
  723. int iData = 0;
  724. hr = pPersistQuery->ReadInt(m_szFilterPrefix, L"DisableCheck", &iData);
  725. if (FAILED(hr))
  726. {
  727. TRACE(_T("Failed to read int \"DisableCheck\" from stream: 0x%x\n"), hr);
  728. ASSERT(FALSE);
  729. return hr;
  730. }
  731. SendDlgItemMessage(IDC_DISABLED_ACCOUNTS_CHECK, BM_SETCHECK, (iData > 0) ? BST_CHECKED : BST_UNCHECKED, 0);
  732. }
  733. else
  734. {
  735. //
  736. // Write disabled accounts flag
  737. //
  738. LRESULT lRes = SendDlgItemMessage(IDC_DISABLED_ACCOUNTS_CHECK, BM_GETCHECK, 0, 0);
  739. if (lRes != -1)
  740. {
  741. int iRes = (lRes == BST_CHECKED) ? 1 : 0;
  742. hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"DisableCheck", iRes);
  743. if (FAILED(hr))
  744. {
  745. ASSERT(FALSE);
  746. return hr;
  747. }
  748. }
  749. }
  750. return hr;
  751. }
  752. ///////////////////////////////////////////////////////////////////////////////
  753. // CUserQueryPage
  754. BEGIN_MESSAGE_MAP(CUserQueryPage, CStdQueryPage)
  755. END_MESSAGE_MAP()
  756. BOOL CUserQueryPage::OnInitDialog()
  757. {
  758. return CUserComputerQueryPage::OnInitDialog();
  759. }
  760. void CUserQueryPage::DoContextHelp(HWND hWndControl)
  761. {
  762. if (hWndControl)
  763. {
  764. ::WinHelp(hWndControl,
  765. DSADMIN_CONTEXT_HELP_FILE,
  766. HELP_WM_HELP,
  767. (DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_QUERY_USER_PAGE);
  768. }
  769. }
  770. void CUserQueryPage::Init()
  771. {
  772. //
  773. // Clear all controls
  774. //
  775. CUserComputerQueryPage::Init();
  776. }
  777. HRESULT CUserQueryPage::GetQueryParams(LPDSQUERYPARAMS* ppDsQueryParams)
  778. {
  779. HRESULT hr = S_OK;
  780. //
  781. // Build the filter string here
  782. //
  783. hr = CUserComputerQueryPage::GetQueryParams(ppDsQueryParams);
  784. CString szFilter;
  785. BOOL bNonExpPwds = FALSE;
  786. BOOL bLastLogon = FALSE;
  787. DWORD dwLastLogonData = 0;
  788. //
  789. // Get non expiring password check
  790. //
  791. LRESULT lRes = SendDlgItemMessage(IDC_NON_EXPIRING_PWD_CHECK, BM_GETCHECK, 0, 0);
  792. if (lRes == BST_CHECKED)
  793. {
  794. bNonExpPwds = TRUE;
  795. }
  796. //
  797. // Get stale acccounts check
  798. //
  799. lRes = SendDlgItemMessage(IDC_LASTLOGON_COMBO, CB_GETCURSEL, 0, 0);
  800. if (lRes == CB_ERR)
  801. {
  802. lRes = m_lLogonSelection;
  803. }
  804. if (lRes != CB_ERR)
  805. {
  806. LRESULT lTextLen = SendDlgItemMessage(IDC_LASTLOGON_COMBO, CB_GETLBTEXTLEN, (WPARAM)lRes, 0);
  807. if (lTextLen != CB_ERR)
  808. {
  809. if (lTextLen > 0)
  810. {
  811. bLastLogon = TRUE;
  812. WCHAR* pszData = new WCHAR[lTextLen + 1];
  813. if (pszData != NULL)
  814. {
  815. LRESULT lData = SendDlgItemMessage(IDC_LASTLOGON_COMBO, CB_GETLBTEXT, (WPARAM)lRes, (LPARAM)pszData);
  816. if (lData != CB_ERR)
  817. {
  818. dwLastLogonData = static_cast<DWORD>(_wtol(pszData));
  819. // NTRAID#NTBUG9-449871-2001/09/20-lucios
  820. // Adding the appropriate filter.
  821. LARGE_INTEGER li;
  822. GetCurrentTimeStampMinusInterval(dwLastLogonData, &li);
  823. CString szTimeStamp;
  824. litow(li, szTimeStamp);
  825. CString szTempFilter;
  826. szTempFilter.Format
  827. (
  828. L"%s(lastLogonTimestamp<=%s)",
  829. szTempFilter,
  830. szTimeStamp
  831. );
  832. szFilter = szTempFilter + szFilter;
  833. }
  834. delete[] pszData;
  835. pszData = NULL;
  836. }
  837. }
  838. }
  839. }
  840. if (bNonExpPwds || bLastLogon)
  841. {
  842. if (bNonExpPwds)
  843. {
  844. szFilter.Format(g_szUserAccountCtrlQuery, UF_DONT_EXPIRE_PASSWD);
  845. }
  846. szFilter = m_szFilterPrefix + szFilter;
  847. hr = BuildQueryParams(ppDsQueryParams, (LPWSTR)(LPCWSTR)szFilter);
  848. if (SUCCEEDED(hr))
  849. {
  850. if (bLastLogon)
  851. {
  852. (*ppDsQueryParams)->dwFlags |= DSQF_LAST_LOGON_QUERY;
  853. (*ppDsQueryParams)->dwReserved = dwLastLogonData;
  854. }
  855. }
  856. }
  857. return hr;
  858. }
  859. HRESULT CUserQueryPage::Persist(IPersistQuery* pPersistQuery, BOOL fRead)
  860. {
  861. HRESULT hr = CUserComputerQueryPage::Persist(pPersistQuery, fRead);
  862. if (FAILED(hr))
  863. {
  864. return hr;
  865. }
  866. if (pPersistQuery == NULL)
  867. {
  868. ASSERT(FALSE);
  869. return E_INVALIDARG;
  870. }
  871. if (fRead)
  872. {
  873. //
  874. // Read non expiring pwds flag
  875. //
  876. int iData = 0;
  877. hr = pPersistQuery->ReadInt(m_szFilterPrefix, L"NonExpPwdCheck", &iData);
  878. if (FAILED(hr))
  879. {
  880. TRACE(_T("Failed to read int \"NonExpPwdCheck\" from stream: 0x%x\n"), hr);
  881. ASSERT(FALSE);
  882. return hr;
  883. }
  884. SendDlgItemMessage(IDC_NON_EXPIRING_PWD_CHECK, BM_SETCHECK, (iData > 0) ? BST_CHECKED : BST_UNCHECKED, 0);
  885. iData = 0;
  886. hr = pPersistQuery->ReadInt(m_szFilterPrefix, L"LastLogonCombo", &iData);
  887. if (FAILED(hr))
  888. {
  889. TRACE(_T("Failed to read int \"LastLogonCombo\" from stream: 0x%x\n"), hr);
  890. ASSERT(FALSE);
  891. return hr;
  892. }
  893. SendDlgItemMessage(IDC_LASTLOGON_COMBO, CB_SETCURSEL, (WPARAM)iData, 0);
  894. m_lLogonSelection = iData;
  895. }
  896. else
  897. {
  898. //
  899. // Write non expiring pwd flag
  900. //
  901. LRESULT lRes = SendDlgItemMessage(IDC_NON_EXPIRING_PWD_CHECK, BM_GETCHECK, 0, 0);
  902. if (lRes != -1)
  903. {
  904. int iRes = (lRes == BST_CHECKED) ? 1 : 0;
  905. hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"NonExpPwdCheck", iRes);
  906. if (FAILED(hr))
  907. {
  908. ASSERT(FALSE);
  909. return hr;
  910. }
  911. }
  912. //
  913. // Write last logon combo index
  914. //
  915. lRes = SendDlgItemMessage(IDC_LASTLOGON_COMBO, CB_GETCURSEL, 0, 0);
  916. if (lRes == CB_ERR)
  917. {
  918. if (m_lLogonSelection != -1)
  919. {
  920. lRes = m_lLogonSelection;
  921. }
  922. else
  923. {
  924. lRes = 0;
  925. }
  926. }
  927. hr = pPersistQuery->WriteInt(m_szFilterPrefix, L"LastLogonCombo", static_cast<int>(lRes));
  928. if (FAILED(hr))
  929. {
  930. ASSERT(FALSE);
  931. return hr;
  932. }
  933. }
  934. return hr;
  935. }
  936. ///////////////////////////////////////////////////////////////////////////////
  937. // CQueryFormBase
  938. HRESULT PageProc(LPCQPAGE pPage, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  939. INT_PTR CALLBACK DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  940. HRESULT GetQueryParams(HWND hWnd, LPDSQUERYPARAMS* ppDsQueryParams);
  941. STDMETHODIMP CQueryFormBase::Initialize(HKEY)
  942. {
  943. // This method is called to initialize the query form object, it is called before
  944. // any pages are added. hkForm should be ignored, in the future however it
  945. // will be a way to persist form state.
  946. HRESULT hr = S_OK;
  947. return hr;
  948. }
  949. STDMETHODIMP CQueryFormBase::AddForms(LPCQADDFORMSPROC pAddFormsProc, LPARAM lParam)
  950. {
  951. CQFORM cqf;
  952. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  953. // This method is called to allow the form handler to register its query form(s),
  954. // each form is identifiered by a CLSID and registered via the pAddFormProc. Here
  955. // we are going to register a test form.
  956. // When registering a form which is only applicable to a specific task, eg. Find a Domain
  957. // object, it is advised that the form be marked as hidden (CQFF_ISNEVERLISTED) which
  958. // will cause it not to appear in the form picker control. Then when the
  959. // client wants to use this form, they specify the form identifier and ask for the
  960. // picker control to be hidden.
  961. if ( !pAddFormsProc )
  962. {
  963. return E_INVALIDARG;
  964. }
  965. cqf.cbStruct = sizeof(cqf);
  966. cqf.dwFlags = CQFF_NOGLOBALPAGES;
  967. cqf.clsid = CLSID_DSAdminQueryUIForm;
  968. cqf.hIcon = NULL;
  969. CString title;
  970. title.LoadString(IDS_QUERY_TITLE_SAVEDQUERYFORM);
  971. cqf.pszTitle = (LPCTSTR)title;
  972. return pAddFormsProc(lParam, &cqf);
  973. }
  974. STDMETHODIMP CQueryFormBase::AddPages(LPCQADDPAGESPROC pAddPagesProc, LPARAM lParam)
  975. {
  976. HRESULT hr = S_OK;
  977. CQPAGE cqp;
  978. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  979. CThemeContextActivator activator;
  980. // AddPages is called after AddForms, it allows us to add the pages for the
  981. // forms we have registered. Each page is presented on a seperate tab within
  982. // the dialog. A form is a dialog with a DlgProc and a PageProc.
  983. //
  984. // When registering a page the entire structure passed to the callback is copied,
  985. // the amount of data to be copied is defined by the cbStruct field, therefore
  986. // a page implementation can grow this structure to store extra information. When
  987. // the page dialog is constructed via CreateDialog the CQPAGE strucuture is passed
  988. // as the create param.
  989. if ( !pAddPagesProc )
  990. return E_INVALIDARG;
  991. cqp.cbStruct = sizeof(cqp);
  992. cqp.dwFlags = 0x0;
  993. cqp.pPageProc = PageProc;
  994. cqp.hInstance = _Module.GetModuleInstance();
  995. cqp.pDlgProc = DlgProc;
  996. //
  997. // Add the user page
  998. //
  999. cqp.idPageName = IDS_QUERY_TITLE_USERPAGE;
  1000. cqp.idPageTemplate = IDD_QUERY_USER_PAGE;
  1001. cqp.lParam = (LPARAM)new CUserQueryPage(FILTER_PREFIX_USER);
  1002. hr = pAddPagesProc(lParam, CLSID_DSAdminQueryUIForm, &cqp);
  1003. //
  1004. // Add the computer page (this is just a std page)
  1005. //
  1006. cqp.idPageName = IDS_QUERY_TITLE_COMPUTER_PAGE;
  1007. cqp.idPageTemplate = IDD_QUERY_COMPUTER_PAGE;
  1008. cqp.lParam = (LPARAM)new CUserComputerQueryPage(IDD_QUERY_COMPUTER_PAGE, FILTER_PREFIX_COMPUTER);
  1009. hr = pAddPagesProc(lParam, CLSID_DSAdminQueryUIForm, &cqp);
  1010. //
  1011. // Add the group page (this is just a std page)
  1012. //
  1013. cqp.idPageName = IDS_QUERY_TITLE_GROUP_PAGE;
  1014. cqp.idPageTemplate = IDD_QUERY_STD_PAGE;
  1015. cqp.lParam = (LPARAM)new CStdQueryPage(IDD_QUERY_STD_PAGE, FILTER_PREFIX_GROUP);
  1016. hr = pAddPagesProc(lParam, CLSID_DSAdminQueryUIForm, &cqp);
  1017. //
  1018. // Add more pages here if needed
  1019. //
  1020. return hr;
  1021. }
  1022. #define ExitGracefully(hr, result, text) \
  1023. { hr = result; goto exit_gracefully; }
  1024. #define StringByteSizeW(sz) ((sz) ? ((lstrlenW(sz)+1)*sizeof(WCHAR)):0)
  1025. //NTRAID#NTBUG9-572010-2002/03/10-jmessec Unsafe wrapper for CopyMemory; what if string is longer than destination buffer?
  1026. #define StringByteCopyW(pDest, iOffset, sz) \
  1027. { CopyMemory(&(((LPBYTE)pDest)[iOffset]), sz, StringByteSizeW(sz)); }
  1028. STDAPI ClassListAlloc(LPDSQUERYCLASSLIST* ppDsQueryClassList, LPWSTR* aClassNames, INT cClassNames)
  1029. {
  1030. HRESULT hres;
  1031. DWORD cbStruct, offset;
  1032. LPDSQUERYCLASSLIST pDsQueryClassList = NULL;
  1033. INT i;
  1034. USES_CONVERSION;
  1035. if ( !ppDsQueryClassList || !aClassNames || !cClassNames )
  1036. ExitGracefully(hres, E_FAIL, "Bad parameters (no class list etc)");
  1037. // Walk the list of classes working out the size of the structure
  1038. // we are going to generate, this consists of the array of
  1039. // classes.
  1040. cbStruct = sizeof(DSQUERYCLASSLIST)+(cClassNames*sizeof(DWORD));
  1041. offset = cbStruct;
  1042. for ( i = 0 ; i < cClassNames ; i++ )
  1043. {
  1044. ASSERT(aClassNames[i]);
  1045. cbStruct += StringByteSizeW(aClassNames[i]);
  1046. }
  1047. // Allocate the structure using the task allocator, then fill
  1048. // it in copying all the strings into the data blob.
  1049. pDsQueryClassList = (LPDSQUERYCLASSLIST)CoTaskMemAlloc(cbStruct);
  1050. ASSERT(pDsQueryClassList);
  1051. if ( !pDsQueryClassList )
  1052. ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate class list structure");
  1053. pDsQueryClassList->cbStruct = cbStruct;
  1054. pDsQueryClassList->cClasses = cClassNames;
  1055. for ( i = 0 ; i < cClassNames ; i++ )
  1056. {
  1057. pDsQueryClassList->offsetClass[i] = offset;
  1058. StringByteCopyW(pDsQueryClassList, offset, aClassNames[i]);
  1059. offset += StringByteSizeW(aClassNames[i]);
  1060. }
  1061. hres = S_OK;
  1062. exit_gracefully:
  1063. ASSERT(pDsQueryClassList);
  1064. if (ppDsQueryClassList)
  1065. *ppDsQueryClassList = pDsQueryClassList;
  1066. return hres;
  1067. }
  1068. /*---------------------------------------------------------------------------*/
  1069. // The PageProc is used to perform general house keeping and communicate between
  1070. // the frame and the page.
  1071. //
  1072. // All un-handled, or unknown reasons should result in an E_NOIMPL response
  1073. // from the proc.
  1074. //
  1075. // In:
  1076. // pPage -> CQPAGE structure (copied from the original passed to pAddPagesProc)
  1077. // hwnd = handle of the dialog for the page
  1078. // uMsg, wParam, lParam = message parameters for this event
  1079. //
  1080. // Out:
  1081. // HRESULT
  1082. //
  1083. // uMsg reasons:
  1084. // ------------
  1085. // CQPM_INIIIALIZE
  1086. // CQPM_RELEASE
  1087. // These are issued as a result of the page being declared or freed, they
  1088. // allow the caller to AddRef, Release or perform basic initialization
  1089. // of the form object.
  1090. //
  1091. // CQPM_ENABLE
  1092. // Enable is when the query form needs to enable or disable the controls
  1093. // on its page. wParam contains TRUE/FALSE indicating the state that
  1094. // is required.
  1095. //
  1096. // CQPM_GETPARAMETERS
  1097. // To collect the parameters for the query each page on the active form
  1098. // receives this event. lParam is an LPVOID* which is set to point to the
  1099. // parameter block to pass to the handler, if the pointer is non-NULL
  1100. // on entry the form needs to appened its query information to it. The
  1101. // parameter block is handler specific.
  1102. //
  1103. // Returning S_FALSE from this event causes the query to be canceled.
  1104. //
  1105. // CQPM_CLEARFORM
  1106. // When the page window is created for the first time, or the user clicks
  1107. // the clear search the page receives a CQPM_CLEARFORM notification, at
  1108. // which point it needs to clear out the edit controls it has and
  1109. // return to a default state.
  1110. //
  1111. // CQPM_PERSIST:
  1112. // When loading of saving a query, each page is called with an IPersistQuery
  1113. // interface which allows them to read or write the configuration information
  1114. // to save or restore their state. lParam is a pointer to the IPersistQuery object,
  1115. // and wParam is TRUE/FALSE indicating read or write accordingly.
  1116. HRESULT PageProc(LPCQPAGE pQueryPage, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1117. {
  1118. HRESULT hr = S_OK;
  1119. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1120. CQueryPageBase* pDialog = (CQueryPageBase*)pQueryPage->lParam;
  1121. ASSERT(pDialog);
  1122. switch ( uMsg )
  1123. {
  1124. // Initialize so AddRef the object we are associated with so that
  1125. // we don't get unloaded.
  1126. case CQPM_INITIALIZE:
  1127. break;
  1128. case DSQPM_GETCLASSLIST:
  1129. {
  1130. LPWSTR classes[]={L"user",L"computer",L"group"};
  1131. hr = ClassListAlloc((LPDSQUERYCLASSLIST*)lParam, classes, sizeof(classes)/sizeof(*classes));
  1132. break;
  1133. }
  1134. case DSQPM_HELPTOPICS:
  1135. {
  1136. HWND hwndFrame = (HWND)lParam;
  1137. HtmlHelp(hwndFrame, TEXT("omc.chm"), HH_HELP_FINDER, 0);
  1138. break;
  1139. }
  1140. // Changed from qform sample to detach the hwnd, and delete the CDialog
  1141. // ensure correct destruction etc.
  1142. case CQPM_RELEASE:
  1143. pDialog->Detach();
  1144. SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM)0);
  1145. delete pDialog;
  1146. break;
  1147. // Enable so fix the state of our two controls within the window.
  1148. case CQPM_ENABLE:
  1149. SetFocus(GetDlgItem(hwnd, IDC_NAME_COMBO));
  1150. break;
  1151. // Fill out the parameter structure to return to the caller, this is
  1152. // handler specific. In our case we constructure a query of the CN
  1153. // and objectClass properties, and we show a columns displaying both
  1154. // of these. For further information about the DSQUERYPARAMs structure
  1155. // see dsquery.h
  1156. case CQPM_GETPARAMETERS:
  1157. hr = pDialog->GetQueryParams((LPDSQUERYPARAMS*)lParam);
  1158. break;
  1159. // Clear form, therefore set the window text for these two controls
  1160. // to zero.
  1161. case CQPM_CLEARFORM:
  1162. hr = pDialog->ClearForm();
  1163. break;
  1164. // persistance is not currently supported by this form.
  1165. case CQPM_PERSIST:
  1166. {
  1167. BOOL fRead = (BOOL)wParam;
  1168. IPersistQuery* pPersistQuery = (IPersistQuery*)lParam;
  1169. if ( !pPersistQuery )
  1170. {
  1171. return E_INVALIDARG;
  1172. }
  1173. hr = pDialog->Persist(pPersistQuery, fRead);
  1174. break;
  1175. }
  1176. default:
  1177. hr = E_NOTIMPL;
  1178. break;
  1179. }
  1180. return hr;
  1181. }
  1182. /*---------------------------------------------------------------------------*/
  1183. // The DlgProc is a standard Win32 dialog proc associated with the form
  1184. // window.
  1185. INT_PTR CALLBACK DlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1186. {
  1187. LPCQPAGE pQueryPage;
  1188. CQueryPageBase* pDialog;
  1189. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1190. if ( uMsg == WM_INITDIALOG )
  1191. {
  1192. // changed from qForm sample to save CDialog pointer
  1193. // in the DWL_USER field of the dialog box instance.
  1194. pQueryPage = (LPCQPAGE)lParam;
  1195. pDialog = (CQueryPageBase*)pQueryPage->lParam;
  1196. pDialog->Attach(hwnd);
  1197. SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM)pDialog);
  1198. return pDialog->OnInitDialog();
  1199. }
  1200. else
  1201. {
  1202. // CDialog pointer is stored in DWL_USER
  1203. // dialog structure, note however that in some cases this will
  1204. // be NULL as it is set on WM_INITDIALOG.
  1205. pDialog = (CQueryPageBase*)GetWindowLongPtr(hwnd, DWLP_USER);
  1206. }
  1207. if(!pDialog)
  1208. {
  1209. return FALSE;
  1210. }
  1211. else
  1212. {
  1213. return AfxCallWndProc(pDialog, hwnd, uMsg, wParam, lParam);
  1214. }
  1215. }
  1216. ///////////////////////////////////////////////////////////////////////
  1217. // CQueryDialog
  1218. CQueryDialog::CQueryDialog(CSavedQueryNode* pQueryNode,
  1219. CFavoritesNode* pFavNode,
  1220. CDSComponentData* pComponentData,
  1221. BOOL bNewQuery,
  1222. BOOL bImportQuery)
  1223. : CHelpDialog(IDD_CREATE_NEW_QUERY)
  1224. {
  1225. m_bInit = FALSE;
  1226. m_bNewQuery = bNewQuery;
  1227. m_bImportQuery = bImportQuery;
  1228. m_pComponentData = pComponentData;
  1229. m_pQueryNode = pQueryNode;
  1230. m_pFavNode = pFavNode;
  1231. m_szName = pQueryNode->GetName();
  1232. m_szOriginalName = pQueryNode->GetName();
  1233. m_szDescription = pQueryNode->GetDesc();
  1234. m_szQueryRoot = pQueryNode->GetRootPath();
  1235. m_szQueryFilter = pQueryNode->GetQueryString();
  1236. m_bMultiLevel = !pQueryNode->IsOneLevel();
  1237. m_bLastLogonFilter = pQueryNode->IsFilterLastLogon();
  1238. m_dwLastLogonData = pQueryNode->GetLastLogonDays();
  1239. m_pPersistQueryImpl = pQueryNode->GetQueryPersist();
  1240. if (m_pPersistQueryImpl != NULL)
  1241. {
  1242. m_pPersistQueryImpl->AddRef();
  1243. }
  1244. else
  1245. {
  1246. //
  1247. // Create the IPersistQuery object
  1248. //
  1249. CComObject<CDSAdminPersistQueryFilterImpl>::CreateInstance(&m_pPersistQueryImpl);
  1250. ASSERT(m_pPersistQueryImpl != NULL);
  1251. //
  1252. // created with zero refcount,need to AddRef() to one
  1253. //
  1254. m_pPersistQueryImpl->AddRef();
  1255. }
  1256. }
  1257. CQueryDialog::~CQueryDialog()
  1258. {
  1259. if (m_pPersistQueryImpl != NULL)
  1260. {
  1261. //
  1262. // go to refcount of zero, to destroy object
  1263. //
  1264. m_pPersistQueryImpl->Release();
  1265. }
  1266. }
  1267. BEGIN_MESSAGE_MAP(CQueryDialog, CHelpDialog)
  1268. ON_BN_CLICKED(IDC_BROWSE_BUTTON, OnBrowse)
  1269. ON_BN_CLICKED(IDC_EDIT_BUTTON, OnEditQuery)
  1270. ON_BN_CLICKED(IDC_MULTI_LEVEL_CHECK, OnMultiLevelChange)
  1271. ON_EN_CHANGE(IDC_NAME_EDIT, OnNameChange)
  1272. ON_EN_CHANGE(IDC_DESCRIPTION_EDIT, OnDescriptionChange)
  1273. ON_NOTIFY_EX(TTN_NEEDTEXT, 0, OnNeedToolTipText)
  1274. END_MESSAGE_MAP()
  1275. void CQueryDialog::DoContextHelp(HWND hWndControl)
  1276. {
  1277. if (hWndControl)
  1278. {
  1279. ::WinHelp(hWndControl,
  1280. DSADMIN_CONTEXT_HELP_FILE,
  1281. HELP_WM_HELP,
  1282. (DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_CREATE_NEW_QUERY);
  1283. }
  1284. }
  1285. BOOL CQueryDialog::OnInitDialog()
  1286. {
  1287. CHelpDialog::OnInitDialog();
  1288. if (m_pQueryNode == NULL)
  1289. {
  1290. ASSERT(FALSE);
  1291. EndDialog(IDCANCEL);
  1292. }
  1293. //
  1294. // Change the title for editing queries
  1295. //
  1296. if (!m_bNewQuery)
  1297. {
  1298. CString szTitle;
  1299. VERIFY(szTitle.LoadString(IDS_SAVED_QUERIES_EDIT_TITLE));
  1300. SetWindowText(szTitle);
  1301. }
  1302. //
  1303. // Initialize the controls with data
  1304. //
  1305. SetDlgItemText(IDC_NAME_EDIT, m_szName);
  1306. SendDlgItemMessage(IDC_NAME_EDIT, EM_SETLIMITTEXT, MAX_QUERY_NAME_LENGTH, 0);
  1307. SetDlgItemText(IDC_DESCRIPTION_EDIT, m_szDescription);
  1308. SendDlgItemMessage(IDC_DESCRIPTION_EDIT, EM_SETLIMITTEXT, MAX_QUERY_DESC_LENGTH, 0);
  1309. SendDlgItemMessage(IDC_MULTI_LEVEL_CHECK, BM_SETCHECK, (m_bMultiLevel) ? BST_CHECKED : BST_UNCHECKED, 0);
  1310. SetQueryFilterDisplay();
  1311. EnableToolTips(TRUE);
  1312. SetQueryRoot(m_szQueryRoot);
  1313. SetDirty();
  1314. m_bInit = TRUE;
  1315. return TRUE;
  1316. }
  1317. void CQueryDialog::SetDirty(BOOL bDirty)
  1318. {
  1319. if (m_bInit || m_bImportQuery)
  1320. {
  1321. m_szName.TrimLeft();
  1322. m_szName.TrimRight();
  1323. if (m_szName.IsEmpty() ||
  1324. m_szQueryRoot.IsEmpty() ||
  1325. m_szQueryFilter.IsEmpty())
  1326. {
  1327. m_bDirty = FALSE;
  1328. }
  1329. else
  1330. {
  1331. m_bDirty = bDirty;
  1332. }
  1333. GetDlgItem(IDOK)->EnableWindow(m_bDirty);
  1334. }
  1335. }
  1336. void CQueryDialog::OnOK()
  1337. {
  1338. CThemeContextActivator activator;
  1339. if (m_bDirty)
  1340. {
  1341. if (m_pQueryNode != NULL)
  1342. {
  1343. GetDlgItemText(IDC_NAME_EDIT, m_szName);
  1344. GetDlgItemText(IDC_DESCRIPTION_EDIT, m_szDescription);
  1345. LRESULT lRes = SendDlgItemMessage(IDC_MULTI_LEVEL_CHECK, BM_GETCHECK, 0, 0);
  1346. if (lRes == BST_CHECKED)
  1347. {
  1348. m_bMultiLevel = TRUE;
  1349. }
  1350. else
  1351. {
  1352. m_bMultiLevel = FALSE;
  1353. }
  1354. //
  1355. // Trim white space
  1356. //
  1357. m_szName.TrimLeft();
  1358. m_szName.TrimRight();
  1359. if (wcscmp(m_szOriginalName, m_szName) != 0 || m_bImportQuery)
  1360. {
  1361. CUINode* pDupNode = NULL;
  1362. if (!m_pFavNode->IsUniqueName(m_szName, &pDupNode))
  1363. {
  1364. CString szFormatMsg;
  1365. VERIFY(szFormatMsg.LoadString(IDS_ERRMSG_NOT_UNIQUE_QUERY_NAME));
  1366. CString szErrMsg;
  1367. szErrMsg.Format(szFormatMsg, m_szName);
  1368. CString szTitle;
  1369. VERIFY(szTitle.LoadString(IDS_DSSNAPINNAME));
  1370. MessageBox(szErrMsg, szTitle, MB_OK | MB_ICONSTOP);
  1371. //
  1372. // Set the focus to the name field and select all the text
  1373. //
  1374. GetDlgItem(IDC_NAME_EDIT)->SetFocus();
  1375. SendDlgItemMessage(IDC_NAME_EDIT, EM_SETSEL, 0, -1);
  1376. return;
  1377. }
  1378. }
  1379. if (m_bLastLogonFilter)
  1380. {
  1381. m_pQueryNode->SetLastLogonQuery(m_dwLastLogonData);
  1382. }
  1383. else
  1384. {
  1385. m_pQueryNode->SetLastLogonQuery(static_cast<DWORD>(-1));
  1386. }
  1387. m_pQueryNode->SetQueryString(m_szQueryFilter);
  1388. m_pQueryNode->SetName(m_szName);
  1389. m_pQueryNode->SetDesc(m_szDescription);
  1390. m_pQueryNode->SetRootPath(m_szQueryRoot);
  1391. m_pQueryNode->SetOneLevel((m_bMultiLevel == BST_CHECKED) ? FALSE : TRUE);
  1392. m_pQueryNode->SetQueryPersist(m_pPersistQueryImpl);
  1393. }
  1394. }
  1395. CHelpDialog::OnOK();
  1396. }
  1397. BOOL CQueryDialog::OnNeedToolTipText(UINT, NMHDR* pTTTStruct, LRESULT* /*ignored*/)
  1398. {
  1399. BOOL bRes = FALSE;
  1400. TOOLTIPTEXT* pTTText = reinterpret_cast<TOOLTIPTEXT*>(pTTTStruct);
  1401. if (pTTText != NULL)
  1402. {
  1403. if (pTTText->uFlags & TTF_IDISHWND)
  1404. {
  1405. UINT nCtrlID = ::GetDlgCtrlID((HWND)pTTText->hdr.idFrom);
  1406. if (nCtrlID == IDC_ROOT_EDIT)
  1407. {
  1408. pTTText->lpszText = (LPWSTR)(LPCWSTR)m_szQueryRoot;
  1409. bRes = TRUE;
  1410. }
  1411. }
  1412. }
  1413. return bRes;
  1414. }
  1415. void CQueryDialog::OnEditQuery()
  1416. {
  1417. CWaitCursor wait;
  1418. CLIPFORMAT cfDsQueryParams = (CLIPFORMAT)::RegisterClipboardFormat(CFSTR_DSQUERYPARAMS);
  1419. //
  1420. // create a query object
  1421. //
  1422. HRESULT hr;
  1423. CComPtr<ICommonQuery> spCommonQuery;
  1424. hr = ::CoCreateInstance(CLSID_CommonQuery, NULL, CLSCTX_INPROC_SERVER,
  1425. IID_ICommonQuery, (PVOID *)&spCommonQuery);
  1426. if (FAILED(hr))
  1427. {
  1428. ReportMessageEx(GetSafeHwnd(), IDS_ERRMSG_NO_DSQUERYUI);
  1429. return;
  1430. }
  1431. //
  1432. // setup structs to make the query
  1433. //
  1434. DSQUERYINITPARAMS dqip;
  1435. OPENQUERYWINDOW oqw;
  1436. ZeroMemory(&dqip, sizeof(DSQUERYINITPARAMS));
  1437. ZeroMemory(&oqw, sizeof(OPENQUERYWINDOW));
  1438. dqip.cbStruct = sizeof(dqip);
  1439. dqip.dwFlags = DSQPF_NOSAVE | DSQPF_SHOWHIDDENOBJECTS |
  1440. DSQPF_ENABLEADMINFEATURES;
  1441. dqip.pDefaultScope = NULL;
  1442. CString szServerName = m_pComponentData->GetBasePathsInfo()->GetServerName();
  1443. if (!szServerName.IsEmpty())
  1444. {
  1445. dqip.dwFlags |= DSQPF_HASCREDENTIALS;
  1446. dqip.pServer = (PWSTR)(PCWSTR)szServerName;
  1447. }
  1448. oqw.cbStruct = sizeof(oqw);
  1449. oqw.dwFlags = OQWF_OKCANCEL | OQWF_DEFAULTFORM | OQWF_SHOWOPTIONAL | /*OQWF_REMOVEFORMS |*/
  1450. OQWF_REMOVESCOPES | OQWF_SAVEQUERYONOK | OQWF_HIDEMENUS | OQWF_HIDESEARCHUI;
  1451. if (!m_pPersistQueryImpl->IsEmpty())
  1452. {
  1453. oqw.dwFlags |= OQWF_LOADQUERY;
  1454. }
  1455. oqw.clsidHandler = CLSID_DsQuery;
  1456. oqw.pHandlerParameters = &dqip;
  1457. oqw.clsidDefaultForm = CLSID_DSAdminQueryUIForm;
  1458. //
  1459. // set the IPersistQuery pointer (smart pointer)
  1460. //
  1461. CComPtr<IPersistQuery> spIPersistQuery;
  1462. hr = m_pPersistQueryImpl->QueryInterface(IID_IPersistQuery, (void**)&spIPersistQuery);
  1463. if (FAILED(hr))
  1464. {
  1465. int iRes = ReportMessageEx(GetSafeHwnd(), IDS_ERRMSG_NO_PERSIST_QUERYUI, MB_OKCANCEL | MB_ICONINFORMATION);
  1466. if (iRes == IDCANCEL)
  1467. {
  1468. return;
  1469. }
  1470. }
  1471. //
  1472. // now smart pointer has refcount=1 for it lifetime
  1473. //
  1474. oqw.pPersistQuery = spIPersistQuery;
  1475. //
  1476. // Get the HWND of the current dialog
  1477. //
  1478. HWND hWnd = GetSafeHwnd();
  1479. //
  1480. // make the call to get the query displayed
  1481. //
  1482. CComPtr<IDataObject> spQueryResultDataObject;
  1483. hr = spCommonQuery->OpenQueryWindow(hWnd, &oqw, &spQueryResultDataObject);
  1484. if (SUCCEEDED(hr) && spQueryResultDataObject != NULL)
  1485. {
  1486. //
  1487. // retrieve the query string from the data object
  1488. //
  1489. FORMATETC fmte = {cfDsQueryParams, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1490. STGMEDIUM medium = {TYMED_NULL, NULL, NULL};
  1491. hr = spQueryResultDataObject->GetData(&fmte, &medium);
  1492. if (SUCCEEDED(hr)) // we have data
  1493. {
  1494. //
  1495. // get the query string
  1496. //
  1497. LPDSQUERYPARAMS pDsQueryParams = (LPDSQUERYPARAMS)medium.hGlobal;
  1498. LPWSTR pwszFilter = (LPWSTR)ByteOffset(pDsQueryParams, pDsQueryParams->offsetQuery);
  1499. CString szTempFilter = pwszFilter;
  1500. //
  1501. // Check to see if we received a "special" query string
  1502. //
  1503. if (pDsQueryParams->dwFlags & DSQF_LAST_LOGON_QUERY)
  1504. {
  1505. m_bLastLogonFilter = TRUE;
  1506. m_dwLastLogonData = pDsQueryParams->dwReserved;
  1507. LARGE_INTEGER li;
  1508. GetCurrentTimeStampMinusInterval(m_dwLastLogonData, &li);
  1509. CString szTimeStamp;
  1510. litow(li, szTimeStamp);
  1511. szTempFilter.Format(L"%s(lastLogonTimestamp<=%s)", szTempFilter, szTimeStamp);
  1512. }
  1513. else
  1514. {
  1515. m_bLastLogonFilter = FALSE;
  1516. m_dwLastLogonData = 0;
  1517. }
  1518. ::ReleaseStgMedium(&medium);
  1519. // REVIEW_MARCOC: this is a hack waiting for Diz to fix it...
  1520. // the query string should be a well formed expression. Period
  1521. // the query string is in the form (<foo>)(<bar>)...
  1522. // if more of one token, need to wrap as (& (<foo>)(<bar>)...)
  1523. PWSTR pChar = (LPWSTR)(LPCWSTR)szTempFilter;
  1524. int nLeftPar = 0;
  1525. while (*pChar != NULL)
  1526. {
  1527. if (*pChar == TEXT('('))
  1528. {
  1529. nLeftPar++;
  1530. if (nLeftPar > 1)
  1531. break;
  1532. }
  1533. pChar++;
  1534. }
  1535. if (nLeftPar > 1)
  1536. {
  1537. m_szQueryFilter.Format(_T("(&%s)"), (LPCWSTR)szTempFilter);
  1538. }
  1539. else
  1540. {
  1541. m_szQueryFilter = szTempFilter;
  1542. }
  1543. SetDirty();
  1544. }
  1545. else
  1546. {
  1547. //
  1548. // The user removed all query data from DSQUERYUI
  1549. //
  1550. //
  1551. // Remove filter data
  1552. //
  1553. m_szQueryFilter = L"";
  1554. m_bLastLogonFilter = FALSE;
  1555. m_dwLastLogonData = 0;
  1556. SetDirty();
  1557. }
  1558. }
  1559. SetQueryFilterDisplay();
  1560. return;
  1561. }
  1562. void CQueryDialog::SetQueryFilterDisplay()
  1563. {
  1564. if (m_bLastLogonFilter)
  1565. {
  1566. CString szTemp;
  1567. szTemp.LoadString(IDS_HIDE_LASTLOGON_QUERY);
  1568. SetDlgItemText(IDC_QUERY_STRING_EDIT, szTemp);
  1569. }
  1570. else
  1571. {
  1572. SetDlgItemText(IDC_QUERY_STRING_EDIT, m_szQueryFilter);
  1573. }
  1574. }
  1575. int SavedQueriesBrowseCallback(HWND, UINT uMsg, LPARAM lParam, LPARAM /*lpData*/)
  1576. {
  1577. int ret = 0;
  1578. switch (uMsg)
  1579. {
  1580. case DSBM_HELP:
  1581. {
  1582. TRACE(L"Browse Callback: msg is DSBM_HELP.\n");
  1583. LPHELPINFO pHelp = (LPHELPINFO) lParam;
  1584. TRACE(_T("CtrlId = %d, ContextId = 0x%x\n"),
  1585. pHelp->iCtrlId, pHelp->dwContextId);
  1586. if (!pHelp ||
  1587. pHelp->iCtrlId != DSBID_CONTAINERLIST)
  1588. {
  1589. ret = 0; // not handled
  1590. break;
  1591. }
  1592. ::WinHelp((HWND)pHelp->hItemHandle,
  1593. DSADMIN_CONTEXT_HELP_FILE,
  1594. HELP_WM_HELP,
  1595. (DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_BROWSE_CONTAINER);
  1596. ret = 1;
  1597. }
  1598. break;
  1599. default:
  1600. ret = 0;
  1601. break;
  1602. }
  1603. return ret;
  1604. }
  1605. void CQueryDialog::OnBrowse()
  1606. {
  1607. DWORD result;
  1608. CString szBrowseTitle;
  1609. VERIFY(szBrowseTitle.LoadString(IDS_QUERY_BROWSE_TITLE));
  1610. CString szBrowseCaption;
  1611. VERIFY(szBrowseCaption.LoadString(IDS_QUERY_BROWSE_CAPTION));
  1612. WCHAR szPath[2 * MAX_PATH+1];
  1613. //
  1614. // Get the root of the console
  1615. CString szDNC = m_pComponentData->GetBasePathsInfo()->GetDefaultRootNamingContext();
  1616. CString szRootPath;
  1617. m_pComponentData->GetBasePathsInfo()->ComposeADsIPath(szRootPath, szDNC);
  1618. DSBROWSEINFO dsbi;
  1619. ::ZeroMemory( &dsbi, sizeof(dsbi) );
  1620. dsbi.hwndOwner = GetSafeHwnd();
  1621. dsbi.cbStruct = sizeof (DSBROWSEINFO);
  1622. dsbi.pszCaption = (LPWSTR)((LPCWSTR)szBrowseTitle);
  1623. dsbi.pszTitle = (LPWSTR)((LPCWSTR)szBrowseCaption);
  1624. dsbi.pszRoot = szRootPath;
  1625. dsbi.pszPath = szPath;
  1626. dsbi.cchPath = ((2 * MAX_PATH + 1) / sizeof(WCHAR));
  1627. dsbi.dwFlags = DSBI_INCLUDEHIDDEN | DSBI_RETURN_FORMAT;
  1628. dsbi.pfnCallback = SavedQueriesBrowseCallback;
  1629. dsbi.lParam = 0;
  1630. dsbi.dwReturnFormat = ADS_FORMAT_X500;
  1631. result = DsBrowseForContainer( &dsbi );
  1632. if ( result == IDOK )
  1633. {
  1634. //
  1635. // returns -1, 0, IDOK or IDCANCEL
  1636. // get path from BROWSEINFO struct, put in text edit field
  1637. //
  1638. TRACE(_T("returned from DS Browse successfully with:\n %s\n"),
  1639. dsbi.pszPath);
  1640. CPathCracker pathCracker;
  1641. HRESULT hr = pathCracker.Set(CComBSTR(dsbi.pszPath), ADS_SETTYPE_FULL);
  1642. if (SUCCEEDED(hr))
  1643. {
  1644. hr = pathCracker.SetDisplayType(ADS_DISPLAY_FULL);
  1645. if (SUCCEEDED(hr))
  1646. {
  1647. CComBSTR bstrDN;
  1648. hr = pathCracker.Retrieve(ADS_FORMAT_X500_DN, &bstrDN);
  1649. if (SUCCEEDED(hr))
  1650. {
  1651. SetQueryRoot(bstrDN);
  1652. SetDirty();
  1653. }
  1654. }
  1655. }
  1656. }
  1657. }
  1658. void CQueryDialog::SetQueryRoot(PCWSTR pszPath)
  1659. {
  1660. m_szQueryRoot = pszPath;
  1661. CPathCracker pathCracker;
  1662. HRESULT hr = pathCracker.Set(CComBSTR(m_szQueryRoot), ADS_SETTYPE_DN);
  1663. if (SUCCEEDED(hr))
  1664. {
  1665. hr = pathCracker.SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  1666. if (SUCCEEDED(hr))
  1667. {
  1668. CComBSTR bstrDisplayPath;
  1669. hr = pathCracker.GetElement(0, &bstrDisplayPath);
  1670. if (SUCCEEDED(hr))
  1671. {
  1672. CString szDisplayString;
  1673. szDisplayString.Format(L"...\\%s", bstrDisplayPath);
  1674. SetDlgItemText(IDC_ROOT_EDIT, szDisplayString);
  1675. }
  1676. else
  1677. {
  1678. SetDlgItemText(IDC_ROOT_EDIT, m_szQueryRoot);
  1679. }
  1680. }
  1681. else
  1682. {
  1683. SetDlgItemText(IDC_ROOT_EDIT, m_szQueryRoot);
  1684. }
  1685. }
  1686. else
  1687. {
  1688. SetDlgItemText(IDC_ROOT_EDIT, m_szQueryRoot);
  1689. }
  1690. }
  1691. void CQueryDialog::OnMultiLevelChange()
  1692. {
  1693. SetDirty();
  1694. }
  1695. void CQueryDialog::OnNameChange()
  1696. {
  1697. GetDlgItemText(IDC_NAME_EDIT, m_szName);
  1698. if (m_szName.IsEmpty())
  1699. {
  1700. SetDirty(FALSE);
  1701. }
  1702. else
  1703. {
  1704. SetDirty();
  1705. }
  1706. }
  1707. void CQueryDialog::OnDescriptionChange()
  1708. {
  1709. SetDirty();
  1710. }
  1711. ///////////////////////////////////////////////////////////////////////////
  1712. // CFavoritesNodePropertyPage
  1713. BEGIN_MESSAGE_MAP(CFavoritesNodePropertyPage, CHelpPropertyPage)
  1714. ON_EN_CHANGE(IDC_DESCRIPTION_EDIT, OnDescriptionChange)
  1715. ON_WM_DESTROY()
  1716. END_MESSAGE_MAP()
  1717. void CFavoritesNodePropertyPage::DoContextHelp(HWND hWndControl)
  1718. {
  1719. if (hWndControl)
  1720. {
  1721. ::WinHelp(hWndControl,
  1722. DSADMIN_CONTEXT_HELP_FILE,
  1723. HELP_WM_HELP,
  1724. (DWORD_PTR)(LPTSTR)g_aHelpIDs_IDD_FAVORITES_PROPERTY_PAGE);
  1725. }
  1726. }
  1727. BOOL CFavoritesNodePropertyPage::OnInitDialog()
  1728. {
  1729. CHelpPropertyPage::OnInitDialog();
  1730. m_szOldDescription = m_pFavNode->GetDesc();
  1731. SetDlgItemText(IDC_CN, m_pFavNode->GetName());
  1732. SetDlgItemText(IDC_DESCRIPTION_EDIT, m_szOldDescription);
  1733. return FALSE;
  1734. }
  1735. void CFavoritesNodePropertyPage::OnDescriptionChange()
  1736. {
  1737. CString szNewDescription;
  1738. GetDlgItemText(IDC_DESCRIPTION_EDIT, szNewDescription);
  1739. if (szNewDescription == m_szOldDescription)
  1740. {
  1741. SetModified(FALSE);
  1742. }
  1743. else
  1744. {
  1745. SetModified(TRUE);
  1746. }
  1747. }
  1748. BOOL CFavoritesNodePropertyPage::OnApply()
  1749. {
  1750. BOOL bRet = TRUE;
  1751. CString szNewDescription;
  1752. GetDlgItemText(IDC_DESCRIPTION_EDIT, szNewDescription);
  1753. if (szNewDescription == m_szOldDescription)
  1754. {
  1755. return TRUE;
  1756. }
  1757. else
  1758. {
  1759. m_pFavNode->SetDesc(szNewDescription);
  1760. if (m_lNotifyHandle != NULL && m_pDataObject != NULL)
  1761. {
  1762. MMCPropertyChangeNotify(m_lNotifyHandle, (LPARAM)m_pDataObject);
  1763. }
  1764. }
  1765. m_szOldDescription = szNewDescription;
  1766. return bRet;
  1767. }
  1768. void CFavoritesNodePropertyPage::OnDestroy()
  1769. {
  1770. m_pComponentData->SheetUnlockCookie(m_pFavNode);
  1771. }