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.

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