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.

1918 lines
55 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Windows NT Directory Service Property Pages
  4. //
  5. // Microsoft Windows
  6. // Copyright (C) Microsoft Corporation, 1992 - 1999
  7. //
  8. // File: notify.cxx
  9. //
  10. // Contents: Change notification ref-counting object.
  11. //
  12. // Classes: CNotifyObj
  13. //
  14. // History: 20-Jan-98 EricB
  15. //
  16. //-----------------------------------------------------------------------------
  17. #include "pch.h"
  18. #include "proppage.h"
  19. #include "objlist.h" // g_ClassIconCache
  20. #define NOTIFYOUT(x) dspDebugOut((DEB_ITRACE, "Notify Obj (this: 0x%p) " #x "\n", this));
  21. #define DSPROP_WAITTIME 600000 // wait 600 seconds, 10 minutes.
  22. //+----------------------------------------------------------------------------
  23. //
  24. // Function: ADsPropCreateNotifyObj
  25. //
  26. // Synopsis: Checks to see if the notification window/object exists for this
  27. // sheet instance and if not creates it.
  28. //
  29. // Arguments: [pAppThdDataObj] - the unmarshalled data object pointer.
  30. // [pwzADsObjName] - object path name.
  31. // [phNotifyObj] - to return the notificion window handle.
  32. //
  33. // Returns: HRESULTs.
  34. //
  35. //-----------------------------------------------------------------------------
  36. STDAPI
  37. ADsPropCreateNotifyObj(LPDATAOBJECT pAppThdDataObj, PWSTR pwzADsObjName,
  38. HWND * phNotifyObj)
  39. {
  40. return CNotifyObj::Create(pAppThdDataObj, pwzADsObjName, phNotifyObj);
  41. }
  42. //+----------------------------------------------------------------------------
  43. //
  44. // Function: ADsPropGetInitInfo
  45. //
  46. // Synopsis: Pages call this at their init time to retreive DS object info.
  47. //
  48. // Arguments: [hNotifyObj] - the notificion window handle.
  49. // [pInitParams] - struct filled in with DS object info.
  50. //
  51. // Returns: FALSE if the notify window has gone away for some reason.
  52. //
  53. // Note that pInitParams->pWritableAttrs can be NULL if there are no writable
  54. // attributes.
  55. //
  56. //-----------------------------------------------------------------------------
  57. STDAPI_(BOOL)
  58. ADsPropGetInitInfo(HWND hNotifyObj, PADSPROPINITPARAMS pInitParams)
  59. {
  60. return CNotifyObj::GetInitInfo(hNotifyObj, pInitParams);
  61. }
  62. //+----------------------------------------------------------------------------
  63. //
  64. // Function: ADsPropSetHwndWithTitle
  65. //
  66. // Synopsis: Pages call this at their dialog init time to send their hwnd
  67. // to the Notify object. Use this function instead of
  68. // ADsPropSetHwnd for multi-select property pages.
  69. //
  70. // Arguments: [hNotifyObj] - the notificion window handle.
  71. // [hPage] - the page's window handle.
  72. // [ptzTitle] - the page's title
  73. //
  74. // Returns: FALSE if the notify window has gone away for some reason.
  75. //
  76. //-----------------------------------------------------------------------------
  77. STDAPI_(BOOL)
  78. ADsPropSetHwndWithTitle(HWND hNotifyObj, HWND hPage, PTSTR ptzTitle)
  79. {
  80. return CNotifyObj::SetHwnd(hNotifyObj, hPage, ptzTitle);
  81. }
  82. //+----------------------------------------------------------------------------
  83. //
  84. // Function: ADsPropSetHwnd
  85. //
  86. // Synopsis: Pages call this at their dialog init time to send their hwnd
  87. // to the Notify object.
  88. //
  89. // Arguments: [hNotifyObj] - the notificion window handle.
  90. // [hPage] - the page's window handle.
  91. //
  92. // Returns: FALSE if the notify window has gone away for some reason.
  93. //
  94. //-----------------------------------------------------------------------------
  95. STDAPI_(BOOL)
  96. ADsPropSetHwnd(HWND hNotifyObj, HWND hPage)
  97. {
  98. return ADsPropSetHwndWithTitle(hNotifyObj, hPage, 0);
  99. }
  100. //+----------------------------------------------------------------------------
  101. //
  102. // function: ADsPropCheckIfWritable
  103. //
  104. // Synopsis: See if the attribute is writable by checking if it is in
  105. // the allowedAttributesEffective array.
  106. //
  107. // Arguments: [pwzAttr] - the attribute name.
  108. // [pWritableAttrs] - the array of writable attributes.
  109. //
  110. // Returns: FALSE if the attribute name is not found in the writable-attrs
  111. // array or if the array pointer is NULL.
  112. //
  113. //-----------------------------------------------------------------------------
  114. STDAPI_(BOOL)
  115. ADsPropCheckIfWritable(const PWSTR pwzAttr, const PADS_ATTR_INFO pWritableAttrs)
  116. {
  117. BOOL fWritable = FALSE;
  118. if (!pWritableAttrs || IsBadReadPtr(pWritableAttrs, sizeof(ADS_ATTR_INFO)))
  119. {
  120. return FALSE;
  121. }
  122. for (DWORD i = 0; i < pWritableAttrs->dwNumValues; i++)
  123. {
  124. if (_wcsicmp(pWritableAttrs->pADsValues[i].CaseIgnoreString,
  125. pwzAttr) == 0)
  126. {
  127. fWritable = TRUE;
  128. break;
  129. }
  130. }
  131. return fWritable;
  132. }
  133. //+----------------------------------------------------------------------------
  134. //
  135. // function: ADsPropSendErrorMessage
  136. //
  137. // Synopsis: Adds an error message to a list which is presented when
  138. // ADsPropShowErrorDialog is called
  139. //
  140. // Arguments: [hNotifyObj] - the notificion window handle.
  141. // [pError] - the error structure
  142. //
  143. // Returns: FALSE if the notify window has gone away for some reason.
  144. //
  145. //-----------------------------------------------------------------------------
  146. STDAPI_(BOOL)
  147. ADsPropSendErrorMessage(HWND hNotifyObj, PADSPROPERROR pError)
  148. {
  149. return SendMessage(hNotifyObj, WM_ADSPROP_NOTIFY_ERROR, 0, (LPARAM)pError) != 0;
  150. }
  151. //+----------------------------------------------------------------------------
  152. //
  153. // function: ADsPropShowErrorDialog
  154. //
  155. // Synopsis: Presents an error dialog with the error messages accumulated
  156. // through calls to ADsPropSendErrorMessage
  157. //
  158. // Arguments: [hNotifyObj] - the notificion window handle.
  159. // [hPage] - the property page window handle.
  160. //
  161. // Returns: FALSE if the notify window has gone away for some reason.
  162. //
  163. //-----------------------------------------------------------------------------
  164. STDAPI_(BOOL)
  165. ADsPropShowErrorDialog(HWND hNotifyObj, HWND hPage)
  166. {
  167. #ifdef DSADMIN
  168. CNotifyObj* pNotifyObj = NULL;
  169. dspAssert(hNotifyObj);
  170. if (!IsWindow(hNotifyObj))
  171. {
  172. return FALSE;
  173. }
  174. LRESULT lResult = SendMessage(hNotifyObj, WM_ADSPROP_NOTIFY_GET_NOTIFY_OBJ, 0,
  175. (LPARAM)&pNotifyObj);
  176. if (lResult && pNotifyObj)
  177. {
  178. CMultiSelectErrorDialog dlg(hNotifyObj, hPage);
  179. CPageInfo* pPageInfoArray = pNotifyObj->m_pPageInfoArray;
  180. UINT cPages = pNotifyObj->m_cPages;
  181. IDataObject* pDataObject = pNotifyObj->m_pAppThdDataObj;
  182. dspAssert(pPageInfoArray);
  183. dspAssert(cPages > 0);
  184. dspAssert(pDataObject);
  185. HRESULT hr = dlg.Init(pPageInfoArray,
  186. cPages,
  187. pDataObject);
  188. if (SUCCEEDED(hr))
  189. {
  190. dlg.DoModal();
  191. SetForegroundWindow(dlg.m_hWnd);
  192. for (UINT pageIdx = 0; pageIdx < cPages; pageIdx++)
  193. {
  194. pPageInfoArray[pageIdx].m_ApplyErrors.Clear();
  195. pPageInfoArray[pageIdx].m_ApplyStatus = CPageInfo::notAttempted;
  196. }
  197. }
  198. }
  199. #endif
  200. return TRUE;
  201. }
  202. //+----------------------------------------------------------------------------
  203. //
  204. // Method: CNotifyObj::Create
  205. //
  206. // Synopsis: Creation procedure: creates instances of the object.
  207. //
  208. // Arguments: [pAppThdDataObj] - the unmarshalled data object pointer.
  209. // [pwzADsObjName] - object path name.
  210. // [phNotifyObj] - to return the notificion window handle.
  211. //
  212. // Returns: HRESULTs.
  213. //
  214. //-----------------------------------------------------------------------------
  215. HRESULT
  216. CNotifyObj::Create(LPDATAOBJECT pAppThdDataObj, PWSTR pwzADsObjName,
  217. HWND * phNotifyObj)
  218. {
  219. HWND hNotify;
  220. HRESULT hr = S_OK;
  221. // Only one caller at a time.
  222. //
  223. CNotifyCreateCriticalSection NotifyCS;
  224. //
  225. // See if the object/window already exist for this property sheet and
  226. // get the object DN.
  227. //
  228. hNotify = FindSheetNoSetFocus(pwzADsObjName);
  229. if (hNotify != NULL)
  230. {
  231. // The window already exists, return the window handle.
  232. //
  233. *phNotifyObj = hNotify;
  234. dspDebugOut((DEB_ITRACE, "CNotifyObj::Create returning existing notify obj HWND.\n"));
  235. return S_OK;
  236. }
  237. dspDebugOut((DEB_ITRACE, "CNotifyObj::Create, creating notify obj.\n"));
  238. PPROPSHEETCFG pSheetCfg;
  239. PROPSHEETCFG sheetCfg;
  240. ZeroMemory(&sheetCfg, sizeof(PROPSHEETCFG));
  241. STGMEDIUM sm = {TYMED_NULL, NULL, NULL};
  242. FORMATETC fmte = {g_cfDsPropCfg, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  243. hr = pAppThdDataObj->GetData(&fmte, &sm);
  244. if (FAILED(hr))
  245. {
  246. if (hr != DV_E_FORMATETC)
  247. {
  248. REPORT_ERROR_FORMAT(hr, IDS_NOTIFYFAILURE, GetDesktopWindow());
  249. return hr;
  250. }
  251. }
  252. else
  253. {
  254. pSheetCfg = (PPROPSHEETCFG)sm.hGlobal;
  255. //NTRAID#NTBUG9-567482-2002/03/10-jmessec dspAssert simply maps to ASSERT; if sm.hGlobal can be NULL, back it up with code
  256. dspAssert(pSheetCfg);
  257. memcpy(&sheetCfg, pSheetCfg, sizeof(PROPSHEETCFG));
  258. ReleaseStgMedium(&sm);
  259. }
  260. //
  261. // Create the notification object.
  262. //
  263. CNotifyObj * pNotifyObj = new CNotifyObj(pAppThdDataObj, &sheetCfg);
  264. CHECK_NULL_REPORT(pNotifyObj, GetDesktopWindow(), return ERROR_OUTOFMEMORY);
  265. if (pNotifyObj->m_hr != S_OK)
  266. {
  267. REPORT_ERROR_FORMAT(pNotifyObj->m_hr, IDS_NOTIFYFAILURE, GetDesktopWindow());
  268. return pNotifyObj->m_hr;
  269. }
  270. dspDebugOut((DEB_ITRACE, "Notify Obj (this: 0x%p) object allocated, pAppThdDataObj = 0x%08p\n",
  271. pNotifyObj, pAppThdDataObj));
  272. if (!AllocWStr(pwzADsObjName, &pNotifyObj->m_pwzObjDN))
  273. {
  274. return E_OUTOFMEMORY;
  275. }
  276. uintptr_t hThread;
  277. hThread = _beginthread(NotifyThreadFcn, 0, (PVOID)pNotifyObj);
  278. if (hThread == -1)
  279. {
  280. dspDebugOut((DEB_ERROR, "_beginthread failed with error %s\n",
  281. strerror(errno)));
  282. REPORT_ERROR_FORMAT(ERROR_NOT_ENOUGH_MEMORY, IDS_NOTIFYFAILURE, GetDesktopWindow());
  283. return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  284. }
  285. //
  286. // Wait for initialization to complete and return the results.
  287. //
  288. if (WaitForSingleObject(pNotifyObj->m_hInitEvent, DSPROP_WAITTIME) == WAIT_TIMEOUT)
  289. {
  290. CloseHandle(pNotifyObj->m_hInitEvent);
  291. REPORT_ERROR_FORMAT(0, IDS_NOTIFYTIMEOUT, GetDesktopWindow());
  292. return HRESULT_FROM_WIN32(WAIT_TIMEOUT);
  293. }
  294. CloseHandle(pNotifyObj->m_hInitEvent);
  295. if (pNotifyObj->m_hWnd != NULL)
  296. {
  297. *phNotifyObj = pNotifyObj->m_hWnd;
  298. }
  299. else
  300. {
  301. REPORT_ERROR_FORMAT(pNotifyObj->m_hr, IDS_NOTIFYFAILURE, GetDesktopWindow());
  302. hr = pNotifyObj->m_hr;
  303. delete pNotifyObj;
  304. return hr;
  305. }
  306. return S_OK;
  307. }
  308. //+----------------------------------------------------------------------------
  309. //
  310. // Method: CNotifyObj::GetInitInfo
  311. //
  312. // Synopsis: Pages call this at their init time to retreive DS object info.
  313. //
  314. // Arguments: [hNotifyObj] - the notificion window handle.
  315. // [pInitParams] - struct filled in with DS object info.
  316. //
  317. // Note that pInitParams->pWritableAttrs can be NULL if there are no writable
  318. // attributes.
  319. //
  320. //-----------------------------------------------------------------------------
  321. BOOL
  322. CNotifyObj::GetInitInfo(HWND hNotifyObj, PADSPROPINITPARAMS pInitParams)
  323. {
  324. dspDebugOut((DEB_ITRACE, "CNotifyObj::GetInitInfo\n"));
  325. if (IsBadWritePtr(pInitParams, sizeof(ADSPROPINITPARAMS)))
  326. {
  327. return FALSE;
  328. }
  329. dspAssert(hNotifyObj && pInitParams);
  330. if (!IsWindow(hNotifyObj))
  331. {
  332. pInitParams->hr = E_FAIL;
  333. return FALSE;
  334. }
  335. if (pInitParams->dwSize != sizeof (ADSPROPINITPARAMS))
  336. {
  337. return FALSE;
  338. }
  339. SendMessage(hNotifyObj, WM_ADSPROP_NOTIFY_PAGEINIT, 0,
  340. (LPARAM)pInitParams);
  341. return TRUE;
  342. }
  343. //+----------------------------------------------------------------------------
  344. //
  345. // Method: CNotifyObj::SetHwnd
  346. //
  347. // Synopsis: Pages call this at their dialog init time to send their hwnd.
  348. //
  349. // Arguments: [hNotifyObj] - the notificion window handle.
  350. // [hPage] - the page's window handle.
  351. //
  352. // Returns: FALSE if the notify window has gone away for some reason.
  353. //
  354. //-----------------------------------------------------------------------------
  355. BOOL
  356. CNotifyObj::SetHwnd(HWND hNotifyObj, HWND hPage, PTSTR ptzTitle)
  357. {
  358. dspDebugOut((DEB_ITRACE, "CNotifyObj::SetHwnd\n"));
  359. dspAssert(hNotifyObj && hPage);
  360. if (!IsWindow(hNotifyObj))
  361. {
  362. return FALSE;
  363. }
  364. SendMessage(hNotifyObj, WM_ADSPROP_NOTIFY_PAGEHWND, (WPARAM)hPage, (LPARAM)ptzTitle);
  365. return TRUE;
  366. }
  367. //+----------------------------------------------------------------------------
  368. //
  369. // Method: NotifyThreadFcn
  370. //
  371. // Synopsis: Object window creation and message loop thread.
  372. //
  373. //-----------------------------------------------------------------------------
  374. VOID __cdecl
  375. NotifyThreadFcn(PVOID pParam)
  376. {
  377. // All of the function except the _endthread() call is enclosed in braces
  378. // so that the dtors of the auto classes would run. Otherwise the thread is
  379. // ended before the function scope is left and the auto class object dtors
  380. // never run.
  381. {
  382. CNotifyObj * pNotifyObj = (CNotifyObj *)pParam;
  383. dspAssert(pNotifyObj);
  384. MSG msg;
  385. CSmartPtr <TCHAR> ptzTitle;
  386. if (!UnicodeToTchar(pNotifyObj->m_pwzObjDN, &ptzTitle))
  387. {
  388. pNotifyObj->m_hr = E_OUTOFMEMORY;
  389. SetEvent(pNotifyObj->m_hInitEvent);
  390. return;
  391. }
  392. CStr cstrTitle(ptzTitle);
  393. WCHAR szIH[10];
  394. _itow(g_iInstance, szIH, 16);
  395. cstrTitle += szIH;
  396. //
  397. // The window title is set to the DN of the object plus the instance
  398. // identifier converted to a string. This enables FindWindow to locate a
  399. // pre-existing instance of the notify window for a specific object for
  400. // a specific instance of DS Admin.
  401. //
  402. pNotifyObj->m_hWnd = CreateWindow(tzNotifyWndClass, cstrTitle, WS_POPUP,
  403. 0, 0, 1, 1, NULL, NULL, g_hInstance,
  404. pNotifyObj);
  405. if (pNotifyObj->m_hWnd == NULL)
  406. {
  407. DWORD dwErr = GetLastError();
  408. dspDebugOut((DEB_ERROR,
  409. "Notify Obj window creation failed with error %d!\n",
  410. dwErr));
  411. pNotifyObj->m_hr = HRESULT_FROM_WIN32(dwErr);
  412. SetEvent(pNotifyObj->m_hInitEvent);
  413. return;
  414. }
  415. dspDebugOut((DEB_ITRACE, "Notify Obj (this: 0x%p) window creation complete.\n",
  416. pNotifyObj));
  417. SetEvent(pNotifyObj->m_hInitEvent);
  418. while (GetMessage(&msg, NULL, 0, 0))
  419. {
  420. DispatchMessage(&msg);
  421. }
  422. delete pNotifyObj;
  423. }
  424. _endthread();
  425. }
  426. //+----------------------------------------------------------------------------
  427. //
  428. // Method: _FindDSAHiddenWindowFromDSFind
  429. //
  430. // Synopsis: Looks for hidden DSA window of the snapin instance calling DS Find
  431. //
  432. // Returns: HWND of DSA hidden window if called from DS Find.
  433. //
  434. //-----------------------------------------------------------------------------
  435. BOOL CALLBACK EnumDSAHiddenWindowProc(HWND hwnd, LPARAM lParam)
  436. {
  437. HWND* phWnd = (HWND*)lParam;
  438. *phWnd = NULL;
  439. // get the window class
  440. TCHAR szClass[64];
  441. if (0 == GetClassName(hwnd, szClass, 64))
  442. {
  443. return TRUE;
  444. }
  445. if (_tcscmp(szClass, TEXT("DSAHiddenWindow")) != 0)
  446. {
  447. return TRUE; // no match, continue
  448. }
  449. // got a DSA hidden window
  450. // get the window title, to make sure it is
  451. // the one originating DS Find
  452. TCHAR szTitle[256];
  453. ::GetWindowText(hwnd, szTitle, 256);
  454. if (_tcscmp(szTitle, TEXT("DS Find")) != 0)
  455. {
  456. return TRUE; // no match continue
  457. }
  458. // we go the right class and title, but
  459. // we still have to verify it is from the
  460. // same process (assuming DS Find modal)
  461. DWORD dwProcessId = 0x0;
  462. GetWindowThreadProcessId(hwnd, &dwProcessId);
  463. if (GetCurrentProcessId() != dwProcessId)
  464. {
  465. return TRUE; // from wrong process, continue
  466. }
  467. // finally, we got it!!
  468. *phWnd = hwnd;
  469. return FALSE;
  470. }
  471. HWND _FindDSAHiddenWindowFromDSFind()
  472. {
  473. HWND hwndHidden = NULL;
  474. EnumWindows(EnumDSAHiddenWindowProc, (LPARAM)&hwndHidden);
  475. return hwndHidden;
  476. }
  477. //+----------------------------------------------------------------------------
  478. //
  479. // Method: CNotifyObj::CNotifyObj
  480. //
  481. //-----------------------------------------------------------------------------
  482. CNotifyObj::CNotifyObj(LPDATAOBJECT pDataObj, PPROPSHEETCFG pSheetCfg) :
  483. m_hWnd(NULL),
  484. m_hPropSheet(NULL),
  485. m_cPages(0),
  486. m_cApplies(0),
  487. m_pAppThdDataObj(pDataObj),
  488. m_pStrmMarshalledDO(NULL),
  489. m_hInitEvent(NULL),
  490. m_fBeingDestroyed(FALSE),
  491. m_fSheetDirty(FALSE),
  492. m_hr(S_OK),
  493. m_pwzObjDN(NULL),
  494. m_pDsObj(NULL),
  495. m_pwzCN(NULL),
  496. m_pWritableAttrs(NULL),
  497. m_pAttrs(NULL),
  498. m_pPageInfoArray(NULL)
  499. {
  500. #ifdef _DEBUG
  501. strcpy(szClass, "CNotifyObj");
  502. #endif
  503. memcpy(&m_sheetCfg, pSheetCfg, sizeof(PROPSHEETCFG));
  504. if (m_sheetCfg.hwndHidden == NULL)
  505. {
  506. // we might be called from DS Find, so we want to find
  507. // the DSA hidden window, needed for creating
  508. // secondary property sheets
  509. m_sheetCfg.hwndHidden = _FindDSAHiddenWindowFromDSFind();
  510. }
  511. //
  512. // We need to addref the data object but can't release it on this thread,
  513. // so we marshall it (which implicitly addrefs it) and then then unmarshall
  514. // and release on the notify object thread.
  515. //
  516. CoMarshalInterThreadInterfaceInStream(IID_IDataObject,
  517. pDataObj,
  518. &m_pStrmMarshalledDO);
  519. m_hInitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  520. if (m_hInitEvent == NULL)
  521. {
  522. m_hr = HRESULT_FROM_WIN32(GetLastError());
  523. }
  524. //
  525. // Arbitrary default size. This will expand as more pages are added
  526. //
  527. m_nPageInfoArraySize = 5;
  528. m_pPageInfoArray = new CPageInfo[m_nPageInfoArraySize];
  529. }
  530. //+----------------------------------------------------------------------------
  531. //
  532. // Method: CNotifyObj::~CNotifyObj
  533. //
  534. //-----------------------------------------------------------------------------
  535. CNotifyObj::~CNotifyObj(void)
  536. {
  537. NOTIFYOUT(destructor);
  538. LPDATAOBJECT pNotifyThdDataObj = NULL;
  539. if (m_pStrmMarshalledDO)
  540. {
  541. CoGetInterfaceAndReleaseStream(m_pStrmMarshalledDO,
  542. IID_IDataObject,
  543. reinterpret_cast<void**>(&pNotifyThdDataObj));
  544. m_pStrmMarshalledDO = NULL;
  545. }
  546. DO_RELEASE(pNotifyThdDataObj);
  547. //DBG_OUT("-----------------------releasing object in notify obj dtor");
  548. DO_RELEASE(m_pDsObj);
  549. if (m_sheetCfg.lNotifyHandle &&
  550. !IsBadReadPtr(
  551. reinterpret_cast<void*>(m_sheetCfg.lNotifyHandle),
  552. sizeof(LONG_PTR)))
  553. {
  554. MMCFreeNotifyHandle(m_sheetCfg.lNotifyHandle);
  555. m_sheetCfg.lNotifyHandle = 0;
  556. }
  557. if (m_sheetCfg.hwndHidden && m_sheetCfg.wParamSheetClose)
  558. {
  559. ::PostMessage(m_sheetCfg.hwndHidden,
  560. WM_DSA_SHEET_CLOSE_NOTIFY,
  561. (WPARAM)m_sheetCfg.wParamSheetClose,
  562. (LPARAM)0);
  563. }
  564. DO_DEL(m_pwzObjDN);
  565. if (m_pAttrs)
  566. {
  567. FreeADsMem(m_pAttrs);
  568. }
  569. if (m_pPageInfoArray != NULL)
  570. {
  571. delete[] m_pPageInfoArray;
  572. m_pPageInfoArray = NULL;
  573. }
  574. }
  575. //+----------------------------------------------------------------------------
  576. //
  577. // Method: CNotifyObj::StaticNotifyProc
  578. //
  579. // Synopsis: window procedure
  580. //
  581. //-----------------------------------------------------------------------------
  582. LRESULT CALLBACK
  583. CNotifyObj::StaticNotifyProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  584. {
  585. CNotifyObj * pNotifyObj = (CNotifyObj*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  586. if (uMsg == WM_CREATE)
  587. {
  588. pNotifyObj = (CNotifyObj *)((CREATESTRUCT *)lParam)->lpCreateParams;
  589. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pNotifyObj);
  590. }
  591. if (pNotifyObj)
  592. {
  593. return pNotifyObj->NotifyProc(hWnd, uMsg, wParam, lParam);
  594. }
  595. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  596. }
  597. //+----------------------------------------------------------------------------
  598. //
  599. // Method: CNotifyObj::NotifyProc
  600. //
  601. // Synopsis: Instance window procedure
  602. //
  603. //-----------------------------------------------------------------------------
  604. LRESULT CALLBACK
  605. CNotifyObj::NotifyProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  606. {
  607. switch (uMsg)
  608. {
  609. case WM_CREATE:
  610. return OnCreate();
  611. case WM_ADSPROP_NOTIFY_PAGEINIT:
  612. dspDebugOut((DEB_ITRACE,
  613. "Notify Obj 0x%p: WM_ADSPROP_NOTIFY_PAGEINIT\n",
  614. this));
  615. PADSPROPINITPARAMS pInitParams;
  616. pInitParams = (PADSPROPINITPARAMS)lParam;
  617. pInitParams->hr = m_hr;
  618. pInitParams->pDsObj = m_pDsObj;
  619. pInitParams->pwzCN = m_pwzCN;
  620. pInitParams->pWritableAttrs = m_pWritableAttrs;
  621. return 0;
  622. case WM_ADSPROP_NOTIFY_PAGEHWND:
  623. {
  624. m_cApplies = ++m_cPages;
  625. dspDebugOut((DEB_ITRACE,
  626. "Notify Obj 0x%p: WM_ADSPROP_NOTIFY_PAGEHWND count now %d\n",
  627. this, m_cPages));
  628. HWND hWndPage = (HWND)wParam;
  629. if (!m_hPropSheet)
  630. {
  631. m_hPropSheet = GetParent(hWndPage);
  632. }
  633. if (m_cPages > m_nPageInfoArraySize)
  634. {
  635. //
  636. // REVIEW_JEFFJON : after going beyond the initial size, should the size increase
  637. // incrementally or in chunks?
  638. //
  639. CPageInfo* pNewPageInfoArray = new CPageInfo[m_cPages];
  640. if (pNewPageInfoArray != NULL)
  641. {
  642. memset(pNewPageInfoArray, 0, sizeof(CPageInfo) * m_cPages);
  643. memcpy(pNewPageInfoArray, m_pPageInfoArray, sizeof(CPageInfo) * m_nPageInfoArraySize);
  644. delete[] m_pPageInfoArray;
  645. m_pPageInfoArray = pNewPageInfoArray;
  646. m_nPageInfoArraySize = m_cPages;
  647. }
  648. }
  649. //NTRAID#NTBUG9-572006-2002/03/10-jmessec buffer overrun: If memory allocation fails above, the array is too small
  650. m_pPageInfoArray[m_cPages - 1].m_hWnd = hWndPage;
  651. //
  652. // Copy the title if one was sent
  653. //
  654. PTSTR ptzPageTitle = reinterpret_cast<PTSTR>(lParam);
  655. if (ptzPageTitle != NULL)
  656. {
  657. size_t iTitleSize = _tcslen(ptzPageTitle);
  658. m_pPageInfoArray[m_cPages - 1].m_ptzTitle = new TCHAR[iTitleSize + 1];
  659. if (m_pPageInfoArray[m_cPages - 1].m_ptzTitle != NULL)
  660. {
  661. _tcscpy(m_pPageInfoArray[m_cPages - 1].m_ptzTitle, ptzPageTitle);
  662. }
  663. }
  664. }
  665. return 0;
  666. case WM_ADSPROP_NOTIFY_APPLY:
  667. {
  668. NOTIFYOUT(WM_ADSPROP_NOTIFY_APPLY);
  669. if ((BOOL)wParam)
  670. {
  671. // The security page and extension pages don't inherit from our
  672. // page framework and thus don't participate in the notify object
  673. // refcounting or the page-dirty flagging. So, don't fire a change
  674. // notification unless one of our pages was dirty.
  675. //
  676. m_fSheetDirty = TRUE;
  677. }
  678. // NTRAID#NTBUG9-462165-2001/10/17-JeffJon
  679. // Need to set the apply status to success.
  680. HWND hPage = reinterpret_cast<HWND>(lParam);
  681. if (hPage)
  682. {
  683. for (UINT idx = 0; idx < m_cPages; idx++)
  684. {
  685. if (m_pPageInfoArray[idx].m_hWnd == hPage)
  686. {
  687. m_pPageInfoArray[idx].m_ApplyStatus = CPageInfo::success;
  688. break;
  689. }
  690. }
  691. }
  692. if (--m_cApplies == 0 && m_fSheetDirty)
  693. {
  694. NOTIFYOUT(Sending change notification);
  695. if (m_sheetCfg.lNotifyHandle)
  696. {
  697. // The change notify call results in a PostMessage back to the
  698. // MMC main thread. Therefore, we need to pass the data object
  699. // pointer that came from the main thread.
  700. //
  701. MMCPropertyChangeNotify(m_sheetCfg.lNotifyHandle, (LPARAM)m_pAppThdDataObj);
  702. }
  703. if (m_sheetCfg.hwndParentSheet)
  704. {
  705. PostMessage(m_sheetCfg.hwndParentSheet, WM_ADSPROP_NOTIFY_CHANGE, 0, 0);
  706. }
  707. m_cApplies = m_cPages;
  708. m_fSheetDirty = FALSE;
  709. //
  710. // Change the status of all the pages back to notAttempted
  711. //
  712. for (UINT idx = 0; idx < m_cPages; idx++)
  713. {
  714. m_pPageInfoArray[idx].m_ApplyStatus = CPageInfo::notAttempted;
  715. }
  716. }
  717. return 0;
  718. }
  719. case WM_ADSPROP_NOTIFY_ERROR:
  720. {
  721. NOTIFYOUT(WM_ADSPROP_NOTIFY_ERROR);
  722. PADSPROPERROR pApplyErrors = reinterpret_cast<PADSPROPERROR>(lParam);
  723. if (pApplyErrors != NULL)
  724. {
  725. for (UINT idx = 0; idx < m_cPages; idx++)
  726. {
  727. if (m_pPageInfoArray[idx].m_hWnd == pApplyErrors->hwndPage)
  728. {
  729. m_pPageInfoArray[idx].m_ApplyErrors.SetError(pApplyErrors);
  730. if (m_pPageInfoArray[idx].m_ApplyErrors.GetErrorCount() > 0)
  731. {
  732. m_pPageInfoArray[idx].m_ApplyStatus = CPageInfo::failed;
  733. }
  734. else
  735. {
  736. m_pPageInfoArray[idx].m_ApplyStatus = CPageInfo::success;
  737. }
  738. break;
  739. }
  740. }
  741. }
  742. return 0;
  743. }
  744. case WM_ADSPROP_NOTIFY_GET_NOTIFY_OBJ:
  745. {
  746. NOTIFYOUT(WM_ADSPROP_NOTIFY_GET_NOTIFY_OBJ);
  747. BOOL retVal = FALSE;
  748. if (lParam != NULL)
  749. {
  750. CNotifyObj** ppNotifyObj = reinterpret_cast<CNotifyObj**>(lParam);
  751. if (ppNotifyObj)
  752. {
  753. *ppNotifyObj = this;
  754. retVal = TRUE;
  755. }
  756. }
  757. return retVal;
  758. }
  759. case WM_ADSPROP_NOTIFY_SETFOCUS:
  760. NOTIFYOUT(WM_ADSPROP_NOTIFY_SETFOCUS);
  761. SetForegroundWindow(m_hPropSheet);
  762. return 0;
  763. case WM_ADSPROP_NOTIFY_FOREGROUND:
  764. NOTIFYOUT(WM_ADSPROP_NOTIFY_FOREGROUND);
  765. if (wParam) // bActivate flag
  766. {
  767. SetForegroundWindow(m_hPropSheet);
  768. }
  769. else
  770. {
  771. SetWindowPos(m_hPropSheet, HWND_TOP,
  772. 0,0,0,0,
  773. SWP_NOMOVE | SWP_NOSIZE);
  774. }
  775. return 0;
  776. case WM_ADSPROP_SHEET_CREATE:
  777. NOTIFYOUT(WM_ADSPROP_SHEET_CREATE);
  778. if (m_sheetCfg.hwndHidden)
  779. {
  780. ::PostMessage(m_sheetCfg.hwndHidden,
  781. WM_DSA_SHEET_CREATE_NOTIFY,
  782. wParam,
  783. lParam);
  784. }
  785. return 0;
  786. case WM_ADSPROP_NOTIFY_EXIT:
  787. {
  788. NOTIFYOUT(WM_ADSPROP_NOTIFY_EXIT);
  789. if (m_fBeingDestroyed)
  790. {
  791. return 0;
  792. }
  793. m_fBeingDestroyed = TRUE;
  794. DestroyWindow(hWnd);
  795. return 0;
  796. }
  797. case WM_DESTROY:
  798. NOTIFYOUT(WM_DESTROY);
  799. CoUninitialize();
  800. PostQuitMessage(0);
  801. return 0;
  802. default:
  803. break;
  804. }
  805. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  806. }
  807. //+----------------------------------------------------------------------------
  808. //
  809. // Method: CNotifyObj::OnCreate
  810. //
  811. // Synopsis: Window creation/initialization processing. Bind to the DS
  812. // object and read its CN and Allowed-Attributes-Effective
  813. // properties.
  814. //
  815. //-----------------------------------------------------------------------------
  816. LRESULT
  817. CNotifyObj::OnCreate(void)
  818. {
  819. NOTIFYOUT(WM_CREATE);
  820. HRESULT hr;
  821. DWORD cAttrs;
  822. CoInitialize(NULL);
  823. //
  824. // we need to check to see if we can
  825. // convert the string to a CLSID. If
  826. // we can then this is a multi-select
  827. // property page and we shouldn't try
  828. // to bind.
  829. //
  830. CLSID clsid;
  831. if (SUCCEEDED(::CLSIDFromString(m_pwzObjDN, &clsid)))
  832. {
  833. m_hr = S_OK;
  834. return S_OK;
  835. }
  836. //DBG_OUT("+++++++++++++++++++++++++++addrefing (opening) object");
  837. hr = DSAdminOpenObject(m_pwzObjDN,
  838. IID_IDirectoryObject,
  839. (PVOID *)&m_pDsObj);
  840. if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
  841. {
  842. // ErrMsg(IDS_ERRMSG_NO_LONGER_EXISTS);
  843. m_hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  844. }
  845. if (hr == 0x80070051)
  846. {
  847. // On subsequent network failures, ADSI returns this error code which
  848. // is not documented anywhere. I'll turn it into a documented error
  849. // code which happens to be the code returned on the first failure.
  850. //
  851. hr = HRESULT_FROM_WIN32(ERROR_BAD_NET_RESP);
  852. }
  853. if (hr == HRESULT_FROM_WIN32(ERROR_BAD_NET_RESP))
  854. {
  855. // ErrMsg(IDS_ERRMSG_NO_DC_RESPONSE);
  856. m_hr = HRESULT_FROM_WIN32(ERROR_BAD_NET_RESP);
  857. return 0;
  858. }
  859. CHECK_HRESULT(hr, m_hr = hr; return hr);
  860. PWSTR rgszNames[2] = {g_wzName, g_wzAllowed};
  861. hr = m_pDsObj->GetObjectAttributes(rgszNames, 2, &m_pAttrs, &cAttrs);
  862. CHECK_HRESULT(hr, m_hr = hr; return hr);
  863. dspAssert(cAttrs >= 1); // expect to always get name.
  864. for (DWORD i = 0; i < cAttrs; i++)
  865. {
  866. if (_wcsicmp(m_pAttrs[i].pszAttrName, g_wzName) == 0)
  867. {
  868. m_pwzCN = m_pAttrs[i].pADsValues->CaseIgnoreString;
  869. continue;
  870. }
  871. if (_wcsicmp(m_pAttrs[i].pszAttrName, g_wzAllowed) == 0)
  872. {
  873. m_pWritableAttrs = &m_pAttrs[i];
  874. #if DBG == 1
  875. for (DWORD j = 0; j < m_pAttrs[i].dwNumValues; j++)
  876. {
  877. dspDebugOut((DEB_USER4, "Allowed attribute (effective): %ws\n",
  878. m_pAttrs[i].pADsValues[j].CaseIgnoreString));
  879. }
  880. #endif
  881. }
  882. }
  883. NOTIFYOUT(WM_CREATE done);
  884. return 0;
  885. }
  886. //+----------------------------------------------------------------------------
  887. //
  888. // Function: RegisterNotifyClass
  889. //
  890. // Synopsis: Register the window class for the notification window.
  891. //
  892. //-----------------------------------------------------------------------------
  893. VOID
  894. RegisterNotifyClass(void)
  895. {
  896. WNDCLASS wcls;
  897. wcls.style = 0;
  898. wcls.lpfnWndProc = CNotifyObj::StaticNotifyProc;
  899. wcls.cbClsExtra = 0;
  900. wcls.cbWndExtra = 0;
  901. wcls.hInstance = g_hInstance;
  902. wcls.hIcon = NULL;
  903. wcls.hCursor = NULL;
  904. wcls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  905. wcls.lpszMenuName = NULL;
  906. wcls.lpszClassName = tzNotifyWndClass;
  907. RegisterClass(&wcls);
  908. }
  909. //+----------------------------------------------------------------------------
  910. //
  911. // Function: FindSheetNoSetFocus
  912. //
  913. // Synopsis: Locate the property sheet for the DS object.
  914. //
  915. //-----------------------------------------------------------------------------
  916. HWND
  917. FindSheetNoSetFocus(PWSTR pwzObjADsPath)
  918. {
  919. HWND hNotify = NULL;
  920. //
  921. // See if the object/window already exists for this property sheet.
  922. // Note that the window title is the DN of the object plus the instance id.
  923. //
  924. #ifdef UNICODE
  925. CStr cstrTitle(pwzObjADsPath);
  926. WCHAR szIH[10];
  927. _itow(g_iInstance, szIH, 16);
  928. cstrTitle += szIH;
  929. hNotify = FindWindow(tzNotifyWndClass, cstrTitle);
  930. #else
  931. LPSTR pszTitle;
  932. if (UnicodeToTchar(pwzObjADsPath, &pszTitle))
  933. {
  934. CStr cstrTitle(pszTitle);
  935. char szIH[10];
  936. _itoa(g_iInstance, szIH, 16);
  937. cstrTitle += szIH;
  938. hNotify = FindWindow(tzNotifyWndClass, cstrTitle);
  939. delete [] pszTitle;
  940. }
  941. #endif
  942. dspDebugOut((DEB_ITRACE, "FindSheet: returned hNotify = 0x%08x\n", hNotify));
  943. return hNotify;
  944. }
  945. //+----------------------------------------------------------------------------
  946. //
  947. // Function: BringSheetToForeground
  948. //
  949. // Synopsis: Locate the property sheet for the DS object identified by the
  950. // data object and bring it to the top of the Z order
  951. //
  952. //-----------------------------------------------------------------------------
  953. extern "C" BOOL
  954. BringSheetToForeground(PWSTR pwzObjADsPath, BOOL bActivate)
  955. {
  956. HWND hNotify = FindSheetNoSetFocus(pwzObjADsPath);
  957. if (!hNotify)
  958. {
  959. return FALSE;
  960. }
  961. PostMessage(hNotify, WM_ADSPROP_NOTIFY_FOREGROUND, (WPARAM)bActivate, 0);
  962. return TRUE;
  963. }
  964. //+----------------------------------------------------------------------------
  965. //
  966. // Function: FindSheet
  967. //
  968. // Synopsis: Locate the property sheet for the DS object identified by the
  969. // data object. For use in the dsprop DLL. If found, bring the
  970. // sheet to the foregroung and set the focus to the sheet.
  971. //
  972. //-----------------------------------------------------------------------------
  973. BOOL
  974. FindSheet(PWSTR pwzObjADsPath)
  975. {
  976. HWND hNotify = FindSheetNoSetFocus(pwzObjADsPath);
  977. if (!hNotify)
  978. {
  979. return FALSE;
  980. }
  981. SendMessage(hNotify, WM_ADSPROP_NOTIFY_SETFOCUS, 0, 0);
  982. return TRUE;
  983. }
  984. //+----------------------------------------------------------------------------
  985. //
  986. // Function: IsSheetAlreadyUp
  987. //
  988. // Synopsis: Public, exported function to locate a prop sheet for the DS
  989. // object identified by the data object. If found, sends a message
  990. // to the sheet to bring it to the foreground.
  991. //
  992. //-----------------------------------------------------------------------------
  993. extern "C" BOOL
  994. IsSheetAlreadyUp(LPDATAOBJECT pDataObj)
  995. {
  996. // Get the object's DN from the data object.
  997. //
  998. HRESULT hr = S_OK;
  999. STGMEDIUM sm = {TYMED_NULL, NULL, NULL};
  1000. FORMATETC fmte = {g_cfDsMultiSelectProppages, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1001. PWSTR pszUniqueID;
  1002. BOOL fFound = FALSE;
  1003. hr = pDataObj->GetData(&fmte, &sm);
  1004. if (FAILED(hr))
  1005. {
  1006. STGMEDIUM smDS = {TYMED_NULL, NULL, NULL};
  1007. FORMATETC fmteDS = {g_cfDsObjectNames, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1008. LPDSOBJECTNAMES pDsObjectNames;
  1009. hr = pDataObj->GetData(&fmteDS, &smDS);
  1010. if (FAILED(hr))
  1011. {
  1012. return FALSE;
  1013. }
  1014. pDsObjectNames = (LPDSOBJECTNAMES)smDS.hGlobal;
  1015. dspAssert(pDsObjectNames->cItems > 0);
  1016. pszUniqueID = (LPWSTR)ByteOffset(pDsObjectNames,
  1017. pDsObjectNames->aObjects[0].offsetName);
  1018. fFound = FindSheet(pszUniqueID);
  1019. ReleaseStgMedium(&smDS);
  1020. }
  1021. else
  1022. {
  1023. pszUniqueID = (PWSTR)sm.hGlobal;
  1024. dspAssert(pszUniqueID != NULL);
  1025. fFound = FindSheet(pszUniqueID);
  1026. ReleaseStgMedium(&sm);
  1027. }
  1028. return fFound;
  1029. }
  1030. #ifdef DSADMIN
  1031. //+----------------------------------------------------------------------------
  1032. //
  1033. // Method: CMultiSelectErrorDialog::CMultiSelectErrorDialog
  1034. //
  1035. // Synopsis: Multi-select error message dialog constructor
  1036. //
  1037. //-----------------------------------------------------------------------------
  1038. CMultiSelectErrorDialog::CMultiSelectErrorDialog(HWND hNotifyObj, HWND hParent)
  1039. : m_hWnd(NULL),
  1040. m_hNotifyObj(hNotifyObj),
  1041. m_hParent(hParent),
  1042. m_bModal(FALSE),
  1043. m_bInit(FALSE),
  1044. m_pPageInfoArray(NULL),
  1045. m_nPageCount(0),
  1046. m_pDataObj(NULL)
  1047. {
  1048. }
  1049. //+----------------------------------------------------------------------------
  1050. //
  1051. // Member: CMultiSelectErrorDialog::StaticDlgProc
  1052. //
  1053. // Synopsis: The static dialog proc for displaying errors for multi-select pages
  1054. //
  1055. //-----------------------------------------------------------------------------
  1056. INT_PTR CALLBACK CMultiSelectErrorDialog::StaticDlgProc(HWND hDlg,
  1057. UINT uMsg,
  1058. WPARAM wParam,
  1059. LPARAM lParam)
  1060. {
  1061. CMultiSelectErrorDialog* dlg = NULL;
  1062. UINT code;
  1063. UINT id;
  1064. switch (uMsg)
  1065. {
  1066. case WM_INITDIALOG:
  1067. dlg = reinterpret_cast<CMultiSelectErrorDialog*>(lParam);
  1068. dspAssert(dlg != NULL);
  1069. SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)dlg);
  1070. SetForegroundWindow(hDlg);
  1071. return dlg->OnInitDialog(hDlg);
  1072. case WM_COMMAND:
  1073. code = GET_WM_COMMAND_CMD(wParam, lParam);
  1074. id = GET_WM_COMMAND_ID(wParam, lParam);
  1075. if (dlg == NULL)
  1076. {
  1077. dlg = reinterpret_cast<CMultiSelectErrorDialog*>(GetWindowLongPtr(hDlg, DWLP_USER));
  1078. }
  1079. switch (id)
  1080. {
  1081. case IDOK:
  1082. case IDCANCEL:
  1083. if (code == BN_CLICKED)
  1084. {
  1085. dlg->OnClose();
  1086. }
  1087. break;
  1088. case IDC_COPY_BUTTON:
  1089. if (code == BN_CLICKED)
  1090. {
  1091. dlg->OnCopyButton();
  1092. }
  1093. break;
  1094. case IDC_PROPERTIES_BUTTON:
  1095. if (code == BN_CLICKED)
  1096. {
  1097. dlg->ShowListViewItemProperties();
  1098. }
  1099. break;
  1100. }
  1101. break;
  1102. case WM_NOTIFY:
  1103. {
  1104. if (dlg == NULL)
  1105. {
  1106. dlg = reinterpret_cast<CMultiSelectErrorDialog*>(GetWindowLongPtr(hDlg, DWLP_USER));
  1107. }
  1108. int idCtrl = (int)wParam;
  1109. LPNMHDR pnmh = reinterpret_cast<LPNMHDR>(lParam);
  1110. if (idCtrl == IDC_ERROR_LIST)
  1111. {
  1112. switch (pnmh->code)
  1113. {
  1114. case NM_DBLCLK:
  1115. {
  1116. dlg->ListItemActivate(pnmh);
  1117. }
  1118. break;
  1119. case LVN_ITEMCHANGED:
  1120. case NM_CLICK:
  1121. {
  1122. dlg->ListItemClick(pnmh);
  1123. }
  1124. break;
  1125. default:
  1126. break;
  1127. }
  1128. }
  1129. break;
  1130. }
  1131. case WM_HELP:
  1132. {
  1133. LPHELPINFO pHelpInfo = reinterpret_cast<LPHELPINFO>(lParam);
  1134. if (!pHelpInfo || pHelpInfo->iCtrlId < 1 || IDH_NO_HELP == pHelpInfo->dwContextId)
  1135. {
  1136. return 0;
  1137. }
  1138. WinHelp(hDlg, DSPROP_HELP_FILE_NAME, HELP_CONTEXTPOPUP, pHelpInfo->dwContextId);
  1139. break;
  1140. }
  1141. }
  1142. return 0;
  1143. }
  1144. //+----------------------------------------------------------------------------
  1145. //
  1146. // Member: CMultiSelectErrorDialog::Init
  1147. //
  1148. // Synopsis: Initializes the member variables
  1149. //
  1150. //-----------------------------------------------------------------------------
  1151. BOOL CMultiSelectErrorDialog::OnInitDialog(HWND hDlg)
  1152. {
  1153. dspAssert(m_bInit);
  1154. if (!m_bInit)
  1155. {
  1156. return TRUE;
  1157. }
  1158. m_hWnd = hDlg;
  1159. //
  1160. // Disable the properties button until there is a selection
  1161. //
  1162. EnableWindow(GetDlgItem(m_hWnd, IDC_PROPERTIES_BUTTON), FALSE);
  1163. HRESULT hr = S_OK;
  1164. hr = InitializeListBox(hDlg);
  1165. CHECK_HRESULT(hr, return TRUE;);
  1166. CComPtr<IADsPathname> spPathCracker;
  1167. hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
  1168. IID_IADsPathname, (PVOID *)&spPathCracker);
  1169. CHECK_HRESULT_REPORT(hr, hDlg, return TRUE);
  1170. dspAssert(m_pPageInfoArray != NULL);
  1171. if (m_pPageInfoArray == NULL)
  1172. {
  1173. return TRUE;
  1174. }
  1175. INT iMaxLen = 0;
  1176. SIZE size = {0,0};
  1177. //
  1178. // Load the appropriate list box
  1179. //
  1180. for (UINT pageIdx = 0; pageIdx < m_nPageCount; pageIdx++)
  1181. {
  1182. if (m_pPageInfoArray[pageIdx].m_ApplyStatus == CPageInfo::failed)
  1183. {
  1184. PTSTR ptzCaptionFormat = NULL;
  1185. LoadStringToTchar(IDS_MULTI_FAILURE_CAPTION, &ptzCaptionFormat);
  1186. if (ptzCaptionFormat != NULL)
  1187. {
  1188. //NTRAID#NTBUG9-571996-2002/03/10-jmessec Buffer Overrun: Can't use wcslen(ptzCaptionFormat) as determination of length of
  1189. //string; format could be %20s
  1190. PWSTR pszCaption = new WCHAR[wcslen(ptzCaptionFormat) + wcslen(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetPageTitle()) + 1];
  1191. if (pszCaption != NULL)
  1192. {
  1193. wsprintf(pszCaption, ptzCaptionFormat, m_pPageInfoArray[pageIdx].m_ApplyErrors.GetPageTitle());
  1194. SetWindowText(GetDlgItem(m_hWnd, IDC_ERROR_STATIC), pszCaption);
  1195. delete[] pszCaption;
  1196. pszCaption = NULL;
  1197. }
  1198. }
  1199. for (UINT objectIdx = 0; objectIdx < m_pPageInfoArray[pageIdx].m_ApplyErrors.GetCount(); objectIdx++)
  1200. {
  1201. //
  1202. // Get the objects path and class name
  1203. //
  1204. PWSTR pszObjPath = m_pPageInfoArray[pageIdx].m_ApplyErrors.GetName(objectIdx);
  1205. PWSTR pszObjClass = m_pPageInfoArray[pageIdx].m_ApplyErrors.GetClass(objectIdx);
  1206. //
  1207. // Get the class icon for the object
  1208. //
  1209. int iIcon = g_ClassIconCache.GetClassIconIndex(pszObjClass);
  1210. dspAssert(iIcon != -1);
  1211. //
  1212. // Get the object name from the path
  1213. //
  1214. PWSTR pszLabel = NULL;
  1215. CComBSTR bstr;
  1216. hr = spPathCracker->Set(CComBSTR(pszObjPath),
  1217. ADS_SETTYPE_FULL);
  1218. CHECK_HRESULT(hr, pszLabel = pszObjPath;);
  1219. if (SUCCEEDED(hr))
  1220. {
  1221. hr = spPathCracker->SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  1222. CHECK_HRESULT(hr, pszLabel = pszObjPath;);
  1223. }
  1224. // CODEWORK 122531 Should we be turning off escaped mode here?
  1225. if (SUCCEEDED(hr))
  1226. {
  1227. hr = spPathCracker->Retrieve(ADS_FORMAT_LEAF, &bstr);
  1228. CHECK_HRESULT(hr, pszLabel = pszObjPath;);
  1229. }
  1230. if (SUCCEEDED(hr))
  1231. {
  1232. pszLabel = bstr;
  1233. }
  1234. dspAssert(pszLabel != NULL);
  1235. //
  1236. // Create the list view item
  1237. //
  1238. LV_ITEM lvi = {0};
  1239. lvi.mask = LVIF_TEXT | LVIF_PARAM;
  1240. lvi.iSubItem = IDX_NAME_COL;
  1241. lvi.lParam = (LPARAM)pszObjPath;
  1242. lvi.pszText = pszLabel;
  1243. lvi.iItem = objectIdx;
  1244. if (-1 != iIcon)
  1245. {
  1246. lvi.mask |= LVIF_IMAGE;
  1247. lvi.iImage = iIcon;
  1248. }
  1249. //
  1250. // Insert the new item
  1251. //
  1252. int NewIndex = ListView_InsertItem(m_hList, &lvi);
  1253. dspAssert(NewIndex != -1);
  1254. if (NewIndex == -1)
  1255. {
  1256. continue;
  1257. }
  1258. //
  1259. // Format the error message and insert it
  1260. //
  1261. PWSTR ptzMsg = NULL;
  1262. if (FAILED(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetError(objectIdx)))
  1263. {
  1264. LoadErrorMessage(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetError(objectIdx), 0, &ptzMsg);
  1265. if (!ptzMsg)
  1266. {
  1267. ptzMsg = L""; // make prefix happy.
  1268. }
  1269. //
  1270. // REVIEW_JEFFJON : this is hack to get rid of two extra characters
  1271. // at the end of the string
  1272. //
  1273. size_t iLen = wcslen(ptzMsg);
  1274. ptzMsg[iLen - 2] = L'\0';
  1275. }
  1276. else
  1277. {
  1278. ptzMsg = new WCHAR[wcslen(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetStringError(objectIdx)) + 1];
  1279. if (ptzMsg != NULL)
  1280. {
  1281. wcscpy(ptzMsg, m_pPageInfoArray[pageIdx].m_ApplyErrors.GetStringError(objectIdx));
  1282. }
  1283. }
  1284. if (NULL != ptzMsg)
  1285. {
  1286. ListView_SetItemText(m_hList, NewIndex, IDX_ERROR_COL,
  1287. ptzMsg);
  1288. INT len = lstrlen(ptzMsg);
  1289. if( len > iMaxLen )
  1290. {
  1291. HDC hdc = GetDC(hDlg);
  1292. GetTextExtentPoint32(hdc,ptzMsg,lstrlen(ptzMsg),&size);
  1293. ReleaseDC(hDlg, hdc);
  1294. iMaxLen = len;
  1295. }
  1296. delete[] ptzMsg;
  1297. }
  1298. }
  1299. }
  1300. else if (m_pPageInfoArray[pageIdx].m_ApplyStatus == CPageInfo::success)
  1301. {
  1302. //
  1303. // Insert the page title into the success list box
  1304. //
  1305. SendDlgItemMessage(m_hWnd, IDC_SUCCESS_LISTBOX, LB_ADDSTRING, 0, (LPARAM)m_pPageInfoArray[pageIdx].m_ptzTitle);
  1306. }
  1307. else // apply not tried yet
  1308. {
  1309. //
  1310. // Insert the page title into the not attempted list box
  1311. //
  1312. SendDlgItemMessage(m_hWnd, IDC_NOT_ATTEMPTED_LISTBOX, LB_ADDSTRING, 0, (LPARAM)m_pPageInfoArray[pageIdx].m_ptzTitle);
  1313. }
  1314. }
  1315. //
  1316. // Select the first item in the error list
  1317. //
  1318. LVCOLUMN col;
  1319. col.mask = LVCF_WIDTH;
  1320. col.cx = size.cx;
  1321. ListView_SetColumn(m_hList,1, &col);
  1322. ListView_SetExtendedListViewStyle(m_hList, LVS_EX_FULLROWSELECT);
  1323. ListView_SetItemState(m_hList, 0, LVIS_SELECTED, LVIS_SELECTED);
  1324. return TRUE;
  1325. }
  1326. //+----------------------------------------------------------------------------
  1327. //
  1328. // Member: CMultiSelectErrorDialog::InitializeListBox
  1329. //
  1330. // Synopsis: Initializes the member variables
  1331. //
  1332. //-----------------------------------------------------------------------------
  1333. HRESULT CMultiSelectErrorDialog::InitializeListBox(HWND hDlg)
  1334. {
  1335. m_hList = GetDlgItem(hDlg, IDC_ERROR_LIST);
  1336. if (m_hList == NULL)
  1337. {
  1338. return HRESULT_FROM_WIN32(GetLastError());
  1339. }
  1340. ListView_SetExtendedListViewStyle(m_hList, LVS_EX_FULLROWSELECT);
  1341. //
  1342. // Set the column headings.
  1343. //
  1344. PTSTR ptsz;
  1345. RECT rect;
  1346. GetClientRect(m_hList, &rect);
  1347. if (!LoadStringToTchar(IDS_COL_TITLE_OBJNAME, &ptsz))
  1348. {
  1349. ReportError(GetLastError(), 0, hDlg);
  1350. return HRESULT_FROM_WIN32(GetLastError());
  1351. }
  1352. LV_COLUMN lvc = {0};
  1353. lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
  1354. lvc.fmt = LVCFMT_LEFT;
  1355. lvc.cx = OBJ_LIST_NAME_COL_WIDTH;
  1356. lvc.pszText = ptsz;
  1357. lvc.iSubItem = IDX_NAME_COL;
  1358. ListView_InsertColumn(m_hList, IDX_NAME_COL, &lvc);
  1359. delete[] ptsz;
  1360. if (!LoadStringToTchar(IDS_COL_TITLE_ERRORMSG, &ptsz))
  1361. {
  1362. ReportError(GetLastError(), 0, hDlg);
  1363. return HRESULT_FROM_WIN32(GetLastError());
  1364. }
  1365. lvc.cx = rect.right - OBJ_LIST_NAME_COL_WIDTH;
  1366. lvc.pszText = ptsz;
  1367. lvc.iSubItem = IDX_ERROR_COL;
  1368. ListView_InsertColumn(m_hList, IDX_ERROR_COL, &lvc);
  1369. delete[] ptsz;
  1370. //
  1371. // Assign the imagelist to the listview
  1372. //
  1373. ListView_SetImageList(m_hList, g_ClassIconCache.GetImageList(), LVSIL_SMALL);
  1374. return S_OK;
  1375. }
  1376. //+----------------------------------------------------------------------------
  1377. //
  1378. // Member: CMultiSelectErrorDialog::Init
  1379. //
  1380. // Synopsis: Initializes the member variables
  1381. //
  1382. //-----------------------------------------------------------------------------
  1383. HRESULT CMultiSelectErrorDialog::Init(CPageInfo* pPageInfoArray,
  1384. UINT nPageCount,
  1385. IDataObject* pDataObj)
  1386. {
  1387. m_nPageCount = nPageCount;
  1388. m_pPageInfoArray = pPageInfoArray;
  1389. m_bInit = TRUE;
  1390. m_pDataObj = pDataObj;
  1391. m_pDataObj->AddRef();
  1392. return S_OK;
  1393. }
  1394. //+----------------------------------------------------------------------------
  1395. //
  1396. // Member: CMultiSelectErrorDialog::OnCopyButton
  1397. //
  1398. // Synopsis: Called when the user presses the Retry button
  1399. //
  1400. //-----------------------------------------------------------------------------
  1401. void CMultiSelectErrorDialog::OnCopyButton()
  1402. {
  1403. dspAssert(m_bInit);
  1404. if (!m_bInit)
  1405. {
  1406. return;
  1407. }
  1408. dspAssert(m_pPageInfoArray != NULL);
  1409. if (m_pPageInfoArray == NULL)
  1410. {
  1411. return;
  1412. }
  1413. CComPtr<IADsPathname> spPathCracker;
  1414. HRESULT hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
  1415. IID_IADsPathname, (PVOID *)&spPathCracker);
  1416. CHECK_HRESULT_REPORT(hr, m_hWnd, return);
  1417. if (OpenClipboard(m_hWnd) == 0)
  1418. {
  1419. return;
  1420. }
  1421. if (EmptyClipboard() == 0)
  1422. {
  1423. CloseClipboard();
  1424. return;
  1425. }
  1426. CStrW szClipboardData;
  1427. szClipboardData.Empty();
  1428. for (UINT pageIdx = 0; pageIdx < m_nPageCount; pageIdx++)
  1429. {
  1430. for (UINT objectIdx = 0; objectIdx < m_pPageInfoArray[pageIdx].m_ApplyErrors.GetCount(); objectIdx++)
  1431. {
  1432. //
  1433. // Get the objects path and class name
  1434. //
  1435. PWSTR pszObjPath = m_pPageInfoArray[pageIdx].m_ApplyErrors.GetName(objectIdx);
  1436. //
  1437. // Get the object name from the path
  1438. //
  1439. PWSTR pszLabel = NULL;
  1440. CComBSTR bstr;
  1441. hr = spPathCracker->Set(CComBSTR(pszObjPath),
  1442. ADS_SETTYPE_FULL);
  1443. CHECK_HRESULT(hr, pszLabel = pszObjPath;);
  1444. if (SUCCEEDED(hr))
  1445. {
  1446. hr = spPathCracker->SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  1447. CHECK_HRESULT(hr, pszLabel = pszObjPath;);
  1448. }
  1449. // CODEWORK 122531 Should we be turning off escaped mode here?
  1450. if (SUCCEEDED(hr))
  1451. {
  1452. hr = spPathCracker->Retrieve(ADS_FORMAT_LEAF, &bstr);
  1453. CHECK_HRESULT(hr, pszLabel = pszObjPath;);
  1454. }
  1455. if (SUCCEEDED(hr))
  1456. {
  1457. pszLabel = bstr;
  1458. }
  1459. dspAssert(pszLabel != NULL);
  1460. //
  1461. // Format the error message and insert it
  1462. //
  1463. PWSTR ptzMsg = NULL;
  1464. if (FAILED(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetError(objectIdx)))
  1465. {
  1466. LoadErrorMessage(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetError(objectIdx), 0, &ptzMsg);
  1467. }
  1468. else
  1469. {
  1470. ptzMsg = new WCHAR[wcslen(m_pPageInfoArray[pageIdx].m_ApplyErrors.GetStringError(objectIdx)) + 1];
  1471. if (ptzMsg != NULL)
  1472. {
  1473. wcscpy(ptzMsg, m_pPageInfoArray[pageIdx].m_ApplyErrors.GetStringError(objectIdx));
  1474. }
  1475. }
  1476. if (NULL != ptzMsg)
  1477. {
  1478. szClipboardData += pszLabel;
  1479. szClipboardData += L",";
  1480. szClipboardData += ptzMsg;
  1481. szClipboardData += g_wzCRLF;
  1482. delete [] ptzMsg;
  1483. }
  1484. }
  1485. }
  1486. HGLOBAL hBuffer = NULL;
  1487. DWORD dwBufferSize;
  1488. HANDLE hMemClipboard;
  1489. LPTSTR pszGlobalBuffer = NULL;
  1490. dwBufferSize = (szClipboardData.GetLength() + 1) * sizeof(TCHAR);
  1491. hBuffer = GlobalAlloc (GMEM_MOVEABLE, dwBufferSize);
  1492. if (!hBuffer)
  1493. {
  1494. return;
  1495. }
  1496. pszGlobalBuffer = (LPTSTR)GlobalLock (hBuffer);
  1497. if ( NULL == pszGlobalBuffer)
  1498. {
  1499. // allocation or lock failed so bail out
  1500. GlobalFree (hBuffer);
  1501. return;
  1502. }
  1503. _tcscpy ( pszGlobalBuffer, szClipboardData );
  1504. GlobalUnlock (hBuffer);
  1505. if ( NULL != hBuffer )
  1506. {
  1507. hMemClipboard = SetClipboardData (
  1508. #if UNICODE
  1509. CF_UNICODETEXT, // UNICODE text in the clipboard
  1510. #else
  1511. CF_TEXT, // ANSI text in the clipboard
  1512. #endif
  1513. hBuffer);
  1514. if (hMemClipboard == NULL)
  1515. {
  1516. //free memory since it didn't make it to the clipboard
  1517. GlobalFree (hBuffer);
  1518. return;
  1519. }
  1520. }
  1521. else
  1522. {
  1523. //free memory since it didn't make it to the clipboard
  1524. GlobalFree (hBuffer);
  1525. return;
  1526. }
  1527. CloseClipboard();
  1528. }
  1529. //+----------------------------------------------------------------------------
  1530. //
  1531. // Member: CMultiSelectErrorDialog::ListItemClick
  1532. //
  1533. // Synopsis: Invokes a property page for the item that was activated
  1534. //
  1535. //-----------------------------------------------------------------------------
  1536. void CMultiSelectErrorDialog::ListItemClick(LPNMHDR)
  1537. {
  1538. UINT nSelectedCount = ListView_GetSelectedCount(m_hList);
  1539. if (nSelectedCount == 1)
  1540. {
  1541. EnableWindow(GetDlgItem(m_hWnd, IDC_PROPERTIES_BUTTON), TRUE);
  1542. }
  1543. else
  1544. {
  1545. EnableWindow(GetDlgItem(m_hWnd, IDC_PROPERTIES_BUTTON), FALSE);
  1546. }
  1547. }
  1548. //+----------------------------------------------------------------------------
  1549. //
  1550. // Member: CMultiSelectErrorDialog::ListItemActivate
  1551. //
  1552. // Synopsis: Invokes a property page for the item that was activated
  1553. //
  1554. //-----------------------------------------------------------------------------
  1555. void CMultiSelectErrorDialog::ListItemActivate(LPNMHDR pnmh)
  1556. {
  1557. LPNMITEMACTIVATE pActivateHeader = reinterpret_cast<LPNMITEMACTIVATE>(pnmh);
  1558. dspAssert(pActivateHeader != NULL);
  1559. if (pActivateHeader != NULL)
  1560. {
  1561. ShowListViewItemProperties();
  1562. }
  1563. }
  1564. //+----------------------------------------------------------------------------
  1565. //
  1566. // Member: CMultiSelectErrorDialog::ShowListViewItemProperties()
  1567. //
  1568. // Synopsis: Invokes a secondary sheet for the selected list view item
  1569. //
  1570. //-----------------------------------------------------------------------------
  1571. BOOL CMultiSelectErrorDialog::ShowListViewItemProperties()
  1572. {
  1573. BOOL bSuccess = TRUE;
  1574. UINT nSelectCount = ListView_GetSelectedCount(m_hList);
  1575. if (nSelectCount == 1)
  1576. {
  1577. //
  1578. // Get the selected item
  1579. //
  1580. int nSelectedItem = ListView_GetNextItem(m_hList, -1, LVNI_SELECTED);
  1581. if (nSelectedItem != -1)
  1582. {
  1583. //
  1584. // Retrieve the item's path
  1585. //
  1586. LVITEM lvi = {0};
  1587. lvi.iItem = nSelectedItem;
  1588. lvi.mask = LVIF_PARAM;
  1589. if (ListView_GetItem(m_hList, &lvi))
  1590. {
  1591. PWSTR pwzPath = reinterpret_cast<PWSTR>(lvi.lParam);
  1592. if (pwzPath != NULL)
  1593. {
  1594. //
  1595. // Get the DN
  1596. //
  1597. CComPtr<IADsPathname> spPathCracker;
  1598. HRESULT hr = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER,
  1599. IID_IADsPathname, (PVOID *)&spPathCracker);
  1600. CHECK_HRESULT_REPORT(hr, m_hWnd, return FALSE;);
  1601. hr = spPathCracker->Set(CComBSTR(pwzPath), ADS_SETTYPE_FULL);
  1602. CHECK_HRESULT_REPORT(hr, m_hWnd, return FALSE;);
  1603. hr = spPathCracker->put_EscapedMode(ADS_ESCAPEDMODE_ON);
  1604. dspAssert(SUCCEEDED(hr));
  1605. hr = spPathCracker->SetDisplayType(ADS_DISPLAY_FULL);
  1606. CHECK_HRESULT_REPORT(hr, m_hWnd, return FALSE;);
  1607. CComBSTR bstrDN;
  1608. hr = spPathCracker->Retrieve(ADS_FORMAT_X500_DN, &bstrDN);
  1609. CHECK_HRESULT_REPORT(hr, m_hWnd, return FALSE;);
  1610. //
  1611. // Invoke the page
  1612. //
  1613. hr = PostADsPropSheet(bstrDN, m_pDataObj, m_hParent, m_hNotifyObj, FALSE);
  1614. if (FAILED(hr))
  1615. {
  1616. bSuccess = FALSE;
  1617. }
  1618. }
  1619. else
  1620. {
  1621. bSuccess = FALSE;
  1622. }
  1623. }
  1624. else
  1625. {
  1626. bSuccess = FALSE;
  1627. }
  1628. }
  1629. else
  1630. {
  1631. bSuccess = FALSE;
  1632. }
  1633. }
  1634. return bSuccess;
  1635. }
  1636. //+----------------------------------------------------------------------------
  1637. //
  1638. // Member: CMultiSelectErrorDialog::OnClose
  1639. //
  1640. // Synopsis: Closes the modal dialog
  1641. //
  1642. //-----------------------------------------------------------------------------
  1643. void CMultiSelectErrorDialog::OnClose()
  1644. {
  1645. EndDialog(m_hWnd, 0);
  1646. }
  1647. //+----------------------------------------------------------------------------
  1648. //
  1649. // Member: CMultiSelectErrorDialog::DoModal
  1650. //
  1651. // Synopsis: Displays the modal dialog
  1652. //
  1653. //-----------------------------------------------------------------------------
  1654. int CMultiSelectErrorDialog::DoModal()
  1655. {
  1656. m_bModal = TRUE;
  1657. dspAssert(IsWindow(m_hParent));
  1658. return (int)DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_MULTISELECT_ERROR_DIALOG),
  1659. m_hParent, StaticDlgProc, (LPARAM)this);
  1660. }
  1661. //+----------------------------------------------------------------------------
  1662. //
  1663. // Member: CMultiSelectErrorDialog::ShowWindow
  1664. //
  1665. // Synopsis: Displays the modeless dialog
  1666. //
  1667. //-----------------------------------------------------------------------------
  1668. BOOL CMultiSelectErrorDialog::ShowWindow()
  1669. {
  1670. m_bModal = FALSE;
  1671. m_hWnd = CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_MULTISELECT_ERROR_DIALOG),
  1672. m_hParent, StaticDlgProc, (LPARAM)this);
  1673. return ::ShowWindow(m_hWnd, SW_SHOWNORMAL);
  1674. }
  1675. #endif // DSADMIN