Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1050 lines
32 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Windows NT Directory Service Property Pages
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1999
  7. //
  8. // File: tablpage.cxx
  9. //
  10. // Contents: CDsTableDrivenPage, the class that implements table-driven
  11. // property pages
  12. //
  13. // History: 1-April-97 EricB created
  14. //
  15. //-----------------------------------------------------------------------------
  16. #include "pch.h"
  17. #include <stdio.h>
  18. #include "proppage.h"
  19. //+----------------------------------------------------------------------------
  20. //
  21. // Member: CDsTableDrivenPage::CDsTableDrivenPage
  22. //
  23. //-----------------------------------------------------------------------------
  24. CDsTableDrivenPage::CDsTableDrivenPage(PDSPAGE pDsPage, LPDATAOBJECT pDataObj,
  25. HWND hNotifyWnd, DWORD dwFlags) :
  26. m_pData(NULL),
  27. CDsPropPageBase(pDsPage, pDataObj, hNotifyWnd, dwFlags)
  28. {
  29. TRACE(CDsTableDrivenPage,CDsTableDrivenPage);
  30. #ifdef _DEBUG
  31. strcpy(szClass, "CDsTableDrivenPage");
  32. #endif
  33. }
  34. //+----------------------------------------------------------------------------
  35. //
  36. // Member: CDsTableDrivenPage::~CDsTableDrivenPage
  37. //
  38. //-----------------------------------------------------------------------------
  39. CDsTableDrivenPage::~CDsTableDrivenPage()
  40. {
  41. TRACE(CDsTableDrivenPage,~CDsTableDrivenPage);
  42. }
  43. //+----------------------------------------------------------------------------
  44. //
  45. // Function: CreateTableDrivenPage
  46. //
  47. // Synopsis: Creates an instance of a page window.
  48. //
  49. //-----------------------------------------------------------------------------
  50. HRESULT
  51. CreateTableDrivenPage(PDSPAGE pDsPage, LPDATAOBJECT pDataObj,
  52. PWSTR pwzADsPath, PWSTR pwzClass, HWND hNotifyWnd,
  53. DWORD dwFlags, CDSBasePathsInfo* pBasePathsInfo,
  54. HPROPSHEETPAGE * phPage)
  55. {
  56. TRACE_FUNCTION(CreateTableDrivenPage);
  57. CDsTableDrivenPage * pPageObj = new CDsTableDrivenPage(pDsPage, pDataObj,
  58. hNotifyWnd, dwFlags);
  59. CHECK_NULL(pPageObj, return E_OUTOFMEMORY);
  60. pPageObj->Init(pwzADsPath, pwzClass, pBasePathsInfo);
  61. return pPageObj->CreatePage(phPage);
  62. }
  63. //+----------------------------------------------------------------------------
  64. //
  65. // Method: CDsTableDrivenPage::DlgProc
  66. //
  67. // Synopsis: per-instance dialog proc
  68. //
  69. //-----------------------------------------------------------------------------
  70. LRESULT
  71. CDsTableDrivenPage::DlgProc(HWND, UINT uMsg, WPARAM wParam, LPARAM lParam)
  72. {
  73. if (uMsg == g_uChangeMsg)
  74. {
  75. return OnAttrChanged(wParam);
  76. }
  77. switch (uMsg)
  78. {
  79. case WM_INITDIALOG:
  80. return InitDlg(lParam);
  81. case WM_NOTIFY:
  82. return OnNotify(wParam, lParam);
  83. case PSM_QUERYSIBLINGS:
  84. return OnQuerySibs(wParam, lParam);
  85. case WM_ADSPROP_NOTIFY_CHANGE:
  86. return OnObjChanged();
  87. case WM_SHOWWINDOW:
  88. return OnShowWindow();
  89. case WM_SETFOCUS:
  90. return OnSetFocus((HWND)wParam);
  91. case WM_HELP:
  92. return OnHelp((LPHELPINFO)lParam);
  93. case WM_COMMAND:
  94. if (m_fInInit)
  95. {
  96. return TRUE;
  97. }
  98. return(OnCommand(GET_WM_COMMAND_ID(wParam, lParam),
  99. GET_WM_COMMAND_HWND(wParam, lParam),
  100. GET_WM_COMMAND_CMD(wParam, lParam)));
  101. case WM_DESTROY:
  102. return OnDestroy();
  103. default:
  104. return FALSE;
  105. }
  106. return FALSE;
  107. }
  108. //+----------------------------------------------------------------------------
  109. //
  110. // Method: CDsTableDrivenPage::OnInitDialog
  111. //
  112. // Synopsis: Set the initial control values from the corresponding DS
  113. // attributes.
  114. //
  115. //-----------------------------------------------------------------------------
  116. HRESULT CDsTableDrivenPage::OnInitDialog(LPARAM)
  117. {
  118. TRACE(CDsTableDrivenPage,OnInitDialog);
  119. if (!ADsPropSetHwnd(m_hNotifyObj, m_hPage))
  120. {
  121. m_pWritableAttrs = NULL;
  122. }
  123. if (SUCCEEDED(m_hrInit))
  124. {
  125. return ReadAttrsSetCtrls(fInit);
  126. }
  127. else
  128. {
  129. // error page is posted automatically.
  130. return 0;
  131. }
  132. }
  133. //+----------------------------------------------------------------------------
  134. //
  135. // Method: CDsTableDrivenPage::OnApply
  136. //
  137. // Synopsis: Handles the Apply notification.
  138. //
  139. //-----------------------------------------------------------------------------
  140. LRESULT
  141. CDsTableDrivenPage::OnApply(void)
  142. {
  143. TRACE(CDsTableDrivenPage,OnApply);
  144. HRESULT hr = S_OK;
  145. LPTSTR ptsz;
  146. LPWSTR pwszValue;
  147. PADSVALUE pADsValue;
  148. DWORD cAttrs = 0;
  149. if (m_fReadOnly)
  150. {
  151. return PSNRET_NOERROR;
  152. }
  153. PADS_ATTR_INFO pAttrs = new ADS_ATTR_INFO[m_cAttrs];
  154. CHECK_NULL_REPORT(pAttrs, GetHWnd(), return -1);
  155. memset(pAttrs, 0, sizeof(ADS_ATTR_INFO) * m_cAttrs);
  156. for (DWORD i = 0; i < m_cAttrs; i++)
  157. {
  158. if (m_rgpAttrMap[i]->fIsReadOnly ||
  159. (!m_rgpAttrMap[i]->pAttrFcn &&
  160. (!ATTR_DATA_IS_WRITABLE(m_rgAttrData[i]) ||
  161. !ATTR_DATA_IS_DIRTY(m_rgAttrData[i]))))
  162. {
  163. // If the map defines it to be read-only or no attr function is
  164. // defined and the attribute is not writable or not dirty, then
  165. // skip it.
  166. //
  167. continue;
  168. }
  169. pAttrs[cAttrs] = m_rgpAttrMap[i]->AttrInfo;
  170. if (m_rgpAttrMap[i]->pAttrFcn)
  171. {
  172. // Handle special-case attribute.
  173. //
  174. hr = (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i],
  175. &pAttrs[cAttrs], 0,
  176. &m_rgAttrData[i], fApply);
  177. CHECK_HRESULT(hr, goto Cleanup);
  178. if (hr == ADM_S_SKIP)
  179. {
  180. // Don't write the attribute.
  181. //
  182. continue;
  183. }
  184. if (hr != S_FALSE)
  185. {
  186. // If the attr fcn didn't return S_FALSE, that means that it
  187. // handled the value. If it did return S_FALSE, then let the
  188. // standard edit control processing below handle the value.
  189. //
  190. cAttrs++;
  191. continue;
  192. }
  193. }
  194. if (m_rgpAttrMap[i]->AttrInfo.dwADsType == ADSTYPE_BOOLEAN)
  195. {
  196. // Handle boolean checkbox attributes.
  197. //
  198. pADsValue = new ADSVALUE;
  199. CHECK_NULL_REPORT(pADsValue, GetHWnd(), goto Cleanup);
  200. pAttrs[cAttrs].pADsValues = pADsValue;
  201. pAttrs[cAttrs].dwNumValues = 1;
  202. pADsValue->dwType = m_rgpAttrMap[i]->AttrInfo.dwADsType;
  203. pADsValue->Boolean =
  204. IsDlgButtonChecked(m_hPage, m_rgpAttrMap[i]->nCtrlID)
  205. == BST_CHECKED;
  206. cAttrs++;
  207. continue;
  208. }
  209. // Assumes that all non-special-case attributes,
  210. // if single-valued and not boolean, come from a text control.
  211. //
  212. ptsz = new TCHAR[m_rgpAttrMap[i]->nSizeLimit + 1];
  213. CHECK_NULL_REPORT(ptsz, GetHWnd(), goto Cleanup);
  214. GetDlgItemText(m_hPage, m_rgpAttrMap[i]->nCtrlID, ptsz,
  215. m_rgpAttrMap[i]->nSizeLimit + 1);
  216. CStr csValue = ptsz;
  217. csValue.TrimLeft();
  218. csValue.TrimRight();
  219. if (_tcslen(ptsz) != (size_t)csValue.GetLength())
  220. {
  221. // the length is different, it must have been trimmed. Write trimmed
  222. // value back to the control.
  223. //
  224. SetDlgItemText(m_hPage, m_rgpAttrMap[i]->nCtrlID, const_cast<PTSTR>((LPCTSTR)csValue));
  225. }
  226. delete ptsz;
  227. if (csValue.IsEmpty())
  228. {
  229. // An empty control means remove the attribute value from the
  230. // object.
  231. //
  232. pAttrs[cAttrs].dwControlCode = ADS_ATTR_CLEAR;
  233. pAttrs[cAttrs].dwNumValues = 0;
  234. pAttrs[cAttrs].pADsValues = NULL;
  235. cAttrs++;
  236. continue;
  237. }
  238. if (!TcharToUnicode(const_cast<PTSTR>((LPCTSTR)csValue), &pwszValue))
  239. {
  240. CHECK_HRESULT_REPORT(E_OUTOFMEMORY, GetHWnd(), goto Cleanup);
  241. }
  242. pADsValue = new ADSVALUE;
  243. CHECK_NULL_REPORT(pADsValue, GetHWnd(), goto Cleanup);
  244. pAttrs[cAttrs].pADsValues = pADsValue;
  245. pAttrs[cAttrs].dwNumValues = 1;
  246. pADsValue->dwType = m_rgpAttrMap[i]->AttrInfo.dwADsType;
  247. switch (pADsValue->dwType)
  248. {
  249. case ADSTYPE_DN_STRING:
  250. pADsValue->DNString = pwszValue;
  251. break;
  252. case ADSTYPE_CASE_EXACT_STRING:
  253. pADsValue->CaseExactString = pwszValue;
  254. break;
  255. case ADSTYPE_CASE_IGNORE_STRING:
  256. pADsValue->CaseIgnoreString = pwszValue;
  257. break;
  258. case ADSTYPE_PRINTABLE_STRING:
  259. pADsValue->PrintableString = pwszValue;
  260. break;
  261. case ADSTYPE_NUMERIC_STRING:
  262. pADsValue->NumericString = pwszValue;
  263. break;
  264. case ADSTYPE_INTEGER:
  265. pADsValue->Integer = _wtoi(pwszValue);
  266. break;
  267. default:
  268. dspDebugOut((DEB_ERROR, "OnApply: Unknown ADS Type %x\n",
  269. pADsValue->dwType));
  270. }
  271. cAttrs++;
  272. }
  273. // cAttrs could be zero if a page was read-only. Don't call ADSI if so.
  274. //
  275. if (cAttrs < 1)
  276. {
  277. goto Cleanup;
  278. }
  279. dspDebugOut((DEB_USER1, "TablePage, about to write %d attrs.\n", cAttrs));
  280. //
  281. // Write the changes.
  282. //
  283. DWORD cModified;
  284. hr = m_pDsObj->SetObjectAttributes(pAttrs, cAttrs, &cModified);
  285. CHECK_ADS_HR(&hr, m_hPage);
  286. Cleanup:
  287. for (i = 0; i < cAttrs; i++)
  288. HelperDeleteADsValues( &(pAttrs[i]) );
  289. delete pAttrs;
  290. if (SUCCEEDED(hr) && cAttrs > 0)
  291. {
  292. for (i = 0; i < m_cAttrs; i++)
  293. {
  294. ATTR_DATA_CLEAR_DIRTY(m_rgAttrData[i]);
  295. }
  296. }
  297. return SUCCEEDED(hr) ? PSNRET_NOERROR : PSNRET_INVALID_NOCHANGEPAGE;
  298. }
  299. void HelperDeleteADsValues( ADS_ATTR_INFO* pAttrs )
  300. {
  301. if (pAttrs && pAttrs->pADsValues)
  302. {
  303. for (DWORD j = 0; j < pAttrs->dwNumValues; j++)
  304. {
  305. LPWSTR pwszValue = NULL;
  306. switch (pAttrs->dwADsType)
  307. {
  308. case ADSTYPE_DN_STRING:
  309. pwszValue = pAttrs->pADsValues[j].DNString;
  310. break;
  311. case ADSTYPE_CASE_EXACT_STRING:
  312. pwszValue = pAttrs->pADsValues[j].CaseExactString;
  313. break;
  314. case ADSTYPE_CASE_IGNORE_STRING:
  315. pwszValue = pAttrs->pADsValues[j].CaseIgnoreString;
  316. break;
  317. case ADSTYPE_PRINTABLE_STRING:
  318. pwszValue = pAttrs->pADsValues[j].PrintableString;
  319. break;
  320. case ADSTYPE_NUMERIC_STRING:
  321. pwszValue = pAttrs->pADsValues[j].NumericString;
  322. break;
  323. }
  324. if (pwszValue)
  325. delete pwszValue;
  326. }
  327. }
  328. delete pAttrs->pADsValues;
  329. pAttrs->pADsValues = NULL;
  330. pAttrs->dwNumValues = 0;
  331. }
  332. //+----------------------------------------------------------------------------
  333. //
  334. // Method: CDsTableDrivenPage::OnCommand
  335. //
  336. // Synopsis: Handle control notifications.
  337. //
  338. // Notes: Standard multi-valued attribute handling assumes that the
  339. // "modify" button has an ID that is one greater than the
  340. // corresponding combo box.
  341. //
  342. //-----------------------------------------------------------------------------
  343. LRESULT
  344. CDsTableDrivenPage::OnCommand(int id, HWND hwndCtl, UINT codeNotify)
  345. {
  346. if (m_fInInit)
  347. {
  348. return 0;
  349. }
  350. HRESULT hr;
  351. DWORD i;
  352. for (i = 0; i < m_cAttrs; i++)
  353. {
  354. if (id == m_rgpAttrMap[i]->nCtrlID)
  355. {
  356. // Give attr functions first crack at the command notification.
  357. //
  358. if (m_rgpAttrMap[i]->pAttrFcn)
  359. {
  360. hr = (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i], NULL,
  361. codeNotify, &m_rgAttrData[i],
  362. fOnCommand);
  363. if (hr == S_FALSE)
  364. {
  365. // If the attr function returns S_FALSE, then don't return
  366. // to the base class OnCommand.
  367. //
  368. return 0;
  369. }
  370. else
  371. {
  372. continue;
  373. }
  374. }
  375. if (codeNotify == BN_CLICKED &&
  376. m_rgpAttrMap[i]->AttrInfo.dwADsType == ADSTYPE_BOOLEAN)
  377. {
  378. // NOTE: Must do this to allow saving from the WAB-hosted sheet.
  379. EnableWindow(GetDlgItem(GetParent(m_hPage), IDOK), TRUE);
  380. // NOTE: end hack.
  381. // The check box was clicked.
  382. //
  383. SetDirty(i);
  384. return CDsPropPageBase::OnCommand(id, hwndCtl, codeNotify);
  385. }
  386. if (codeNotify == EN_CHANGE)
  387. {
  388. // NOTE: Must do this to allow saving from the WAB-hosted sheet.
  389. EnableWindow(GetDlgItem(GetParent(m_hPage), IDOK), TRUE);
  390. // Note: End Hack.
  391. SetDirty(i);
  392. }
  393. }
  394. }
  395. return CDsPropPageBase::OnCommand(id, hwndCtl, codeNotify);
  396. }
  397. //+----------------------------------------------------------------------------
  398. //
  399. // Method: CDsTableDrivenPage::OnObjChanged
  400. //
  401. // Synopsis: Object Change notification for inter-sheet syncronization.
  402. // Handles the private WM_ADSPROP_NOTIFY_CHANGE message.
  403. //
  404. //-----------------------------------------------------------------------------
  405. LRESULT
  406. CDsTableDrivenPage::OnObjChanged(void)
  407. {
  408. TRACE(CDsTableDrivenPage,OnObjChanged);
  409. return ReadAttrsSetCtrls(fObjChanged);
  410. }
  411. //+----------------------------------------------------------------------------
  412. //
  413. // Method: CDsTableDrivenPage::ReadAttrsSetCtrls
  414. //
  415. // Synopsis: Refreshes the UI.
  416. //
  417. //-----------------------------------------------------------------------------
  418. HRESULT
  419. CDsTableDrivenPage::ReadAttrsSetCtrls(DLG_OP DlgOp)
  420. {
  421. HRESULT hr = S_OK;
  422. PADS_ATTR_INFO pAttrs = NULL;
  423. DWORD cAttrs = 0, i, j;
  424. CWaitCursor wait;
  425. PWSTR * rgpwszAttrNames = new LPWSTR[m_cAttrs];
  426. CHECK_NULL_REPORT(rgpwszAttrNames, GetHWnd(), return E_OUTOFMEMORY);
  427. if (fInit == DlgOp)
  428. {
  429. // Check what attributes are writable.
  430. //
  431. CheckIfPageAttrsWritable();
  432. }
  433. // Build the list of attribute names.
  434. //
  435. for (i = 0; i < m_cAttrs; i++)
  436. {
  437. // If the attr name in the table is null, then don't try to do a
  438. // fetch on that attr. Attr table entries of that sort are used for
  439. // special purposes such as push buttons or check boxes. If the
  440. // attr name is set to null, then the attr must be declared as read-
  441. // only.
  442. //
  443. if (m_rgpAttrMap[i]->AttrInfo.pszAttrName)
  444. {
  445. // If the attribute already appears in the attribute list
  446. // then don't add it again
  447. bool fAlreadyPresent = false;
  448. for (j = 0; j < cAttrs; j++)
  449. {
  450. if ( _wcsicmp(m_rgpAttrMap[i]->AttrInfo.pszAttrName,
  451. rgpwszAttrNames[j] ) == 0 )
  452. {
  453. fAlreadyPresent = true;
  454. break;
  455. }
  456. }
  457. if (!fAlreadyPresent)
  458. {
  459. rgpwszAttrNames[cAttrs] = m_rgpAttrMap[i]->AttrInfo.pszAttrName;
  460. cAttrs++;
  461. }
  462. }
  463. }
  464. // Get the attribute values.
  465. //
  466. hr = m_pDsObj->GetObjectAttributes(rgpwszAttrNames, cAttrs, &pAttrs,
  467. &cAttrs);
  468. if (!CHECK_ADS_HR_IGNORE_UNFOUND_ATTR(&hr, m_hPage))
  469. {
  470. goto ExitCleanup;
  471. }
  472. // The returned values are a subset of the requested values. Loop over
  473. // both sets, checking for matches.
  474. //
  475. // JonN 5/5/98 Removed assumption that returned values are in same order,
  476. // added support for multiple table entries for same attribute (all but
  477. // one must be read-only)
  478. //
  479. for (i = 0; i < m_cAttrs; i++)
  480. {
  481. if (!ATTR_DATA_IS_WRITABLE(m_rgAttrData[i]) &&
  482. !m_rgpAttrMap[i]->fIsReadOnly &&
  483. !m_rgpAttrMap[i]->pAttrFcn)
  484. {
  485. // If user does not have write permission for the attribute and
  486. // the control is not already read-only and there is no attr
  487. // function then disable the control.
  488. //
  489. if (ADSTYPE_CASE_IGNORE_STRING == m_rgpAttrMap[i]->AttrInfo.dwADsType &&
  490. !m_rgpAttrMap[i]->fIsMultiValued)
  491. {
  492. // If it is a single-valued text attribute, make its edit box
  493. // read only.
  494. //
  495. SendDlgItemMessage(m_hPage, m_rgpAttrMap[i]->nCtrlID, EM_SETREADONLY, (WPARAM)TRUE, 0);
  496. }
  497. else
  498. {
  499. EnableWindow(GetDlgItem(m_hPage, m_rgpAttrMap[i]->nCtrlID), FALSE);
  500. }
  501. }
  502. BOOL fFound = FALSE;
  503. for (j = 0; j < cAttrs; j++)
  504. {
  505. if (m_rgpAttrMap[i]->AttrInfo.pszAttrName &&
  506. _wcsicmp(m_rgpAttrMap[i]->AttrInfo.pszAttrName,
  507. pAttrs[j].pszAttrName) == 0)
  508. {
  509. dspAssert(!fFound);
  510. fFound = TRUE;
  511. if (m_rgpAttrMap[i]->AttrInfo.dwADsType != pAttrs[j].dwADsType)
  512. {
  513. dspDebugOut((DEB_ITRACE,
  514. "ADsType: from table = %d, returned = %d.\n",
  515. m_rgpAttrMap[i]->AttrInfo.dwADsType,
  516. pAttrs[j].dwADsType));
  517. m_rgpAttrMap[i]->AttrInfo.dwADsType = pAttrs[j].dwADsType;
  518. }
  519. if (m_rgpAttrMap[i]->pAttrFcn)
  520. {
  521. // Handle special-case attribute
  522. //
  523. hr = (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i],
  524. &pAttrs[j], 0,
  525. &m_rgAttrData[i], DlgOp);
  526. if (hr != S_FALSE)
  527. {
  528. // If the attr function returns S_FALSE, that means
  529. // let the standard text control processing below
  530. // display the value.
  531. //
  532. break;
  533. }
  534. }
  535. dspAssert(pAttrs[j].dwNumValues > 0);
  536. if (m_rgpAttrMap[i]->AttrInfo.dwADsType == ADSTYPE_BOOLEAN)
  537. {
  538. // Handle boolean attribute, initialize the checkbox.
  539. //
  540. if (pAttrs[j].pADsValues->Boolean)
  541. {
  542. CheckDlgButton(m_hPage, m_rgpAttrMap[i]->nCtrlID,
  543. BST_CHECKED);
  544. }
  545. break;
  546. }
  547. // Assumes that all non-special-case attributes, if
  548. // single-valued and not boolean, go into a text control.
  549. //
  550. SendDlgItemMessage(m_hPage, m_rgpAttrMap[i]->nCtrlID,
  551. EM_LIMITTEXT, m_rgpAttrMap[i]->nSizeLimit,
  552. 0);
  553. LPTSTR ptszValue = NULL;
  554. LPWSTR pwszValue;
  555. WCHAR wszNum[64];
  556. switch (pAttrs[j].dwADsType)
  557. {
  558. case ADSTYPE_DN_STRING:
  559. pwszValue = pAttrs[j].pADsValues->DNString;
  560. break;
  561. case ADSTYPE_CASE_EXACT_STRING:
  562. pwszValue = pAttrs[j].pADsValues->CaseExactString;
  563. break;
  564. case ADSTYPE_CASE_IGNORE_STRING:
  565. pwszValue = pAttrs[j].pADsValues->CaseIgnoreString;
  566. break;
  567. case ADSTYPE_PRINTABLE_STRING:
  568. pwszValue = pAttrs[j].pADsValues->PrintableString;
  569. break;
  570. case ADSTYPE_NUMERIC_STRING:
  571. pwszValue = pAttrs[j].pADsValues->NumericString;
  572. break;
  573. case ADSTYPE_INTEGER:
  574. wsprintfW(wszNum, L"%d", pAttrs[j].pADsValues->Integer);
  575. pwszValue = wszNum;
  576. break;
  577. case ADSTYPE_LARGE_INTEGER:
  578. __int64 i64;
  579. memcpy(&i64, &pAttrs[j].pADsValues->LargeInteger,
  580. sizeof(pAttrs[j].pADsValues->LargeInteger));
  581. swprintf(wszNum, L"%I64d", i64);
  582. pwszValue = wszNum;
  583. break;
  584. default:
  585. dspDebugOut((DEB_ERROR, "Unknown ADS Type %x\n",
  586. pAttrs[j].dwADsType));
  587. pwszValue = L"";
  588. }
  589. if (!UnicodeToTchar(pwszValue, &ptszValue))
  590. {
  591. goto ExitCleanup;
  592. }
  593. SetDlgItemText(m_hPage, m_rgpAttrMap[i]->nCtrlID, ptszValue);
  594. delete ptszValue;
  595. break;
  596. }
  597. }
  598. if (!fFound)
  599. {
  600. if (m_rgpAttrMap[i]->pAttrFcn)
  601. {
  602. (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i], NULL,
  603. 0, &m_rgAttrData[i], DlgOp);
  604. continue;
  605. }
  606. if (!m_rgpAttrMap[i]->fIsMultiValued)
  607. {
  608. SendDlgItemMessage(m_hPage, m_rgpAttrMap[i]->nCtrlID,
  609. EM_LIMITTEXT, m_rgpAttrMap[i]->nSizeLimit,
  610. 0);
  611. switch (m_rgpAttrMap[i]->AttrInfo.dwADsType)
  612. {
  613. case ADSTYPE_DN_STRING:
  614. case ADSTYPE_CASE_EXACT_STRING:
  615. case ADSTYPE_CASE_IGNORE_STRING:
  616. case ADSTYPE_PRINTABLE_STRING:
  617. case ADSTYPE_NUMERIC_STRING:
  618. SetDlgItemText(m_hPage, m_rgpAttrMap[i]->nCtrlID, TEXT(""));
  619. break;
  620. }
  621. }
  622. }
  623. }
  624. ExitCleanup:
  625. if (pAttrs)
  626. {
  627. FreeADsMem(pAttrs);
  628. }
  629. delete rgpwszAttrNames;
  630. return hr;
  631. }
  632. //+----------------------------------------------------------------------------
  633. //
  634. // Method: CDsTableDrivenPage::OnAttrChanged
  635. //
  636. // Synopsis: Attribute Change notification for inter-page syncronization.
  637. // Handles the private DSPROP_ATTRCHANGED_MSG message.
  638. //
  639. // Arguments: wParam - contains a pointer to an ADS_ATTR_INFO that contains
  640. // the changed attribute value. The attribute is named
  641. // in this struct, so it is self-describing.
  642. //
  643. //-----------------------------------------------------------------------------
  644. LRESULT
  645. CDsTableDrivenPage::OnAttrChanged(WPARAM wParam)
  646. {
  647. if (m_fInInit)
  648. {
  649. return 0;
  650. }
  651. for (DWORD i = 0; i < m_cAttrs; i++)
  652. {
  653. // Call attr functions.
  654. //
  655. if (m_rgpAttrMap[i]->pAttrFcn)
  656. {
  657. (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i],
  658. (PADS_ATTR_INFO)wParam, 0,
  659. &m_rgAttrData[i], fAttrChange);
  660. }
  661. }
  662. return 0;
  663. }
  664. //+----------------------------------------------------------------------------
  665. //
  666. // Method: CDsTableDrivenPage::OnQuerySibs
  667. //
  668. // Synopsis: Inter-page communication. Handles the PSM_QUERYSIBLINGS msg.
  669. //
  670. // Arguments: wParam - pointer to the name of the attribute in question.
  671. // lParam - HWND of the page that wants to know if the attr has
  672. // changed.
  673. //
  674. //-----------------------------------------------------------------------------
  675. LRESULT
  676. CDsTableDrivenPage::OnQuerySibs(WPARAM wParam, LPARAM lParam)
  677. {
  678. if (m_fInInit)
  679. {
  680. return 0;
  681. }
  682. LRESULT ret = 0;
  683. HRESULT hr;
  684. for (DWORD i = 0; i < m_cAttrs; i++)
  685. {
  686. // Call attr functions.
  687. //
  688. if (m_rgpAttrMap[i]->pAttrFcn)
  689. {
  690. hr = (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i],
  691. (PADS_ATTR_INFO)wParam, lParam,
  692. &m_rgAttrData[i], fQuerySibling);
  693. if (hr != S_OK)
  694. {
  695. ret = hr;
  696. }
  697. }
  698. }
  699. return ret;
  700. }
  701. //+----------------------------------------------------------------------------
  702. //
  703. // Method: CDsTableDrivenPage::OnNotify
  704. //
  705. // Synopsis: Handles notification messages
  706. //
  707. // Arguments: [lParam] - a pointer to a NMHDR structure.
  708. // [wParam] - the control ID.
  709. //
  710. //-----------------------------------------------------------------------------
  711. LRESULT
  712. CDsTableDrivenPage::OnNotify(WPARAM wParam, LPARAM lParam)
  713. {
  714. DWORD i;
  715. HRESULT hr = S_OK;
  716. switch (((LPNMHDR)lParam)->code)
  717. {
  718. case PSN_SETACTIVE:
  719. case PSN_KILLACTIVE:
  720. if (m_fInInit)
  721. {
  722. return 0;
  723. }
  724. for (i = 0; i < m_cAttrs; i++)
  725. {
  726. // Call attr functions.
  727. //
  728. if (m_rgpAttrMap[i]->pAttrFcn)
  729. {
  730. hr = (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i], NULL,
  731. lParam,
  732. &m_rgAttrData[i],
  733. (PSN_SETACTIVE == ((LPNMHDR)lParam)->code) ?
  734. fOnSetActive : fOnKillActive);
  735. if (PSNRET_INVALID_NOCHANGEPAGE == HRESULT_CODE(hr))
  736. {
  737. SetWindowLongPtr(m_hPage, DWLP_MSGRESULT,
  738. (LONG_PTR)PSNRET_INVALID_NOCHANGEPAGE);
  739. return PSNRET_INVALID_NOCHANGEPAGE;
  740. }
  741. }
  742. }
  743. break;
  744. default:
  745. if (!m_fInInit)
  746. {
  747. for (i = 0; i < m_cAttrs; i++)
  748. {
  749. // Call attr functions.
  750. //
  751. if (m_rgpAttrMap[i]->pAttrFcn)
  752. {
  753. (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i], NULL,
  754. lParam,
  755. &m_rgAttrData[i], fOnNotify);
  756. }
  757. }
  758. }
  759. break;
  760. }
  761. return CDsPropPageBase::OnNotify(wParam, lParam);
  762. }
  763. //+----------------------------------------------------------------------------
  764. //
  765. // Method: CDsTableDrivenPage::OnDestroy
  766. //
  767. // Synopsis: Exit cleanup
  768. //
  769. //-----------------------------------------------------------------------------
  770. LRESULT
  771. CDsTableDrivenPage::OnDestroy(void)
  772. {
  773. if (FAILED(m_hrInit))
  774. {
  775. return 0;
  776. }
  777. //
  778. // Allow attr functions to do control cleanup.
  779. //
  780. for (DWORD i = 0; i < m_cAttrs; i++)
  781. {
  782. if (m_rgpAttrMap[i]->pAttrFcn)
  783. {
  784. (*m_rgpAttrMap[i]->pAttrFcn)(this, m_rgpAttrMap[i], NULL,
  785. 0, &m_rgAttrData[i], fOnDestroy);
  786. }
  787. }
  788. // If an application processes this message, it should return zero.
  789. return 0;
  790. }
  791. //+----------------------------------------------------------------------------
  792. //
  793. // Method: CDsTableDrivenPage::SetNamedAttrDirty
  794. //
  795. // Synopsis: Set a specific attribute dirty
  796. //
  797. //-----------------------------------------------------------------------------
  798. BOOL CDsTableDrivenPage::SetNamedAttrDirty( LPCWSTR pszAttrName )
  799. {
  800. for (DWORD i = 0; i < m_cAttrs; i++)
  801. {
  802. if ( NULL != m_rgpAttrMap[i]->AttrInfo.pszAttrName
  803. && !_wcsicmp(pszAttrName, m_rgpAttrMap[i]->AttrInfo.pszAttrName)
  804. && !m_rgpAttrMap[i]->fIsReadOnly
  805. )
  806. {
  807. SetDirty(i);
  808. return TRUE;
  809. }
  810. }
  811. return FALSE;
  812. }
  813. //+----------------------------------------------------------------------------
  814. //
  815. // Function: GeneralPageIcon
  816. //
  817. // Synopsis: Fetches the icon for the object class from the display spec
  818. // cache and draws it on the page. The GenIcon ATTR_MAP uses the
  819. // control ID IDC_DS_ICON. To use this, add an icon control to
  820. // your page sized appropriately (20 x 20) and labeled
  821. // IDC_DS_ICON, then add GenIcon to your ATTR_MAP array.
  822. //
  823. //-----------------------------------------------------------------------------
  824. HRESULT GeneralPageIcon(CDsPropPageBase * pPage, PATTR_MAP pAttrMap,
  825. PADS_ATTR_INFO, LPARAM, PATTR_DATA pAttrData,
  826. DLG_OP DlgOp)
  827. {
  828. HRESULT hr;
  829. HICON hIcon;
  830. HWND hIconCtrl;
  831. CDsIconCtrl * pIconCtrl;
  832. switch (DlgOp)
  833. {
  834. case fInit:
  835. IDsDisplaySpecifier * pDispSpec;
  836. hr = pPage->GetIDispSpec(&pDispSpec);
  837. CHECK_HRESULT(hr, return hr);
  838. hIconCtrl = GetDlgItem(pPage->GetHWnd(), pAttrMap->nCtrlID);
  839. hIcon = pDispSpec->GetIcon(pPage->GetObjClass(),
  840. DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON,
  841. 32, 32);
  842. // NULL return puts up a default icon
  843. CHECK_NULL(hIcon, return S_OK);
  844. pIconCtrl = new CDsIconCtrl(hIconCtrl, hIcon);
  845. CHECK_NULL_REPORT(pIconCtrl, pPage->GetHWnd(), return E_OUTOFMEMORY);
  846. pAttrData->pVoid = reinterpret_cast<LPARAM>(pIconCtrl);
  847. break;
  848. case fOnDestroy:
  849. if (pAttrData->pVoid)
  850. {
  851. pIconCtrl = (CDsIconCtrl *)pAttrData->pVoid;
  852. DO_DEL(pIconCtrl);
  853. }
  854. break;
  855. }
  856. return S_OK;
  857. }
  858. //+----------------------------------------------------------------------------
  859. //
  860. // Class: CDsIconCtrl
  861. //
  862. // Synopsis: Icon control window subclass object, so we can paint a class-
  863. // specific icon.
  864. //
  865. //-----------------------------------------------------------------------------
  866. CDsIconCtrl::CDsIconCtrl(HWND hCtrl, HICON hIcon) :
  867. m_hCtrl(hCtrl),
  868. m_hIcon(hIcon),
  869. m_pOldProc(NULL)
  870. {
  871. SetWindowLongPtr(hCtrl, GWLP_USERDATA, (LONG_PTR)this);
  872. m_pOldProc = (WNDPROC)SetWindowLongPtr(hCtrl, GWLP_WNDPROC, (LONG_PTR)StaticCtrlProc);
  873. m_hDlg = GetParent(hCtrl);
  874. }
  875. CDsIconCtrl::~CDsIconCtrl(void)
  876. {
  877. SetWindowLongPtr(m_hCtrl, GWLP_WNDPROC, (LONG_PTR)m_pOldProc);
  878. DestroyIcon(m_hIcon);
  879. }
  880. //+----------------------------------------------------------------------------
  881. //
  882. // Method: CDsIconCtrl::StaticCtrlProc
  883. //
  884. // Synopsis: control sub-proc
  885. //
  886. //-----------------------------------------------------------------------------
  887. LRESULT CALLBACK
  888. CDsIconCtrl::StaticCtrlProc(HWND hCtrl, UINT uMsg, WPARAM wParam, LPARAM lParam)
  889. {
  890. CDsIconCtrl * pCCtrl = (CDsIconCtrl*)GetWindowLongPtr(hCtrl, GWLP_USERDATA);
  891. if (pCCtrl != NULL)
  892. {
  893. if (uMsg == WM_PAINT)
  894. {
  895. if (!pCCtrl->OnPaint())
  896. {
  897. return FALSE;
  898. }
  899. }
  900. return CallWindowProc(pCCtrl->m_pOldProc, hCtrl, uMsg, wParam, lParam);
  901. }
  902. else
  903. {
  904. return DefWindowProc(hCtrl, uMsg, wParam, lParam);
  905. }
  906. }
  907. //+----------------------------------------------------------------------------
  908. //
  909. // Method: CDsIconCtrl::OnPaint
  910. //
  911. // Synopsis: Paint the DS specified icon.
  912. //
  913. //-----------------------------------------------------------------------------
  914. LRESULT
  915. CDsIconCtrl::OnPaint(void)
  916. {
  917. HDC hDC;
  918. PAINTSTRUCT ps;
  919. hDC = BeginPaint(m_hCtrl, &ps);
  920. CHECK_NULL_REPORT(hDC, m_hDlg, return FALSE);
  921. if (!DrawIcon(hDC, 0, 0, m_hIcon))
  922. {
  923. REPORT_ERROR(GetLastError(), m_hDlg);
  924. return FALSE;
  925. }
  926. EndPaint(m_hCtrl, &ps);
  927. return TRUE;
  928. }