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.

1338 lines
38 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Windows NT Directory Service Property Pages
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1999
  7. //
  8. // File: propbase.cxx
  9. //
  10. // Contents: CDsPropPageBase, the base class for property page classes.
  11. //
  12. // History: 31-March-97 EricB created
  13. //
  14. //-----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #include "proppage.h"
  17. //+----------------------------------------------------------------------------
  18. //
  19. // Member: CADsApplyErrors::~CADsApplyErrors
  20. //
  21. //-----------------------------------------------------------------------------
  22. CADsApplyErrors::~CADsApplyErrors()
  23. {
  24. if (m_pszTitle != NULL)
  25. {
  26. delete[] m_pszTitle;
  27. }
  28. Clear();
  29. }
  30. //+----------------------------------------------------------------------------
  31. //
  32. // Member: CADsApplyErrors::SetError
  33. //
  34. //-----------------------------------------------------------------------------
  35. void CADsApplyErrors::SetError(PADSPROPERROR pError)
  36. {
  37. if (m_nCount == m_nArraySize)
  38. {
  39. PAPPLY_ERROR_ENTRY pNewTable = new APPLY_ERROR_ENTRY[m_nCount + m_nIncAmount];
  40. m_nArraySize = m_nCount + m_nIncAmount;
  41. if (pNewTable != NULL)
  42. {
  43. memset(pNewTable, 0, sizeof(APPLY_ERROR_ENTRY) * (m_nCount + m_nIncAmount));
  44. if (m_pErrorTable != NULL)
  45. {
  46. for (UINT nIdx = 0; nIdx < m_nCount; nIdx++)
  47. {
  48. pNewTable[nIdx].pszPath = m_pErrorTable[nIdx].pszPath;
  49. pNewTable[nIdx].pszClass = m_pErrorTable[nIdx].pszClass;
  50. pNewTable[nIdx].hr = m_pErrorTable[nIdx].hr;
  51. pNewTable[nIdx].pszStringError = m_pErrorTable[nIdx].pszStringError;
  52. }
  53. delete[] m_pErrorTable;
  54. }
  55. m_pErrorTable = pNewTable;
  56. }
  57. }
  58. //
  59. // Copy the path to the object
  60. //
  61. if (pError->pszObjPath != NULL)
  62. {
  63. m_pErrorTable[m_nCount].pszPath = new WCHAR[wcslen(pError->pszObjPath) + 1];
  64. dspAssert(m_pErrorTable[m_nCount].pszPath != NULL);
  65. if (m_pErrorTable[m_nCount].pszPath != NULL)
  66. {
  67. wcscpy(m_pErrorTable[m_nCount].pszPath, pError->pszObjPath);
  68. }
  69. }
  70. //
  71. // Copy the class to the object
  72. //
  73. if (pError->pszObjClass != NULL)
  74. {
  75. // Note: this memory is freed in the Clear() method which is called from
  76. // the class destructor
  77. m_pErrorTable[m_nCount].pszClass = new WCHAR[wcslen(pError->pszObjClass) + 1];
  78. dspAssert(m_pErrorTable[m_nCount].pszClass != NULL);
  79. if (m_pErrorTable[m_nCount].pszClass != NULL)
  80. {
  81. wcscpy(m_pErrorTable[m_nCount].pszClass, pError->pszObjClass);
  82. }
  83. }
  84. //
  85. // Copy the error
  86. //
  87. if (pError->hr != S_OK)
  88. {
  89. m_pErrorTable[m_nCount].hr = pError->hr;
  90. }
  91. else
  92. {
  93. if (pError->pszError != NULL)
  94. {
  95. m_pErrorTable[m_nCount].pszStringError = new WCHAR[wcslen(pError->pszError) + 1];
  96. dspAssert(m_pErrorTable[m_nCount].pszStringError != NULL);
  97. if (m_pErrorTable[m_nCount].pszStringError != NULL)
  98. {
  99. wcscpy(m_pErrorTable[m_nCount].pszStringError, pError->pszError);
  100. }
  101. }
  102. }
  103. //
  104. // Copy the page title
  105. //
  106. if (pError->pszPageTitle != NULL)
  107. {
  108. m_pszTitle = new WCHAR[wcslen(pError->pszPageTitle) + 1];
  109. if (m_pszTitle != NULL)
  110. {
  111. wcscpy(m_pszTitle, pError->pszPageTitle);
  112. }
  113. }
  114. m_nCount++;
  115. }
  116. //+----------------------------------------------------------------------------
  117. //
  118. // Member: CADsApplyErrors::GetError
  119. //
  120. //-----------------------------------------------------------------------------
  121. HRESULT CADsApplyErrors::GetError(UINT nIndex)
  122. {
  123. dspAssert(nIndex < m_nCount);
  124. if (nIndex < m_nCount)
  125. {
  126. return m_pErrorTable[nIndex].hr;
  127. }
  128. return S_FALSE;
  129. }
  130. //+----------------------------------------------------------------------------
  131. //
  132. // Member: CADsApplyErrors::GetStringError
  133. //
  134. //-----------------------------------------------------------------------------
  135. PWSTR CADsApplyErrors::GetStringError(UINT nIndex)
  136. {
  137. dspAssert(nIndex < m_nCount);
  138. if (nIndex < m_nCount)
  139. {
  140. return m_pErrorTable[nIndex].pszStringError;
  141. }
  142. return NULL;
  143. }
  144. //+----------------------------------------------------------------------------
  145. //
  146. // Member: CADsApplyErrors::Clear
  147. //
  148. //-----------------------------------------------------------------------------
  149. void CADsApplyErrors::Clear()
  150. {
  151. if (m_pErrorTable != NULL)
  152. {
  153. for (UINT idx = 0; idx < m_nCount; idx++)
  154. {
  155. if (m_pErrorTable[idx].pszPath != NULL)
  156. {
  157. delete[] m_pErrorTable[idx].pszPath;
  158. m_pErrorTable[idx].pszPath = NULL;
  159. }
  160. if (m_pErrorTable[idx].pszClass != NULL)
  161. {
  162. delete[] m_pErrorTable[idx].pszClass;
  163. m_pErrorTable[idx].pszClass = NULL;
  164. }
  165. if (m_pErrorTable[idx].pszStringError != NULL)
  166. {
  167. delete[] m_pErrorTable[idx].pszStringError;
  168. m_pErrorTable[idx].pszStringError = NULL;
  169. }
  170. }
  171. delete[] m_pErrorTable;
  172. m_pErrorTable = NULL;
  173. }
  174. m_nCount = 0;
  175. m_nArraySize = 0;
  176. }
  177. //+----------------------------------------------------------------------------
  178. //
  179. // Member: CADsApplyErrors::GetName
  180. //
  181. //-----------------------------------------------------------------------------
  182. PWSTR CADsApplyErrors::GetName(UINT nIndex)
  183. {
  184. dspAssert(nIndex < m_nCount);
  185. if (nIndex < m_nCount)
  186. {
  187. return m_pErrorTable[nIndex].pszPath;
  188. }
  189. return NULL;
  190. }
  191. //+----------------------------------------------------------------------------
  192. //
  193. // Member: CADsApplyErrors::GetClass
  194. //
  195. //-----------------------------------------------------------------------------
  196. PWSTR CADsApplyErrors::GetClass(UINT nIndex)
  197. {
  198. dspAssert(nIndex < m_nCount);
  199. if (nIndex < m_nCount)
  200. {
  201. return m_pErrorTable[nIndex].pszClass;
  202. }
  203. return NULL;
  204. }
  205. //+----------------------------------------------------------------------------
  206. //
  207. // Member: CDsPropPageBase::CDsPropPageBase
  208. //
  209. //-----------------------------------------------------------------------------
  210. CDsPropPageBase::CDsPropPageBase(PDSPAGE pDsPage, LPDATAOBJECT pDataObj,
  211. HWND hNotifyObj, DWORD dwFlags) :
  212. m_hPage(NULL),
  213. m_fInInit(FALSE),
  214. m_fPageDirty(FALSE),
  215. m_fReadOnly(FALSE),
  216. m_fMultiselectPage(FALSE),
  217. m_pDataObj(pDataObj),
  218. m_pWPTDataObj(NULL),
  219. m_pDataObjStrm(NULL),
  220. m_pDsObj(NULL),
  221. m_nPageTitle(pDsPage->nPageTitle),
  222. m_nDlgTemplate(pDsPage->nDlgTemplate),
  223. m_cAttrs(pDsPage->cAttrs),
  224. m_rgpAttrMap(pDsPage->rgpAttrMap),
  225. m_pwszObjPathName(NULL),
  226. m_pwszObjClass(NULL),
  227. m_pwszRDName(NULL),
  228. m_pDispSpec(NULL),
  229. m_pObjSel(NULL),
  230. m_fObjSelInited(FALSE),
  231. m_rgAttrData(NULL),
  232. m_uRefs(1),
  233. m_hNotifyObj(hNotifyObj),
  234. m_pWritableAttrs(NULL),
  235. m_hrInit(S_OK)
  236. {
  237. TRACE2(CDsPropPageBase,CDsPropPageBase);
  238. //
  239. // Get the read-only state.
  240. //
  241. if (dwFlags & DSOBJECT_READONLYPAGES)
  242. {
  243. m_fReadOnly = TRUE;
  244. }
  245. }
  246. //+----------------------------------------------------------------------------
  247. //
  248. // Member: CDsPropPageBase::~CDsPropPageBase
  249. //
  250. //-----------------------------------------------------------------------------
  251. CDsPropPageBase::~CDsPropPageBase()
  252. {
  253. TRACE2(CDsPropPageBase,~CDsPropPageBase);
  254. if (m_pwszObjPathName)
  255. {
  256. delete m_pwszObjPathName;
  257. }
  258. if (m_pwszObjClass)
  259. {
  260. delete m_pwszObjClass;
  261. }
  262. if (m_pwszRDName)
  263. {
  264. delete m_pwszRDName;
  265. }
  266. if (m_rgAttrData)
  267. {
  268. delete [] m_rgAttrData;
  269. }
  270. if (m_pObjSel)
  271. {
  272. m_pObjSel->Release();
  273. }
  274. if (m_pDispSpec)
  275. {
  276. m_pDispSpec->Release();
  277. }
  278. if (m_pDataObjStrm)
  279. {
  280. m_pDataObjStrm->Release();
  281. }
  282. }
  283. //+----------------------------------------------------------------------------
  284. //
  285. // Method: CDsPropPageBase::Init
  286. //
  287. // Synopsis: Initialize the page object. This is the second part of a two
  288. // phase creation where operations that could fail are located.
  289. // Failures here are recorded in m_hrInit and then an error page
  290. // is substituted in CreatePage.
  291. //
  292. //-----------------------------------------------------------------------------
  293. void
  294. CDsPropPageBase::Init(PWSTR pwzADsPath, LPWSTR pwzClass, const CDSSmartBasePathsInfo& basePathsInfo)
  295. {
  296. TRACE(CDsPropPageBase,Init);
  297. CWaitCursor cWait;
  298. ADSPROPINITPARAMS InitParams = {0};
  299. InitParams.dwSize = sizeof(ADSPROPINITPARAMS);
  300. ADsPropGetInitInfo(m_hNotifyObj, &InitParams);
  301. if (FAILED(InitParams.hr))
  302. {
  303. m_hrInit = InitParams.hr;
  304. return;
  305. }
  306. m_basePathsInfo = basePathsInfo;
  307. if (!AllocWStr(pwzADsPath, &m_pwszObjPathName) ||
  308. !AllocWStr(InitParams.pwzCN, &m_pwszRDName) ||
  309. !AllocWStr(pwzClass, &m_pwszObjClass))
  310. {
  311. m_hrInit = E_OUTOFMEMORY;
  312. return;
  313. }
  314. dspAssert(InitParams.pDsObj);
  315. m_pDsObj = InitParams.pDsObj;
  316. DBG_OUT("+++++++++++++++++++++++++++addrefing object");
  317. m_pDsObj->AddRef();
  318. m_pWritableAttrs = InitParams.pWritableAttrs;
  319. //
  320. // Allocate memory for the attribute data.
  321. //
  322. m_rgAttrData = new ATTR_DATA[m_cAttrs];
  323. CHECK_NULL(m_rgAttrData, m_hrInit = E_OUTOFMEMORY; return);
  324. memset(m_rgAttrData, 0, m_cAttrs * sizeof(ATTR_DATA));
  325. //
  326. // Marshall the data object pointer for passing to the window proc thread.
  327. //
  328. HRESULT hr = CoMarshalInterThreadInterfaceInStream(IID_IDataObject, m_pDataObj,
  329. &m_pDataObjStrm);
  330. m_pDataObj = NULL; // to make sure no one calls here
  331. CHECK_HRESULT(hr, m_hrInit = hr; return);
  332. }
  333. //+----------------------------------------------------------------------------
  334. //
  335. // Method: CDsPropPageBase::CreatePage
  336. //
  337. // Synopsis: Create the prop page
  338. //
  339. //-----------------------------------------------------------------------------
  340. HRESULT
  341. CDsPropPageBase::CreatePage(HPROPSHEETPAGE * phPage)
  342. {
  343. TCHAR szTitle[MAX_PATH];
  344. if (!LoadStringReport(m_nPageTitle, szTitle, MAX_PATH, NULL))
  345. {
  346. return HRESULT_FROM_WIN32(GetLastError());
  347. }
  348. PROPSHEETPAGE psp;
  349. psp.dwSize = sizeof(PROPSHEETPAGE);
  350. psp.dwFlags = PSP_USECALLBACK | PSP_USETITLE;
  351. psp.pszTemplate = MAKEINTRESOURCE((SUCCEEDED(m_hrInit)) ? m_nDlgTemplate : IDD_ERROR_PAGE);
  352. psp.pfnDlgProc = StaticDlgProc;
  353. psp.pfnCallback = PageCallback;
  354. psp.pcRefParent = NULL; // do not set PSP_USEREFPARENT
  355. psp.lParam = (LPARAM) this;
  356. psp.hInstance = g_hInstance;
  357. psp.pszTitle = szTitle;
  358. *phPage = CreatePropertySheetPage(&psp);
  359. if (*phPage == NULL)
  360. {
  361. return HRESULT_FROM_WIN32(GetLastError());
  362. }
  363. return S_OK;
  364. }
  365. //+----------------------------------------------------------------------------
  366. //
  367. // Method: CDsPropPageBase::StaticDlgProc
  368. //
  369. // Synopsis: static dialog proc
  370. //
  371. //-----------------------------------------------------------------------------
  372. INT_PTR CALLBACK
  373. CDsPropPageBase::StaticDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  374. {
  375. CDsPropPageBase * pPage = (CDsPropPageBase *)GetWindowLongPtr(hDlg, DWLP_USER);
  376. if (uMsg == WM_INITDIALOG)
  377. {
  378. LPPROPSHEETPAGE ppsp = (LPPROPSHEETPAGE)lParam;
  379. pPage = (CDsPropPageBase *) ppsp->lParam;
  380. pPage->m_hPage = hDlg;
  381. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pPage);
  382. if (pPage->m_pDataObjStrm)
  383. {
  384. // Unmarshall the Data Object pointer.
  385. //
  386. HRESULT hr;
  387. hr = CoGetInterfaceAndReleaseStream(pPage->m_pDataObjStrm,
  388. IID_IDataObject,
  389. reinterpret_cast<void**>(&pPage->m_pWPTDataObj));
  390. CHECK_HRESULT_REPORT(hr, hDlg, return FALSE);
  391. // The stream should have been released above so set the
  392. // pointer to NULL so that we don't try to release again
  393. pPage->m_pDataObjStrm = 0;
  394. }
  395. return pPage->DlgProc(hDlg, uMsg, wParam, lParam);
  396. }
  397. if (pPage != NULL && (SUCCEEDED(pPage->m_hrInit)))
  398. {
  399. if (uMsg == WM_ADSPROP_PAGE_GET_NOTIFY)
  400. {
  401. HWND* pHWnd = (HWND*)wParam;
  402. *pHWnd = pPage->m_hNotifyObj;
  403. return TRUE;
  404. }
  405. return pPage->DlgProc(hDlg, uMsg, wParam, lParam);
  406. }
  407. return FALSE;
  408. }
  409. //+----------------------------------------------------------------------------
  410. //
  411. // Method: CDsPropPageBase::InitDlg
  412. //
  413. // Synopsis: Handles dialog initialization for error cases. Passes non-
  414. // error initialization to subclass' OnInitDialog.
  415. //
  416. //-----------------------------------------------------------------------------
  417. LRESULT CDsPropPageBase::InitDlg(LPARAM lParam)
  418. {
  419. m_fInInit = TRUE;
  420. if (FAILED(m_hrInit))
  421. {
  422. // Bind to the object failed, display an error page with the error
  423. // message string.
  424. //
  425. PTSTR ptz = NULL;
  426. BOOL fSpecialCaseErr = TRUE;
  427. switch (HRESULT_CODE(m_hrInit))
  428. {
  429. case ERROR_DS_NO_ATTRIBUTE_OR_VALUE:
  430. LoadStringToTchar(IDS_ERROR_VIEW_PERMISSIONS, &ptz);
  431. break;
  432. case ERROR_DS_REFERRAL:
  433. LoadStringToTchar(IDS_ERRMSG_NO_DC_RESPONSE, &ptz);
  434. break;
  435. case ERROR_DS_NO_SUCH_OBJECT:
  436. LoadStringToTchar(IDS_ERRMSG_NO_LONGER_EXISTS, &ptz);
  437. break;
  438. default:
  439. fSpecialCaseErr = FALSE;
  440. break;
  441. }
  442. if (fSpecialCaseErr && ptz)
  443. {
  444. SetWindowText(GetDlgItem(m_hPage, IDC_ERROR_MSG), ptz);
  445. delete ptz;
  446. }
  447. else
  448. {
  449. int cch;
  450. cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  451. | FORMAT_MESSAGE_FROM_SYSTEM, NULL, m_hrInit,
  452. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  453. (PTSTR)&ptz, 0, NULL);
  454. if (!cch)
  455. {
  456. // Try ADSI errors.
  457. //
  458. cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  459. | FORMAT_MESSAGE_FROM_HMODULE,
  460. GetModuleHandle(TEXT("activeds.dll")), m_hrInit,
  461. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  462. (PTSTR)&ptz, 0, NULL);
  463. }
  464. if (cch)
  465. {
  466. SetWindowText(GetDlgItem(m_hPage, IDC_ERROR_MSG), ptz);
  467. LocalFree(ptz);
  468. }
  469. }
  470. m_fInInit = FALSE;
  471. return S_OK;
  472. }
  473. HRESULT hResult = OnInitDialog(lParam);
  474. m_fInInit = FALSE;
  475. return hResult;
  476. }
  477. //+----------------------------------------------------------------------------
  478. //
  479. // Method: CDsPropPageBase::OnNotify
  480. //
  481. // Synopsis: Handles notification messages
  482. //
  483. //-----------------------------------------------------------------------------
  484. LRESULT
  485. CDsPropPageBase::OnNotify(WPARAM, LPARAM lParam)
  486. {
  487. LRESULT lResult;
  488. BOOL fPageDirty;
  489. switch (((LPNMHDR)lParam)->code)
  490. {
  491. case PSN_APPLY:
  492. if (FAILED(m_hrInit))
  493. {
  494. return PSNRET_NOERROR;
  495. }
  496. lResult = PSNRET_NOERROR;
  497. //
  498. // The member var m_fPageDirty gets cleared in OnApply, so save a local
  499. // copy for passing as the wParam of the WM_ADSPROP_NOTIFY_APPLY msg.
  500. //
  501. fPageDirty = m_fPageDirty;
  502. if (m_fPageDirty)
  503. {
  504. // Call the virtual function OnApply()
  505. lResult = OnApply();
  506. }
  507. // Store the result into the dialog
  508. SetWindowLongPtr(m_hPage, DWLP_MSGRESULT, (LONG_PTR)lResult);
  509. if (lResult == PSNRET_NOERROR)
  510. {
  511. m_fPageDirty = FALSE;
  512. //
  513. // Signal the change notification. Note that the notify-apply
  514. // message must be sent even if the page is not dirty so that the
  515. // notify ref-counting will properly decrement.
  516. //
  517. SendMessage(m_hNotifyObj, WM_ADSPROP_NOTIFY_APPLY, fPageDirty, (LPARAM)m_hPage);
  518. }
  519. else
  520. {
  521. EnableWindow(GetDlgItem(GetParent(m_hPage), IDCANCEL), TRUE);
  522. }
  523. return lResult;
  524. case PSN_RESET:
  525. OnCancel();
  526. return FALSE; // allow the property sheet to be destroyed.
  527. case PSN_SETACTIVE:
  528. return OnPSNSetActive(lParam);
  529. case PSN_KILLACTIVE:
  530. return OnPSNKillActive(lParam);
  531. }
  532. return TRUE;
  533. }
  534. //+----------------------------------------------------------------------------
  535. //
  536. // Method: CDsPropPageBase::OnCommand
  537. //
  538. // Synopsis: Handles the WM_COMMAND message
  539. //
  540. //-----------------------------------------------------------------------------
  541. LRESULT
  542. CDsPropPageBase::OnCommand(int id, HWND hwndCtl, UINT codeNotify)
  543. {
  544. dspDebugOut((DEB_USER3, "CDsPropPageBase::OnCommand - id: %d, code: %x\n",
  545. id, codeNotify));
  546. if ((codeNotify == EN_CHANGE) && !m_fInInit)
  547. {
  548. SetDirty();
  549. }
  550. if ((codeNotify == BN_CLICKED) && (id == IDCANCEL))
  551. {
  552. //
  553. // Pressing ESC in a multi-line edit control results in this
  554. // WM_COMMAND being sent. Pass it on to the parent (the sheet proc) to
  555. // close the sheet.
  556. //
  557. PostMessage(GetParent(m_hPage), WM_COMMAND, MAKEWPARAM(id, codeNotify),
  558. (LPARAM)hwndCtl);
  559. }
  560. return 0;
  561. }
  562. //+----------------------------------------------------------------------------
  563. //
  564. // Method: CDsPropPageBase::CheckIfPageAttrsWritable
  565. //
  566. // Synopsis: See which attributes are writable by checking if they are in
  567. // the allowedAttributesEffective array.
  568. //
  569. // Notes: The m_rgAttrData array is 1 to 1 with the m_rgpAttrMap array.
  570. //-----------------------------------------------------------------------------
  571. void
  572. CDsPropPageBase::CheckIfPageAttrsWritable(void)
  573. {
  574. DWORD iAllowed;
  575. if (m_fReadOnly || !m_pWritableAttrs)
  576. {
  577. return;
  578. }
  579. for (DWORD iAttrs = 0; iAttrs < m_cAttrs; iAttrs++)
  580. {
  581. if (m_rgpAttrMap[iAttrs]->AttrInfo.pszAttrName)
  582. {
  583. for (iAllowed = 0; iAllowed < m_pWritableAttrs->dwNumValues; iAllowed++)
  584. {
  585. if (_wcsicmp(m_rgpAttrMap[iAttrs]->AttrInfo.pszAttrName,
  586. m_pWritableAttrs->pADsValues[iAllowed].CaseIgnoreString) == 0)
  587. {
  588. ATTR_DATA_SET_WRITABLE(m_rgAttrData[iAttrs]);
  589. break;
  590. }
  591. }
  592. }
  593. }
  594. return;
  595. }
  596. //+----------------------------------------------------------------------------
  597. //
  598. // Method: CDsPropPageBase::CheckIfWritable
  599. //
  600. // Synopsis: See if the attribute is writable by checking if it is in
  601. // the allowedAttributesEffective array.
  602. //
  603. //-----------------------------------------------------------------------------
  604. BOOL
  605. CDsPropPageBase::CheckIfWritable(const PWSTR & wzAttr)
  606. {
  607. BOOL fWritable = FALSE;
  608. if (m_fReadOnly || !m_pWritableAttrs)
  609. {
  610. return FALSE;
  611. }
  612. for (DWORD i = 0; i < m_pWritableAttrs->dwNumValues; i++)
  613. {
  614. if (_wcsicmp(m_pWritableAttrs->pADsValues[i].CaseIgnoreString,
  615. wzAttr) == 0)
  616. {
  617. fWritable = TRUE;
  618. break;
  619. }
  620. }
  621. return fWritable;
  622. }
  623. //+----------------------------------------------------------------------------
  624. //
  625. // Method: CDsPropPageBase::OnCancel
  626. //
  627. // Synopsis:
  628. //
  629. //-----------------------------------------------------------------------------
  630. LRESULT
  631. CDsPropPageBase::OnCancel(void)
  632. {
  633. return FALSE;
  634. }
  635. //+----------------------------------------------------------------------------
  636. //
  637. // Method: CDsPropPageBase::OnSetFocus
  638. //
  639. // Synopsis:
  640. //
  641. //-----------------------------------------------------------------------------
  642. LRESULT
  643. CDsPropPageBase::OnSetFocus(HWND)
  644. {
  645. // An application should return zero if it processes this message.
  646. return 1;
  647. }
  648. //+----------------------------------------------------------------------------
  649. //
  650. // Method: CDsPropPageBase::OnPSNSetActive
  651. //
  652. // Synopsis: Page activation event.
  653. //
  654. //-----------------------------------------------------------------------------
  655. LRESULT
  656. CDsPropPageBase::OnPSNSetActive(LPARAM)
  657. {
  658. SetWindowLongPtr(m_hPage, DWLP_MSGRESULT, 0);
  659. return TRUE;
  660. }
  661. //+----------------------------------------------------------------------------
  662. //
  663. // Method: CDsPropPageBase::OnPSNKillActive
  664. //
  665. // Synopsis: Page deactivation event (when other pages cover this one).
  666. //
  667. //-----------------------------------------------------------------------------
  668. LRESULT
  669. CDsPropPageBase::OnPSNKillActive(LPARAM)
  670. {
  671. SetWindowLongPtr(m_hPage, DWLP_MSGRESULT, 0);
  672. return TRUE;
  673. }
  674. //+----------------------------------------------------------------------------
  675. //
  676. // Method: CDsPropPageBase::OnDestroy
  677. //
  678. // Synopsis: Exit cleanup
  679. //
  680. //-----------------------------------------------------------------------------
  681. LRESULT
  682. CDsPropPageBase::OnDestroy(void)
  683. {
  684. return 1;
  685. }
  686. //+----------------------------------------------------------------------------
  687. //
  688. // Method: CDsPropPageBase::OnShowWindow
  689. //
  690. // Synopsis: On dialog window show operations, resizes the view window.
  691. //
  692. //-----------------------------------------------------------------------------
  693. LRESULT
  694. CDsPropPageBase::OnShowWindow(void)
  695. {
  696. return 0;
  697. }
  698. //+----------------------------------------------------------------------------
  699. //
  700. // Method: CDsPropPageBase::GetIDispSpec
  701. //
  702. // Synopsis: If needed, create the interface instance and return the pointer.
  703. //
  704. //-----------------------------------------------------------------------------
  705. HRESULT
  706. CDsPropPageBase::GetIDispSpec(IDsDisplaySpecifier ** ppDispSpec)
  707. {
  708. HRESULT hr;
  709. TRACE2(CDsPropPageBase, GetIDispSpec);
  710. if (!m_pDispSpec)
  711. {
  712. hr = CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER,
  713. IID_IDsDisplaySpecifier, (PVOID *)&m_pDispSpec);
  714. CHECK_HRESULT(hr, return hr);
  715. CStrW strDC;
  716. CComPtr<IDirectoryObject> spDsObj;
  717. if (m_pDsObj == NULL)
  718. {
  719. //
  720. // For the retrieval of the DS Object names
  721. //
  722. FORMATETC fmte = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  723. STGMEDIUM objMedium;
  724. hr = m_pWPTDataObj->GetData(&fmte, &objMedium);
  725. CHECK_HRESULT(hr, return hr);
  726. LPDSOBJECTNAMES pDsObjectNames = (LPDSOBJECTNAMES)objMedium.hGlobal;
  727. //
  728. // Get the objects path
  729. //
  730. LPWSTR pwzObjADsPath = (PWSTR)ByteOffset(pDsObjectNames,
  731. pDsObjectNames->aObjects[0].offsetName);
  732. //
  733. // Bind to the object
  734. //
  735. hr = DSAdminOpenObject(pwzObjADsPath,
  736. IID_IDirectoryObject,
  737. (PVOID*)&spDsObj);
  738. ReleaseStgMedium(&objMedium);
  739. CHECK_HRESULT(hr, return hr);
  740. }
  741. else
  742. {
  743. spDsObj = m_pDsObj;
  744. }
  745. hr = GetLdapServerName(spDsObj, strDC);
  746. CHECK_HRESULT(hr, return hr);
  747. hr = m_pDispSpec->SetServer(strDC, NULL, NULL, 0);
  748. CHECK_HRESULT(hr, return hr);
  749. }
  750. if (ppDispSpec)
  751. {
  752. *ppDispSpec = m_pDispSpec;
  753. }
  754. return S_OK;
  755. }
  756. //+----------------------------------------------------------------------------
  757. //
  758. // Method: CDsPropPageBase::GetADsPathname
  759. //
  760. // Synopsis: If needed, create the interface instance and return the pointer.
  761. //
  762. //-----------------------------------------------------------------------------
  763. HRESULT
  764. CDsPropPageBase::GetADsPathname(CComPtr<IADsPathname>& refADsPath)
  765. {
  766. HRESULT hr;
  767. if (!m_pADsPath)
  768. {
  769. hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
  770. IID_IADsPathname, (PVOID *)&m_pADsPath);
  771. CHECK_HRESULT(hr, return hr);
  772. }
  773. refADsPath = m_pADsPath;
  774. return S_OK;
  775. }
  776. //+----------------------------------------------------------------------------
  777. //
  778. // Method: CDsPropPageBase::SkipPrefix
  779. //
  780. // Synopsis: Given an object name, returns a buffer containing the same
  781. // name without the provider/server prefix. The buffer must be
  782. // freed using delete.
  783. //
  784. // Notes: The fX500 parameter defaults to true and applies whenever the
  785. // input path uses the LDAP provider prefix. The path cracker
  786. // interface can be used to strip the prefix in this case. However,
  787. // if the provider is WINNT, then the path cracker doesn't give the
  788. // desired results so simple string manipulation is used instead.
  789. //-----------------------------------------------------------------------------
  790. HRESULT
  791. CDsPropPageBase::SkipPrefix(PWSTR pwzObj, PWSTR * ppResult, BOOL fX500)
  792. {
  793. if (fX500)
  794. {
  795. // Strip of the "LDAP://" prefix using the path cracker.
  796. //
  797. CComPtr<IADsPathname> spPathname;
  798. HRESULT hr = GetADsPathname(spPathname);
  799. CHECK_HRESULT(hr, return hr);
  800. hr = spPathname->Set(CComBSTR(pwzObj), ADS_SETTYPE_FULL);
  801. CHECK_HRESULT(hr, return hr);
  802. BSTR bstr;
  803. hr = spPathname->Retrieve(ADS_FORMAT_X500_DN, &bstr);
  804. CHECK_HRESULT(hr, return hr);
  805. if (!AllocWStr(bstr, ppResult))
  806. {
  807. SysFreeString(bstr);
  808. return E_OUTOFMEMORY;
  809. }
  810. SysFreeString(bstr);
  811. }
  812. else
  813. {
  814. // Strip off the "WINNT://" prefix.
  815. //
  816. if (wcslen(pwzObj) < 9 || pwzObj[7] != L'/')
  817. {
  818. // Can't be a valid WINNT name if not at least "WINNT://x"
  819. //
  820. return E_INVALIDARG;
  821. }
  822. if (!AllocWStr(&pwzObj[8], ppResult))
  823. {
  824. return E_OUTOFMEMORY;
  825. }
  826. }
  827. return S_OK;
  828. }
  829. //+----------------------------------------------------------------------------
  830. //
  831. // Method: CDsPropPageBase::AddLdapPrefix
  832. //
  833. // Synopsis: Given an object name, returns same name with the LDAP provider
  834. // prefix. The server name is also added by default.
  835. //
  836. //-----------------------------------------------------------------------------
  837. HRESULT
  838. CDsPropPageBase::AddLDAPPrefix(PWSTR pwzObj, CStrW &pstrResult, BOOL fServer)
  839. {
  840. return ::AddLDAPPrefix(this, pwzObj, pstrResult, fServer);
  841. }
  842. //
  843. // Non-class member version.
  844. //
  845. HRESULT
  846. AddLDAPPrefix(CDsPropPageBase * pPage, PWSTR pwzObj, CStrW &strResult,
  847. BOOL fServer)
  848. {
  849. HRESULT hr;
  850. CComPtr<IADsPathname> spPathCracker;
  851. strResult.Empty();
  852. if (pPage)
  853. {
  854. hr = pPage->GetADsPathname(spPathCracker);
  855. CHECK_HRESULT(hr, return hr);
  856. }
  857. else
  858. {
  859. hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
  860. IID_IADsPathname, (PVOID *)&spPathCracker);
  861. CHECK_HRESULT(hr, return hr);
  862. }
  863. hr = spPathCracker->Set(CComBSTR(L"LDAP"), ADS_SETTYPE_PROVIDER);
  864. CHECK_HRESULT(hr, return hr);
  865. if (pPage)
  866. {
  867. CStrW strDC;
  868. CComPtr<IDirectoryObject> spDsObj;
  869. if (pPage->m_pDsObj == NULL)
  870. {
  871. //
  872. // For the retrieval of the DS Object names
  873. //
  874. FORMATETC fmte = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  875. STGMEDIUM objMedium;
  876. hr = pPage->m_pWPTDataObj->GetData(&fmte, &objMedium);
  877. CHECK_HRESULT(hr, return hr);
  878. LPDSOBJECTNAMES pDsObjectNames = (LPDSOBJECTNAMES)objMedium.hGlobal;
  879. //
  880. // Get the objects path
  881. //
  882. LPWSTR pwzObjADsPath = (PWSTR)ByteOffset(pDsObjectNames,
  883. pDsObjectNames->aObjects[0].offsetName);
  884. //
  885. // Bind to the object
  886. //
  887. hr = DSAdminOpenObject(pwzObjADsPath,
  888. IID_IDirectoryObject,
  889. (PVOID*)&spDsObj);
  890. ReleaseStgMedium(&objMedium);
  891. CHECK_HRESULT(hr, return hr);
  892. }
  893. else
  894. {
  895. spDsObj = pPage->m_pDsObj;
  896. }
  897. hr = GetLdapServerName(spDsObj, strDC);
  898. CHECK_HRESULT(hr, return hr);
  899. hr = spPathCracker->Set(CComBSTR(strDC), ADS_SETTYPE_SERVER);
  900. CHECK_HRESULT(hr, return hr);
  901. }
  902. hr = spPathCracker->Set(CComBSTR(pwzObj), ADS_SETTYPE_DN);
  903. CHECK_HRESULT(hr, return hr);
  904. CComBSTR bstr;
  905. hr = spPathCracker->Retrieve((fServer) ? ADS_FORMAT_X500 : ADS_FORMAT_X500_NO_SERVER,
  906. &bstr);
  907. CHECK_HRESULT(hr, return hr);
  908. strResult = bstr;
  909. return S_OK;
  910. }
  911. //+----------------------------------------------------------------------------
  912. //
  913. // Method: CDsPropPageBase::GetObjSel
  914. //
  915. // Synopsis: CoCreates the object picker if needed, returns the pointer.
  916. //
  917. //-----------------------------------------------------------------------------
  918. HRESULT
  919. CDsPropPageBase::GetObjSel(IDsObjectPicker ** ppObjSel, PBOOL pfIsInited)
  920. {
  921. HRESULT hr;
  922. TRACE2(CDsPropPageBase,GetObjSel);
  923. if (!m_pObjSel)
  924. {
  925. hr = CoCreateInstance(CLSID_DsObjectPicker, NULL, CLSCTX_INPROC_SERVER,
  926. IID_IDsObjectPicker, (PVOID *)&m_pObjSel);
  927. if (FAILED(hr))
  928. {
  929. REPORT_ERROR(hr, m_hPage);
  930. return hr;
  931. }
  932. }
  933. *ppObjSel = m_pObjSel;
  934. if (pfIsInited)
  935. {
  936. *pfIsInited = m_fObjSelInited;
  937. }
  938. return S_OK;
  939. }
  940. #ifdef DO_HELP
  941. #include "helpids.h"
  942. #endif
  943. //+----------------------------------------------------------------------------
  944. //
  945. // Method: CDsPropPageBase::OnHelp
  946. //
  947. // Synopsis: Put up popup help for the control.
  948. //
  949. //-----------------------------------------------------------------------------
  950. LRESULT
  951. CDsPropPageBase::OnHelp(LPHELPINFO pHelpInfo)
  952. {
  953. dspDebugOut((DEB_ITRACE, "WM_HELP: CtrlId = %d, ContextId = 0x%x\n",
  954. pHelpInfo->iCtrlId, pHelpInfo->dwContextId));
  955. if (pHelpInfo->iCtrlId < 1 || IDH_NO_HELP == pHelpInfo->dwContextId)
  956. {
  957. return 0;
  958. }
  959. WinHelp(m_hPage, DSPROP_HELP_FILE_NAME, HELP_CONTEXTPOPUP, pHelpInfo->dwContextId);
  960. #ifdef DONT_DO_THIS
  961. WinHelp((HWND)pHelpInfo->hItemHandle, DSPROP_HELP_FILE_NAME, HELP_WM_HELP, (DWORD)g_aHelpIDs);
  962. #endif
  963. return 0;
  964. }
  965. //+----------------------------------------------------------------------------
  966. //
  967. // Method: CDsPropPageBase::PageCallback
  968. //
  969. // Synopsis: Callback used to free the CDsPropPageBase object when the
  970. // property sheet has been destroyed.
  971. //
  972. //-----------------------------------------------------------------------------
  973. UINT CALLBACK
  974. CDsPropPageBase::PageCallback(HWND hDlg, UINT uMsg, LPPROPSHEETPAGE ppsp)
  975. {
  976. TRACE_FUNCTION(CDsPropPageBase::PageCallback);
  977. if (uMsg == PSPCB_RELEASE)
  978. {
  979. //
  980. // Determine instance that invoked this static function
  981. //
  982. CDsPropPageBase * pPage = (CDsPropPageBase *) ppsp->lParam;
  983. //
  984. // Call all function pointers so that they can do any needed cleanup.
  985. //
  986. if (SUCCEEDED(pPage->m_hrInit))
  987. {
  988. for (DWORD i = 0; i < pPage->m_cAttrs; i++)
  989. {
  990. if (pPage->m_rgpAttrMap[i]->pAttrFcn)
  991. {
  992. (*pPage->m_rgpAttrMap[i]->pAttrFcn)(pPage,
  993. pPage->m_rgpAttrMap[i],
  994. NULL, 0,
  995. &pPage->m_rgAttrData[i],
  996. fOnCallbackRelease);
  997. }
  998. }
  999. }
  1000. if (IsWindow(pPage->m_hNotifyObj))
  1001. {
  1002. SendMessage(pPage->m_hNotifyObj, WM_ADSPROP_NOTIFY_EXIT, 0, 0);
  1003. }
  1004. // Release on same thread on which created.
  1005. //
  1006. DO_RELEASE(pPage->m_pWPTDataObj);
  1007. //DBG_OUT("-----------------------releasing object in page callback.");
  1008. DO_RELEASE(pPage->m_pDsObj);
  1009. dspDebugOut((DEB_ITRACE, "Deleting CDsPropPageBase instance 0x%x\n",
  1010. pPage));
  1011. pPage->Release();
  1012. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)NULL);
  1013. }
  1014. return TRUE;
  1015. }
  1016. //+----------------------------------------------------------------------------
  1017. //
  1018. // Member: CDsPropPageBase::IUnknown::QueryInterface
  1019. //
  1020. // Synopsis: Returns requested interface pointer
  1021. //
  1022. //-----------------------------------------------------------------------------
  1023. STDMETHODIMP
  1024. CDsPropPageBase::QueryInterface(REFIID riid, void ** ppvObject)
  1025. {
  1026. TRACE2(CDsPropPageBase,QueryInterface);
  1027. if (IID_IUnknown == riid)
  1028. {
  1029. *ppvObject = (IUnknown *)this;
  1030. }
  1031. else
  1032. {
  1033. *ppvObject = NULL;
  1034. return E_NOINTERFACE;
  1035. }
  1036. AddRef();
  1037. return S_OK;
  1038. }
  1039. //+----------------------------------------------------------------------------
  1040. //
  1041. // Member: CDsPropPageBase::IUnknown::AddRef
  1042. //
  1043. // Synopsis: increments reference count
  1044. //
  1045. // Returns: the reference count
  1046. //
  1047. //-----------------------------------------------------------------------------
  1048. STDMETHODIMP_(ULONG)
  1049. CDsPropPageBase::AddRef(void)
  1050. {
  1051. dspDebugOut((DEB_USER2, "CDsPropPageBase::AddRef refcount going in %d\n", m_uRefs));
  1052. return InterlockedIncrement((long *)&m_uRefs);
  1053. }
  1054. //+----------------------------------------------------------------------------
  1055. //
  1056. // Member: CDsPropPageBase::IUnknown::Release
  1057. //
  1058. // Synopsis: Decrements the object's reference count and frees it when
  1059. // no longer referenced.
  1060. //
  1061. // Returns: zero if the reference count is zero or non-zero otherwise
  1062. //
  1063. //-----------------------------------------------------------------------------
  1064. STDMETHODIMP_(ULONG)
  1065. CDsPropPageBase::Release(void)
  1066. {
  1067. dspDebugOut((DEB_USER2, "CDsPropPageBase::Release ref count going in %d\n", m_uRefs));
  1068. unsigned long uTmp;
  1069. if ((uTmp = InterlockedDecrement((long *)&m_uRefs)) == 0)
  1070. {
  1071. delete this;
  1072. }
  1073. return uTmp;
  1074. }
  1075. //+----------------------------------------------------------------------------
  1076. //
  1077. // Function: GetLdapServerName
  1078. //
  1079. // Synopsis: Given an IDirectoryObject* that supports IADsObjectOptions, it
  1080. // returns the server name ADSI is bound to.
  1081. //
  1082. //-----------------------------------------------------------------------------
  1083. HRESULT
  1084. GetLdapServerName(IUnknown * pDsObj, CStrW& strServer)
  1085. {
  1086. HRESULT hr;
  1087. strServer.Empty();
  1088. CComPtr<IADsObjectOptions> spIADsObjectOptions;
  1089. hr = pDsObj->QueryInterface(IID_IADsObjectOptions, (void**)&spIADsObjectOptions);
  1090. CHECK_HRESULT(hr, return hr);
  1091. CComVariant var;
  1092. hr = spIADsObjectOptions->GetOption(ADS_OPTION_SERVERNAME, &var);
  1093. CHECK_HRESULT(hr, return hr);
  1094. dspAssert(var.vt == VT_BSTR);
  1095. strServer = V_BSTR(&var);
  1096. return hr;
  1097. }
  1098. //+----------------------------------------------------------------------------
  1099. //
  1100. // Function: BindToGCcopyOfObj
  1101. //
  1102. // Synopsis: Bind to the GC copy of the object.
  1103. //
  1104. //-----------------------------------------------------------------------------
  1105. HRESULT
  1106. BindToGCcopyOfObj(CDsPropPageBase * pPage, PWSTR pwzObjADsPath,
  1107. IDirectoryObject ** ppDsObj)
  1108. {
  1109. CSmartWStr cswzCleanObj;
  1110. PWSTR pwzDnsDom;
  1111. PDOMAIN_CONTROLLER_INFOW pDCInfo;
  1112. HRESULT hr = pPage->SkipPrefix(pwzObjADsPath, &cswzCleanObj);
  1113. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  1114. // To bind to a GC, you need to supply the tree root domain name rather
  1115. // than the server path because the current DC/domain may not be hosting a
  1116. // GC.
  1117. //
  1118. hr = CrackName(cswzCleanObj, &pwzDnsDom, GET_DNS_DOMAIN_NAME, pPage->GetHWnd());
  1119. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  1120. DWORD dwErr = DsGetDcNameW(NULL,
  1121. pwzDnsDom,
  1122. NULL,NULL,
  1123. DS_DIRECTORY_SERVICE_REQUIRED,
  1124. &pDCInfo);
  1125. LocalFreeStringW(&pwzDnsDom);
  1126. hr = HRESULT_FROM_WIN32(dwErr);
  1127. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  1128. CComPtr<IADsPathname> spADsPath;
  1129. long lEscapeMode;
  1130. hr = pPage->GetADsPathname(spADsPath);
  1131. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  1132. spADsPath->get_EscapedMode(&lEscapeMode);
  1133. hr = spADsPath->Set(CComBSTR(L"GC"), ADS_SETTYPE_PROVIDER);
  1134. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  1135. hr = spADsPath->Set(CComBSTR(pDCInfo->DnsForestName), ADS_SETTYPE_SERVER);
  1136. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  1137. NetApiBufferFree(pDCInfo);
  1138. hr = spADsPath->Set(CComBSTR((PCWSTR)cswzCleanObj), ADS_SETTYPE_DN);
  1139. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  1140. spADsPath->put_EscapedMode(ADS_ESCAPEDMODE_ON);
  1141. CComBSTR bstrEscapedPath;
  1142. hr = spADsPath->Retrieve(ADS_FORMAT_X500, &bstrEscapedPath);
  1143. // restore defaults
  1144. spADsPath->Set(CComBSTR(L"LDAP"), ADS_SETTYPE_PROVIDER);
  1145. spADsPath->put_EscapedMode(lEscapeMode);
  1146. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  1147. dspDebugOut((DEB_ITRACE, "Binding to object at %ws\n", bstrEscapedPath));
  1148. hr = DSAdminOpenObject(bstrEscapedPath,
  1149. IID_IDirectoryObject,
  1150. (PVOID*)ppDsObj);
  1151. return hr;
  1152. }