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.

1333 lines
37 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. m_pBasePathsInfo(0)
  237. {
  238. TRACE2(CDsPropPageBase,CDsPropPageBase);
  239. //
  240. // Get the read-only state.
  241. //
  242. if (dwFlags & DSOBJECT_READONLYPAGES)
  243. {
  244. m_fReadOnly = TRUE;
  245. }
  246. }
  247. //+----------------------------------------------------------------------------
  248. //
  249. // Member: CDsPropPageBase::~CDsPropPageBase
  250. //
  251. //-----------------------------------------------------------------------------
  252. CDsPropPageBase::~CDsPropPageBase()
  253. {
  254. TRACE2(CDsPropPageBase,~CDsPropPageBase);
  255. if (m_pwszObjPathName)
  256. {
  257. delete m_pwszObjPathName;
  258. }
  259. if (m_pwszObjClass)
  260. {
  261. delete m_pwszObjClass;
  262. }
  263. if (m_pwszRDName)
  264. {
  265. delete m_pwszRDName;
  266. }
  267. if (m_rgAttrData)
  268. {
  269. delete [] m_rgAttrData;
  270. }
  271. if (m_pObjSel)
  272. {
  273. m_pObjSel->Release();
  274. }
  275. if (m_pDispSpec)
  276. {
  277. m_pDispSpec->Release();
  278. }
  279. if (m_pBasePathsInfo)
  280. {
  281. m_pBasePathsInfo->Release();
  282. }
  283. }
  284. //+----------------------------------------------------------------------------
  285. //
  286. // Method: CDsPropPageBase::Init
  287. //
  288. // Synopsis: Initialize the page object. This is the second part of a two
  289. // phase creation where operations that could fail are located.
  290. // Failures here are recorded in m_hrInit and then an error page
  291. // is substituted in CreatePage.
  292. //
  293. //-----------------------------------------------------------------------------
  294. void
  295. CDsPropPageBase::Init(PWSTR pwzADsPath, LPWSTR pwzClass, CDSBasePathsInfo* pBasePathsInfo)
  296. {
  297. TRACE(CDsPropPageBase,Init);
  298. CWaitCursor cWait;
  299. ADSPROPINITPARAMS InitParams = {0};
  300. InitParams.dwSize = sizeof(ADSPROPINITPARAMS);
  301. ADsPropGetInitInfo(m_hNotifyObj, &InitParams);
  302. if (FAILED(InitParams.hr))
  303. {
  304. m_hrInit = InitParams.hr;
  305. return;
  306. }
  307. if (!pBasePathsInfo)
  308. {
  309. m_hrInit = E_INVALIDARG;
  310. return;
  311. }
  312. m_pBasePathsInfo = pBasePathsInfo;
  313. m_pBasePathsInfo->AddRef();
  314. if (!AllocWStr(pwzADsPath, &m_pwszObjPathName) ||
  315. !AllocWStr(InitParams.pwzCN, &m_pwszRDName) ||
  316. !AllocWStr(pwzClass, &m_pwszObjClass))
  317. {
  318. m_hrInit = E_OUTOFMEMORY;
  319. return;
  320. }
  321. dspAssert(InitParams.pDsObj);
  322. m_pDsObj = InitParams.pDsObj;
  323. DBG_OUT("+++++++++++++++++++++++++++addrefing object");
  324. m_pDsObj->AddRef();
  325. m_pWritableAttrs = InitParams.pWritableAttrs;
  326. //
  327. // Allocate memory for the attribute data.
  328. //
  329. m_rgAttrData = new ATTR_DATA[m_cAttrs];
  330. CHECK_NULL(m_rgAttrData, m_hrInit = E_OUTOFMEMORY; return);
  331. memset(m_rgAttrData, 0, m_cAttrs * sizeof(ATTR_DATA));
  332. //
  333. // Marshall the data object pointer for passing to the window proc thread.
  334. //
  335. HRESULT hr = CoMarshalInterThreadInterfaceInStream(IID_IDataObject, m_pDataObj,
  336. &m_pDataObjStrm);
  337. m_pDataObj = NULL; // to make sure no one calls here
  338. CHECK_HRESULT(hr, m_hrInit = hr; return);
  339. }
  340. //+----------------------------------------------------------------------------
  341. //
  342. // Method: CDsPropPageBase::CreatePage
  343. //
  344. // Synopsis: Create the prop page
  345. //
  346. //-----------------------------------------------------------------------------
  347. HRESULT
  348. CDsPropPageBase::CreatePage(HPROPSHEETPAGE * phPage)
  349. {
  350. TCHAR szTitle[MAX_PATH];
  351. if (!LoadStringReport(m_nPageTitle, szTitle, MAX_PATH, NULL))
  352. {
  353. return HRESULT_FROM_WIN32(GetLastError());
  354. }
  355. PROPSHEETPAGE psp;
  356. psp.dwSize = sizeof(PROPSHEETPAGE);
  357. psp.dwFlags = PSP_USECALLBACK | PSP_USETITLE;
  358. psp.pszTemplate = MAKEINTRESOURCE((SUCCEEDED(m_hrInit)) ? m_nDlgTemplate : IDD_ERROR_PAGE);
  359. psp.pfnDlgProc = (DLGPROC)StaticDlgProc;
  360. psp.pfnCallback = PageCallback;
  361. psp.pcRefParent = NULL; // do not set PSP_USEREFPARENT
  362. psp.lParam = (LPARAM) this;
  363. psp.hInstance = g_hInstance;
  364. psp.pszTitle = szTitle;
  365. *phPage = CreatePropertySheetPage(&psp);
  366. if (*phPage == NULL)
  367. {
  368. return HRESULT_FROM_WIN32(GetLastError());
  369. }
  370. return S_OK;
  371. }
  372. //+----------------------------------------------------------------------------
  373. //
  374. // Method: CDsPropPageBase::StaticDlgProc
  375. //
  376. // Synopsis: static dialog proc
  377. //
  378. //-----------------------------------------------------------------------------
  379. LRESULT CALLBACK
  380. CDsPropPageBase::StaticDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  381. {
  382. CDsPropPageBase * pPage = (CDsPropPageBase *)GetWindowLongPtr(hDlg, DWLP_USER);
  383. if (uMsg == WM_INITDIALOG)
  384. {
  385. LPPROPSHEETPAGE ppsp = (LPPROPSHEETPAGE)lParam;
  386. pPage = (CDsPropPageBase *) ppsp->lParam;
  387. pPage->m_hPage = hDlg;
  388. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)pPage);
  389. if (pPage->m_pDataObjStrm)
  390. {
  391. // Unmarshall the Data Object pointer.
  392. //
  393. HRESULT hr;
  394. hr = CoGetInterfaceAndReleaseStream(pPage->m_pDataObjStrm,
  395. IID_IDataObject,
  396. reinterpret_cast<void**>(&pPage->m_pWPTDataObj));
  397. CHECK_HRESULT_REPORT(hr, hDlg, return FALSE);
  398. }
  399. return pPage->DlgProc(hDlg, uMsg, wParam, lParam);
  400. }
  401. if (pPage != NULL && (SUCCEEDED(pPage->m_hrInit)))
  402. {
  403. if (uMsg == WM_ADSPROP_PAGE_GET_NOTIFY)
  404. {
  405. HWND* pHWnd = (HWND*)wParam;
  406. *pHWnd = pPage->m_hNotifyObj;
  407. return TRUE;
  408. }
  409. return pPage->DlgProc(hDlg, uMsg, wParam, lParam);
  410. }
  411. return FALSE;
  412. }
  413. //+----------------------------------------------------------------------------
  414. //
  415. // Method: CDsPropPageBase::InitDlg
  416. //
  417. // Synopsis: Handles dialog initialization for error cases. Passes non-
  418. // error initialization to subclass' OnInitDialog.
  419. //
  420. //-----------------------------------------------------------------------------
  421. LRESULT CDsPropPageBase::InitDlg(LPARAM lParam)
  422. {
  423. m_fInInit = TRUE;
  424. if (FAILED(m_hrInit))
  425. {
  426. // Bind to the object failed, display an error page with the error
  427. // message string.
  428. //
  429. PTSTR ptz = NULL;
  430. BOOL fSpecialCaseErr = TRUE;
  431. switch (HRESULT_CODE(m_hrInit))
  432. {
  433. case ERROR_DS_NO_ATTRIBUTE_OR_VALUE:
  434. LoadStringToTchar(IDS_ERROR_VIEW_PERMISSIONS, &ptz);
  435. break;
  436. case ERROR_DS_REFERRAL:
  437. LoadStringToTchar(IDS_ERRMSG_NO_DC_RESPONSE, &ptz);
  438. break;
  439. case ERROR_DS_NO_SUCH_OBJECT:
  440. LoadStringToTchar(IDS_ERRMSG_NO_LONGER_EXISTS, &ptz);
  441. break;
  442. default:
  443. fSpecialCaseErr = FALSE;
  444. break;
  445. }
  446. if (fSpecialCaseErr && ptz)
  447. {
  448. SetWindowText(GetDlgItem(m_hPage, IDC_ERROR_MSG), ptz);
  449. delete ptz;
  450. }
  451. else
  452. {
  453. int cch;
  454. cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  455. | FORMAT_MESSAGE_FROM_SYSTEM, NULL, m_hrInit,
  456. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  457. (PTSTR)&ptz, 0, NULL);
  458. if (!cch)
  459. {
  460. // Try ADSI errors.
  461. //
  462. cch = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  463. | FORMAT_MESSAGE_FROM_HMODULE,
  464. GetModuleHandle(TEXT("activeds.dll")), m_hrInit,
  465. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  466. (PTSTR)&ptz, 0, NULL);
  467. }
  468. if (cch)
  469. {
  470. SetWindowText(GetDlgItem(m_hPage, IDC_ERROR_MSG), ptz);
  471. LocalFree(ptz);
  472. }
  473. }
  474. m_fInInit = FALSE;
  475. return S_OK;
  476. }
  477. HRESULT hResult = OnInitDialog(lParam);
  478. m_fInInit = FALSE;
  479. return hResult;
  480. }
  481. //+----------------------------------------------------------------------------
  482. //
  483. // Method: CDsPropPageBase::OnNotify
  484. //
  485. // Synopsis: Handles notification messages
  486. //
  487. //-----------------------------------------------------------------------------
  488. LRESULT
  489. CDsPropPageBase::OnNotify(WPARAM, LPARAM lParam)
  490. {
  491. LRESULT lResult;
  492. BOOL fPageDirty;
  493. switch (((LPNMHDR)lParam)->code)
  494. {
  495. case PSN_APPLY:
  496. if (FAILED(m_hrInit))
  497. {
  498. return PSNRET_NOERROR;
  499. }
  500. lResult = PSNRET_NOERROR;
  501. //
  502. // The member var m_fPageDirty gets cleared in OnApply, so save a local
  503. // copy for passing as the wParam of the WM_ADSPROP_NOTIFY_APPLY msg.
  504. //
  505. fPageDirty = m_fPageDirty;
  506. if (m_fPageDirty)
  507. {
  508. // Call the virtual function OnApply()
  509. lResult = OnApply();
  510. }
  511. // Store the result into the dialog
  512. SetWindowLongPtr(m_hPage, DWLP_MSGRESULT, (LONG_PTR)lResult);
  513. if (lResult == PSNRET_NOERROR)
  514. {
  515. m_fPageDirty = FALSE;
  516. //
  517. // Signal the change notification. Note that the notify-apply
  518. // message must be sent even if the page is not dirty so that the
  519. // notify ref-counting will properly decrement.
  520. //
  521. SendMessage(m_hNotifyObj, WM_ADSPROP_NOTIFY_APPLY, fPageDirty, (LPARAM)m_hPage);
  522. }
  523. else
  524. {
  525. EnableWindow(GetDlgItem(GetParent(m_hPage), IDCANCEL), TRUE);
  526. }
  527. return lResult;
  528. case PSN_RESET:
  529. OnCancel();
  530. return FALSE; // allow the property sheet to be destroyed.
  531. case PSN_SETACTIVE:
  532. return OnPSNSetActive(lParam);
  533. case PSN_KILLACTIVE:
  534. return OnPSNKillActive(lParam);
  535. }
  536. return TRUE;
  537. }
  538. //+----------------------------------------------------------------------------
  539. //
  540. // Method: CDsPropPageBase::OnCommand
  541. //
  542. // Synopsis: Handles the WM_COMMAND message
  543. //
  544. //-----------------------------------------------------------------------------
  545. LRESULT
  546. CDsPropPageBase::OnCommand(int id, HWND hwndCtl, UINT codeNotify)
  547. {
  548. dspDebugOut((DEB_USER3, "CDsPropPageBase::OnCommand - id: %d, code: %x\n",
  549. id, codeNotify));
  550. if ((codeNotify == EN_CHANGE) && !m_fInInit)
  551. {
  552. SetDirty();
  553. }
  554. if ((codeNotify == BN_CLICKED) && (id == IDCANCEL))
  555. {
  556. //
  557. // Pressing ESC in a multi-line edit control results in this
  558. // WM_COMMAND being sent. Pass it on to the parent (the sheet proc) to
  559. // close the sheet.
  560. //
  561. PostMessage(GetParent(m_hPage), WM_COMMAND, MAKEWPARAM(id, codeNotify),
  562. (LPARAM)hwndCtl);
  563. }
  564. return 0;
  565. }
  566. //+----------------------------------------------------------------------------
  567. //
  568. // Method: CDsPropPageBase::CheckIfPageAttrsWritable
  569. //
  570. // Synopsis: See which attributes are writable by checking if they are in
  571. // the allowedAttributesEffective array.
  572. //
  573. // Notes: The m_rgAttrData array is 1 to 1 with the m_rgpAttrMap array.
  574. //-----------------------------------------------------------------------------
  575. void
  576. CDsPropPageBase::CheckIfPageAttrsWritable(void)
  577. {
  578. DWORD iAllowed;
  579. if (m_fReadOnly || !m_pWritableAttrs)
  580. {
  581. return;
  582. }
  583. for (DWORD iAttrs = 0; iAttrs < m_cAttrs; iAttrs++)
  584. {
  585. if (m_rgpAttrMap[iAttrs]->AttrInfo.pszAttrName)
  586. {
  587. for (iAllowed = 0; iAllowed < m_pWritableAttrs->dwNumValues; iAllowed++)
  588. {
  589. if (_wcsicmp(m_rgpAttrMap[iAttrs]->AttrInfo.pszAttrName,
  590. m_pWritableAttrs->pADsValues[iAllowed].CaseIgnoreString) == 0)
  591. {
  592. ATTR_DATA_SET_WRITABLE(m_rgAttrData[iAttrs]);
  593. break;
  594. }
  595. }
  596. }
  597. }
  598. return;
  599. }
  600. //+----------------------------------------------------------------------------
  601. //
  602. // Method: CDsPropPageBase::CheckIfWritable
  603. //
  604. // Synopsis: See if the attribute is writable by checking if it is in
  605. // the allowedAttributesEffective array.
  606. //
  607. //-----------------------------------------------------------------------------
  608. BOOL
  609. CDsPropPageBase::CheckIfWritable(const PWSTR & wzAttr)
  610. {
  611. BOOL fWritable = FALSE;
  612. if (m_fReadOnly || !m_pWritableAttrs)
  613. {
  614. return FALSE;
  615. }
  616. for (DWORD i = 0; i < m_pWritableAttrs->dwNumValues; i++)
  617. {
  618. if (_wcsicmp(m_pWritableAttrs->pADsValues[i].CaseIgnoreString,
  619. wzAttr) == 0)
  620. {
  621. fWritable = TRUE;
  622. break;
  623. }
  624. }
  625. return fWritable;
  626. }
  627. //+----------------------------------------------------------------------------
  628. //
  629. // Method: CDsPropPageBase::OnCancel
  630. //
  631. // Synopsis:
  632. //
  633. //-----------------------------------------------------------------------------
  634. LRESULT
  635. CDsPropPageBase::OnCancel(void)
  636. {
  637. return FALSE;
  638. }
  639. //+----------------------------------------------------------------------------
  640. //
  641. // Method: CDsPropPageBase::OnSetFocus
  642. //
  643. // Synopsis:
  644. //
  645. //-----------------------------------------------------------------------------
  646. LRESULT
  647. CDsPropPageBase::OnSetFocus(HWND)
  648. {
  649. // An application should return zero if it processes this message.
  650. return 1;
  651. }
  652. //+----------------------------------------------------------------------------
  653. //
  654. // Method: CDsPropPageBase::OnPSNSetActive
  655. //
  656. // Synopsis: Page activation event.
  657. //
  658. //-----------------------------------------------------------------------------
  659. LRESULT
  660. CDsPropPageBase::OnPSNSetActive(LPARAM)
  661. {
  662. SetWindowLongPtr(m_hPage, DWLP_MSGRESULT, 0);
  663. return TRUE;
  664. }
  665. //+----------------------------------------------------------------------------
  666. //
  667. // Method: CDsPropPageBase::OnPSNKillActive
  668. //
  669. // Synopsis: Page deactivation event (when other pages cover this one).
  670. //
  671. //-----------------------------------------------------------------------------
  672. LRESULT
  673. CDsPropPageBase::OnPSNKillActive(LPARAM)
  674. {
  675. SetWindowLongPtr(m_hPage, DWLP_MSGRESULT, 0);
  676. return TRUE;
  677. }
  678. //+----------------------------------------------------------------------------
  679. //
  680. // Method: CDsPropPageBase::OnDestroy
  681. //
  682. // Synopsis: Exit cleanup
  683. //
  684. //-----------------------------------------------------------------------------
  685. LRESULT
  686. CDsPropPageBase::OnDestroy(void)
  687. {
  688. return 1;
  689. }
  690. //+----------------------------------------------------------------------------
  691. //
  692. // Method: CDsPropPageBase::OnShowWindow
  693. //
  694. // Synopsis: On dialog window show operations, resizes the view window.
  695. //
  696. //-----------------------------------------------------------------------------
  697. LRESULT
  698. CDsPropPageBase::OnShowWindow(void)
  699. {
  700. return 0;
  701. }
  702. //+----------------------------------------------------------------------------
  703. //
  704. // Method: CDsPropPageBase::GetIDispSpec
  705. //
  706. // Synopsis: If needed, create the interface instance and return the pointer.
  707. //
  708. //-----------------------------------------------------------------------------
  709. HRESULT
  710. CDsPropPageBase::GetIDispSpec(IDsDisplaySpecifier ** ppDispSpec)
  711. {
  712. HRESULT hr;
  713. TRACE2(CDsPropPageBase, GetIDispSpec);
  714. if (!m_pDispSpec)
  715. {
  716. hr = CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER,
  717. IID_IDsDisplaySpecifier, (PVOID *)&m_pDispSpec);
  718. CHECK_HRESULT(hr, return hr);
  719. CStrW strDC;
  720. CComPtr<IDirectoryObject> spDsObj;
  721. if (m_pDsObj == NULL)
  722. {
  723. //
  724. // For the retrieval of the DS Object names
  725. //
  726. FORMATETC fmte = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  727. STGMEDIUM objMedium;
  728. hr = m_pWPTDataObj->GetData(&fmte, &objMedium);
  729. CHECK_HRESULT(hr, return hr);
  730. LPDSOBJECTNAMES pDsObjectNames = (LPDSOBJECTNAMES)objMedium.hGlobal;
  731. //
  732. // Get the objects path
  733. //
  734. LPWSTR pwzObjADsPath = (PWSTR)ByteOffset(pDsObjectNames,
  735. pDsObjectNames->aObjects[0].offsetName);
  736. //
  737. // Bind to the object
  738. //
  739. hr = ADsOpenObject(pwzObjADsPath, NULL, NULL, ADS_SECURE_AUTHENTICATION,
  740. IID_IDirectoryObject, (PVOID*)&spDsObj);
  741. CHECK_HRESULT(hr, return hr);
  742. }
  743. else
  744. {
  745. spDsObj = m_pDsObj;
  746. }
  747. hr = GetLdapServerName(spDsObj, strDC);
  748. CHECK_HRESULT(hr, return hr);
  749. hr = m_pDispSpec->SetServer(strDC, NULL, NULL, 0);
  750. CHECK_HRESULT(hr, return hr);
  751. }
  752. if (ppDispSpec)
  753. {
  754. *ppDispSpec = m_pDispSpec;
  755. }
  756. return S_OK;
  757. }
  758. //+----------------------------------------------------------------------------
  759. //
  760. // Method: CDsPropPageBase::GetADsPathname
  761. //
  762. // Synopsis: If needed, create the interface instance and return the pointer.
  763. //
  764. //-----------------------------------------------------------------------------
  765. HRESULT
  766. CDsPropPageBase::GetADsPathname(CComPtr<IADsPathname>& refADsPath)
  767. {
  768. HRESULT hr;
  769. if (!m_pADsPath)
  770. {
  771. hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
  772. IID_IADsPathname, (PVOID *)&m_pADsPath);
  773. CHECK_HRESULT(hr, return hr);
  774. }
  775. refADsPath = m_pADsPath;
  776. return S_OK;
  777. }
  778. //+----------------------------------------------------------------------------
  779. //
  780. // Method: CDsPropPageBase::SkipPrefix
  781. //
  782. // Synopsis: Given an object name, returns a buffer containing the same
  783. // name without the provider/server prefix. The buffer must be
  784. // freed using delete.
  785. //
  786. // Notes: The fX500 parameter defaults to true and applies whenever the
  787. // input path uses the LDAP provider prefix. The path cracker
  788. // interface can be used to strip the prefix in this case. However,
  789. // if the provider is WINNT, then the path cracker doesn't give the
  790. // desired results so simple string manipulation is used instead.
  791. //-----------------------------------------------------------------------------
  792. HRESULT
  793. CDsPropPageBase::SkipPrefix(PWSTR pwzObj, PWSTR * ppResult, BOOL fX500)
  794. {
  795. if (fX500)
  796. {
  797. // Strip of the "LDAP://" prefix using the path cracker.
  798. //
  799. CComPtr<IADsPathname> spPathname;
  800. HRESULT hr = GetADsPathname(spPathname);
  801. CHECK_HRESULT(hr, return hr);
  802. hr = spPathname->Set(pwzObj, ADS_SETTYPE_FULL);
  803. CHECK_HRESULT(hr, return hr);
  804. BSTR bstr;
  805. hr = spPathname->Retrieve(ADS_FORMAT_X500_DN, &bstr);
  806. CHECK_HRESULT(hr, return hr);
  807. if (!AllocWStr(bstr, ppResult))
  808. {
  809. SysFreeString(bstr);
  810. return E_OUTOFMEMORY;
  811. }
  812. SysFreeString(bstr);
  813. }
  814. else
  815. {
  816. // Strip off the "WINNT://" prefix.
  817. //
  818. if (wcslen(pwzObj) < 9 || pwzObj[7] != L'/')
  819. {
  820. // Can't be a valid WINNT name if not at least "WINNT://x"
  821. //
  822. return E_INVALIDARG;
  823. }
  824. if (!AllocWStr(&pwzObj[8], ppResult))
  825. {
  826. return E_OUTOFMEMORY;
  827. }
  828. }
  829. return S_OK;
  830. }
  831. //+----------------------------------------------------------------------------
  832. //
  833. // Method: CDsPropPageBase::AddLdapPrefix
  834. //
  835. // Synopsis: Given an object name, returns same name with the LDAP provider
  836. // prefix. The server name is also added by default.
  837. //
  838. //-----------------------------------------------------------------------------
  839. HRESULT
  840. CDsPropPageBase::AddLDAPPrefix(PWSTR pwzObj, CStrW &pstrResult, BOOL fServer)
  841. {
  842. return ::AddLDAPPrefix(this, pwzObj, pstrResult, fServer);
  843. }
  844. //
  845. // Non-class member version.
  846. //
  847. HRESULT
  848. AddLDAPPrefix(CDsPropPageBase * pPage, PWSTR pwzObj, CStrW &strResult,
  849. BOOL fServer)
  850. {
  851. HRESULT hr;
  852. CComPtr<IADsPathname> spPathCracker;
  853. strResult.Empty();
  854. if (pPage)
  855. {
  856. hr = pPage->GetADsPathname(spPathCracker);
  857. CHECK_HRESULT(hr, return hr);
  858. }
  859. else
  860. {
  861. hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
  862. IID_IADsPathname, (PVOID *)&spPathCracker);
  863. CHECK_HRESULT(hr, return hr);
  864. }
  865. hr = spPathCracker->Set(L"LDAP", ADS_SETTYPE_PROVIDER);
  866. CHECK_HRESULT(hr, return hr);
  867. if (pPage)
  868. {
  869. CStrW strDC;
  870. CComPtr<IDirectoryObject> spDsObj;
  871. if (pPage->m_pDsObj == NULL)
  872. {
  873. //
  874. // For the retrieval of the DS Object names
  875. //
  876. FORMATETC fmte = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  877. STGMEDIUM objMedium;
  878. hr = pPage->m_pWPTDataObj->GetData(&fmte, &objMedium);
  879. CHECK_HRESULT(hr, return hr);
  880. LPDSOBJECTNAMES pDsObjectNames = (LPDSOBJECTNAMES)objMedium.hGlobal;
  881. //
  882. // Get the objects path
  883. //
  884. LPWSTR pwzObjADsPath = (PWSTR)ByteOffset(pDsObjectNames,
  885. pDsObjectNames->aObjects[0].offsetName);
  886. //
  887. // Bind to the object
  888. //
  889. hr = ADsOpenObject(pwzObjADsPath, NULL, NULL, ADS_SECURE_AUTHENTICATION,
  890. IID_IDirectoryObject, (PVOID*)&spDsObj);
  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(const_cast<PWSTR>((LPCWSTR)strDC), ADS_SETTYPE_SERVER);
  900. CHECK_HRESULT(hr, return hr);
  901. }
  902. hr = spPathCracker->Set(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(L"GC", ADS_SETTYPE_PROVIDER);
  1134. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  1135. hr = spADsPath->Set(pDCInfo->DnsForestName, ADS_SETTYPE_SERVER);
  1136. CHECK_HRESULT_REPORT(hr, pPage->GetHWnd(), return hr);
  1137. NetApiBufferFree(pDCInfo);
  1138. hr = spADsPath->Set(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(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 = ADsOpenObject(bstrEscapedPath, NULL, NULL,
  1149. ADS_SECURE_AUTHENTICATION,
  1150. IID_IDirectoryObject, (PVOID*)ppDsObj);
  1151. return hr;
  1152. }