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.

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