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.

2007 lines
55 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: cdomain.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "stdafx.h"
  11. //#include "afxdlgs.h"
  12. #include <lm.h>
  13. #include "activeds.h"
  14. #include <dnsapi.h> // for DnsFlushResolverCache()
  15. #include "domobj.h"
  16. #include "Cdomain.h"
  17. #include "DataObj.h"
  18. #include "notify.h"
  19. #ifdef _DEBUG
  20. #define new DEBUG_NEW
  21. #undef THIS_FILE
  22. static char THIS_FILE[] = __FILE__;
  23. #endif
  24. #define DOMADMIN_LINKED_HELP_FILE L"ADconcepts.chm"
  25. #define DOMADMIN_SNAPIN_HELP_FILE L"domadmin.chm"
  26. int _MessageBox(HWND hWnd, // handle to owner window
  27. LPCTSTR lpText, // pointer to text in message box
  28. UINT uType); // style of message box
  29. /////////////////////////////////////////////////////////////////////////////
  30. // macros
  31. #define ARRAYLEN(x) (sizeof(x) / sizeof((x)[0]))
  32. /////////////////////////////////////////////////////////////////////////////
  33. // constants
  34. // {19B9A3F8-F975-11d1-97AD-00A0C9A06D2D}
  35. static const GUID CLSID_DomainSnapinAbout =
  36. { 0x19b9a3f8, 0xf975, 0x11d1, { 0x97, 0xad, 0x0, 0xa0, 0xc9, 0xa0, 0x6d, 0x2d } };
  37. const CLSID CLSID_DomainAdmin = { /* ebc53a38-a23f-11d0-b09b-00c04fd8dca6 */
  38. 0xebc53a38,
  39. 0xa23f,
  40. 0x11d0,
  41. {0xb0, 0x9b, 0x00, 0xc0, 0x4f, 0xd8, 0xdc, 0xa6}
  42. };
  43. const GUID cDefaultNodeType = { /* 4c06495e-a241-11d0-b09b-00c04fd8dca6 */
  44. 0x4c06495e,
  45. 0xa241,
  46. 0x11d0,
  47. {0xb0, 0x9b, 0x00, 0xc0, 0x4f, 0xd8, 0xdc, 0xa6}
  48. };
  49. const wchar_t* cszDefaultNodeType = _T("4c06495e-a241-11d0-b09b-00c04fd8dca6");
  50. // Internal private format
  51. const wchar_t* CCF_DS_DOMAIN_TREE_SNAPIN_INTERNAL = L"DS_DOMAIN_TREE_SNAPIN_INTERNAL";
  52. /////////////////////////////////////////////////////////////////////////////
  53. // global functions
  54. //forward decl
  55. void PrintColumn(
  56. PADS_SEARCH_COLUMN pColumn,
  57. LPWSTR pszColumnName
  58. );
  59. BOOL IsMMCMultiSelectDataObject(IDataObject* pDataObject)
  60. {
  61. if (pDataObject == NULL)
  62. return FALSE;
  63. static UINT s_cf = 0;
  64. if (s_cf == 0)
  65. {
  66. USES_CONVERSION;
  67. s_cf = RegisterClipboardFormat(W2T(CCF_MMC_MULTISELECT_DATAOBJECT));
  68. }
  69. FORMATETC fmt = {(CLIPFORMAT)s_cf, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  70. return (pDataObject->QueryGetData(&fmt) == S_OK);
  71. }
  72. #define NEXT_HELP_TABLE_ENTRY(p) ((p)+2)
  73. #define TABLE_ENTRY_CTRL_ID(p) (*p)
  74. #define TABLE_ENTRY_HELP_ID(p) (*(p+1))
  75. #define IS_LAST_TABLE_ENTRY(p) (TABLE_ENTRY_CTRL_ID(p) == 0)
  76. BOOL FindDialogContextTopic(/*IN*/ DWORD* pTable,
  77. /*IN*/ HELPINFO* pHelpInfo,
  78. /*OUT*/ ULONG* pnContextTopic)
  79. {
  80. ASSERT(pHelpInfo != NULL);
  81. *pnContextTopic = 0;
  82. // look inside the table
  83. while (!IS_LAST_TABLE_ENTRY(pTable))
  84. {
  85. if (TABLE_ENTRY_CTRL_ID(pTable) == (DWORD)pHelpInfo->iCtrlId)
  86. {
  87. *pnContextTopic = TABLE_ENTRY_HELP_ID(pTable);
  88. return TRUE;
  89. }
  90. pTable = NEXT_HELP_TABLE_ENTRY(pTable);
  91. }
  92. return FALSE;
  93. }
  94. void DialogContextHelp(DWORD* pTable, HELPINFO* pHelpInfo)
  95. {
  96. ULONG nContextTopic;
  97. if (FindDialogContextTopic(pTable, pHelpInfo, &nContextTopic))
  98. {
  99. CString szHelpFilePath;
  100. LPTSTR lpszBuffer = szHelpFilePath.GetBuffer(2*MAX_PATH+1);
  101. UINT nLen = ::GetSystemWindowsDirectory(lpszBuffer, 2*MAX_PATH);
  102. if (nLen == 0)
  103. return;
  104. // NOTICE-2002/03/07-ericb - SecurityPush: using wcsncpy now. GetBuffer above null terminates the buffer.
  105. wcsncpy(&lpszBuffer[nLen], L"\\HELP\\DOMADMIN.HLP", 2*MAX_PATH - nLen);
  106. szHelpFilePath.ReleaseBuffer();
  107. ::WinHelp((HWND) pHelpInfo->hItemHandle,
  108. szHelpFilePath, HELP_CONTEXTPOPUP, nContextTopic);
  109. }
  110. }
  111. LPCWSTR GetServerNameFromCommandLine()
  112. {
  113. const WCHAR szOverrideSrvCommandLine[] = L"/Server="; // Not subject to localization
  114. const int cchOverrideSrvCommandLine = (sizeof(szOverrideSrvCommandLine)/sizeof(WCHAR)) - 1;
  115. static CString g_strOverrideServerName;
  116. // retrieve the command line arguments
  117. LPCWSTR* lpServiceArgVectors; // Array of pointers to string
  118. int cArgs = 0; // Count of arguments
  119. lpServiceArgVectors = (LPCWSTR *)CommandLineToArgvW(GetCommandLineW(), OUT &cArgs);
  120. if (lpServiceArgVectors == NULL)
  121. {
  122. return NULL;
  123. }
  124. CString str;
  125. for (int i = 1; i < cArgs; i++)
  126. {
  127. ASSERT(lpServiceArgVectors[i] != NULL);
  128. str = lpServiceArgVectors[i]; // Copy the string
  129. TRACE (_T("command line arg: %s\n"), lpServiceArgVectors[i]);
  130. str = str.Left(cchOverrideSrvCommandLine);
  131. if (str.CompareNoCase(szOverrideSrvCommandLine) == 0)
  132. {
  133. g_strOverrideServerName = lpServiceArgVectors[i] + cchOverrideSrvCommandLine;
  134. break;
  135. }
  136. } // for
  137. LocalFree(lpServiceArgVectors);
  138. TRACE(L"GetServerNameFromCommandLine() returning <%s>\n", (LPCWSTR)g_strOverrideServerName);
  139. return g_strOverrideServerName.IsEmpty() ? NULL : (LPCWSTR)g_strOverrideServerName;
  140. }
  141. /////////////////////////////////////////////////////////////////////////////
  142. // CInternalFormatCracker
  143. BOOL CInternalFormatCracker::Extract(LPDATAOBJECT lpDataObject)
  144. {
  145. if (m_pInternalFormat != NULL)
  146. {
  147. FREE_INTERNAL(m_pInternalFormat);
  148. m_pInternalFormat = NULL;
  149. }
  150. if (lpDataObject == NULL)
  151. return FALSE;
  152. STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
  153. FORMATETC formatetc = { (CLIPFORMAT)CDataObject::m_cfInternal, NULL,
  154. DVASPECT_CONTENT, -1, TYMED_HGLOBAL
  155. };
  156. // Allocate memory for the stream
  157. stgmedium.hGlobal = ::GlobalAlloc(GMEM_SHARE, sizeof(INTERNAL));
  158. // Attempt to get data from the object
  159. do
  160. {
  161. if (stgmedium.hGlobal == NULL)
  162. break;
  163. if (FAILED(lpDataObject->GetDataHere(&formatetc, &stgmedium)))
  164. break;
  165. m_pInternalFormat = reinterpret_cast<INTERNAL*>(stgmedium.hGlobal);
  166. if (m_pInternalFormat == NULL)
  167. return FALSE;
  168. } while (FALSE);
  169. return TRUE;
  170. }
  171. BOOL CInternalFormatCracker::GetContext(LPDATAOBJECT pDataObject, // input
  172. CFolderObject** ppFolderObject, // output
  173. DATA_OBJECT_TYPES* pType // output
  174. )
  175. {
  176. *ppFolderObject = NULL;
  177. *pType = CCT_UNINITIALIZED;
  178. BOOL bRet = FALSE;
  179. if (!Extract(pDataObject))
  180. return bRet;
  181. // have to figure out which kind of cookie we have
  182. if ( (GetInternal()->m_type == CCT_RESULT) || (GetInternal()->m_type == CCT_SCOPE) )
  183. {
  184. if (GetInternal()->m_cookie == 0)
  185. {
  186. // this is the root
  187. *ppFolderObject = m_pCD->GetRootFolder();
  188. bRet = TRUE;
  189. }
  190. else
  191. {
  192. // regular cookie (scope or result pane)
  193. *ppFolderObject = reinterpret_cast<CFolderObject*>(GetInternal()->m_cookie);
  194. _ASSERTE(*ppFolderObject != NULL);
  195. *pType = GetInternal()->m_type;
  196. bRet = TRUE;
  197. }
  198. }
  199. else if (GetInternal()->m_type == CCT_UNINITIALIZED)
  200. {
  201. // no data in the object, just ignore
  202. if(GetInternal()->m_cookie == -1)
  203. {
  204. bRet = TRUE;
  205. }
  206. else
  207. {
  208. // secondary page cookie
  209. *ppFolderObject = reinterpret_cast<CFolderObject*>(GetInternal()->m_cookie);
  210. bRet = TRUE;
  211. }
  212. }
  213. else //CCT_SNAPIN_MANAGER
  214. {
  215. ASSERT(GetInternal()->m_type == CCT_SNAPIN_MANAGER);
  216. bRet = TRUE;
  217. *pType = GetInternal()->m_type;
  218. }
  219. return bRet;
  220. }
  221. ///////////////////////////////////////////////////////////////////////////////
  222. ////////////////////////// CComponentDataImpl (i.e. scope pane side) //////////
  223. ///////////////////////////////////////////////////////////////////////////////
  224. ///////////////////////////////////////////////////////////////////////////////
  225. // IComponentData implementation
  226. DEBUG_DECLARE_INSTANCE_COUNTER(CComponentDataImpl);
  227. CComponentDataImpl::CComponentDataImpl() : m_rootFolder(this)
  228. {
  229. DEBUG_INCREMENT_INSTANCE_COUNTER(CComponentDataImpl);
  230. m_bInitSuccess = FALSE;
  231. m_hDomainIcon = NULL;
  232. m_pConsoleNameSpace = NULL;
  233. m_pConsole = NULL;
  234. /* HACK WARNING: this is a gross hack to get around a blunder
  235. in dsuiext.dll. in order to see get DS extension information,
  236. we MUST have USERDNSDOMAIN set in the environment
  237. */
  238. {
  239. WCHAR * pszUDD = NULL;
  240. pszUDD = _wgetenv (L"USERDNSDOMAIN");
  241. if (pszUDD == NULL) {
  242. _wputenv (L"USERDNSDOMAIN=not-present");
  243. }
  244. }
  245. }
  246. HRESULT CComponentDataImpl::FinalConstruct()
  247. {
  248. // create and initialize hidden window
  249. m_pHiddenWnd = new CHiddenWnd(this);
  250. ASSERT(m_pHiddenWnd);
  251. if (!m_pHiddenWnd->Create())
  252. {
  253. TRACE(_T("Failed to create hidden window\n"));
  254. ASSERT(FALSE);
  255. }
  256. return S_OK;
  257. }
  258. CComponentDataImpl::~CComponentDataImpl()
  259. {
  260. DEBUG_DECREMENT_INSTANCE_COUNTER(CComponentDataImpl);
  261. ASSERT(m_pConsoleNameSpace == NULL);
  262. }
  263. void CComponentDataImpl::FinalRelease()
  264. {
  265. _DeleteHiddenWnd();
  266. }
  267. STDMETHODIMP CComponentDataImpl::Initialize(LPUNKNOWN pUnknown)
  268. {
  269. ASSERT(pUnknown != NULL);
  270. HRESULT hr;
  271. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  272. // MMC should only call ::Initialize once!
  273. ASSERT(m_pConsoleNameSpace == NULL);
  274. pUnknown->QueryInterface(IID_IConsoleNameSpace,
  275. reinterpret_cast<void**>(&m_pConsoleNameSpace));
  276. // add the images for the scope tree
  277. CBitmap bmp16x16;
  278. LPIMAGELIST lpScopeImage;
  279. hr = pUnknown->QueryInterface(IID_IConsole, reinterpret_cast<void**>(&m_pConsole));
  280. ASSERT(hr == S_OK);
  281. if (FAILED(hr))
  282. {
  283. return hr;
  284. }
  285. hr = m_pConsole->QueryScopeImageList(&lpScopeImage);
  286. ASSERT(hr == S_OK);
  287. if (FAILED(hr))
  288. {
  289. return hr;
  290. }
  291. // Load the bitmaps from the dll
  292. bmp16x16.LoadBitmap(IDB_DOMAIN_SMALL);
  293. // Set the images
  294. lpScopeImage->ImageListSetStrip(reinterpret_cast<LONG_PTR*>(static_cast<HBITMAP>(bmp16x16)),
  295. reinterpret_cast<LONG_PTR*>(static_cast<HBITMAP>(bmp16x16)),
  296. 0, RGB(128, 0, 0));
  297. lpScopeImage->Release();
  298. // bind to the path info
  299. hr = GetBasePathsInfo()->InitFromName(GetServerNameFromCommandLine());
  300. m_bInitSuccess = SUCCEEDED(hr);
  301. if (FAILED(hr))
  302. {
  303. HWND hWndParent;
  304. GetMainWindow(&hWndParent);
  305. ReportError(hWndParent, IDS_CANT_GET_PARTITIONS_INFORMATION, hr);
  306. // TODO: error handling, change icon
  307. }
  308. return S_OK;
  309. }
  310. HWND CComponentDataImpl::GetHiddenWindow()
  311. {
  312. ASSERT(m_pHiddenWnd != NULL);
  313. ASSERT(::IsWindow(m_pHiddenWnd->m_hWnd));
  314. return m_pHiddenWnd->m_hWnd;
  315. }
  316. void CComponentDataImpl::_DeleteHiddenWnd()
  317. {
  318. if (m_pHiddenWnd == NULL)
  319. return;
  320. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  321. if (m_pHiddenWnd->m_hWnd != NULL)
  322. {
  323. VERIFY(m_pHiddenWnd->DestroyWindow());
  324. }
  325. delete m_pHiddenWnd;
  326. m_pHiddenWnd = NULL;
  327. }
  328. STDMETHODIMP CComponentDataImpl::CreateComponent(LPCOMPONENT* ppComponent)
  329. {
  330. ASSERT(ppComponent != NULL);
  331. CComObject<CComponentImpl>* pObject;
  332. HRESULT hr = CComObject<CComponentImpl>::CreateInstance(&pObject);
  333. if (FAILED(hr))
  334. {
  335. ASSERT(FALSE && "CComObject<CComponentImpl>::CreateInstance(&pObject) failed");
  336. return hr;
  337. }
  338. ASSERT(pObject != NULL);
  339. // Store IComponentData
  340. pObject->SetIComponentData(this);
  341. return pObject->QueryInterface(IID_IComponent,
  342. reinterpret_cast<void**>(ppComponent));
  343. }
  344. STDMETHODIMP CComponentDataImpl::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
  345. {
  346. ASSERT(m_pConsoleNameSpace != NULL);
  347. HRESULT hr = S_OK;
  348. // Since it's my folder it has an internal format.
  349. // Design Note: for extension. I can use the fact, that the data object doesn't have
  350. // my internal format and I should look at the node type and see how to extend it.
  351. if (event == MMCN_PROPERTY_CHANGE)
  352. {
  353. hr = OnPropertyChange(param);
  354. }
  355. else
  356. {
  357. if (lpDataObject == NULL)
  358. return S_OK;
  359. CFolderObject* pFolderObject = NULL;
  360. DATA_OBJECT_TYPES type;
  361. CInternalFormatCracker dobjCracker(this);
  362. if (!dobjCracker.GetContext(lpDataObject, &pFolderObject, &type))
  363. {
  364. // Extensions not supported.
  365. ASSERT(FALSE);
  366. return S_OK;
  367. }
  368. switch(event)
  369. {
  370. case MMCN_EXPAND:
  371. hr = OnExpand(pFolderObject, arg, param);
  372. break;
  373. case MMCN_REFRESH:
  374. OnRefreshVerbHandler(pFolderObject, NULL);
  375. break;
  376. default:
  377. break;
  378. }
  379. }
  380. return hr;
  381. }
  382. STDMETHODIMP CComponentDataImpl::Destroy()
  383. {
  384. SAFE_RELEASE(m_pConsoleNameSpace);
  385. SAFE_RELEASE(m_pConsole);
  386. return S_OK;
  387. }
  388. STDMETHODIMP CComponentDataImpl::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject)
  389. {
  390. ASSERT(ppDataObject != NULL);
  391. if (ppDataObject == NULL)
  392. return E_INVALIDARG;
  393. // create data object
  394. CComObject<CDataObject>* pObject = NULL;
  395. CComObject<CDataObject>::CreateInstance(&pObject);
  396. ASSERT(pObject != NULL);
  397. if ( !pObject )
  398. return E_OUTOFMEMORY;
  399. // Save cookie and type for delayed rendering
  400. pObject->SetType(type);
  401. pObject->SetCookie(cookie);
  402. // set pointer to IComponentData
  403. pObject->SetIComponentData(this);
  404. if (cookie != NULL)
  405. {
  406. // object is not the root
  407. CDomainObject * pDomain = (CDomainObject *)cookie;
  408. pObject->SetClass( pDomain->GetClass());
  409. }
  410. return pObject->QueryInterface(IID_IDataObject,
  411. reinterpret_cast<void**>(ppDataObject));
  412. }
  413. ///////////////////////////////////////////////////////////////////////////////
  414. //// Notify handlers for IComponentData
  415. HRESULT CComponentDataImpl::OnExpand(CFolderObject* pFolderObject, LPARAM arg, LPARAM param)
  416. {
  417. if (arg == TRUE)
  418. {
  419. // Did Initialize get called?
  420. ASSERT(m_pConsoleNameSpace != NULL);
  421. EnumerateScopePane(pFolderObject,
  422. param);
  423. }
  424. return S_OK;
  425. }
  426. HRESULT CComponentDataImpl::OnPropertyChange(LPARAM param)
  427. {
  428. return S_OK;
  429. }
  430. void CComponentDataImpl::EnumerateScopePane(CFolderObject* pFolderObject, HSCOPEITEM pParent)
  431. {
  432. ASSERT(m_pConsoleNameSpace != NULL); // make sure we QI'ed for the interface
  433. HRESULT hr = S_OK;
  434. HWND hWndParent;
  435. GetMainWindow(&hWndParent);
  436. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  437. CWaitCursor cWait;
  438. CRootFolderObject* pRootFolder = GetRootFolder();
  439. if (pFolderObject == pRootFolder) // asked to enumerate the root
  440. {
  441. pRootFolder->SetScopeID(pParent);
  442. if (m_bInitSuccess && (!pRootFolder->HasData()))
  443. {
  444. hr = GetDsDisplaySpecOptionsCFHolder()->Init(GetBasePathsInfo());
  445. ASSERT(SUCCEEDED(hr));
  446. hr = pRootFolder->Bind();
  447. if (FAILED(hr))
  448. {
  449. ReportError(hWndParent, IDS_CANT_GET_PARTITIONS_INFORMATION, hr);
  450. // TODO: error handling, change icon
  451. return;
  452. }
  453. hr = pRootFolder->GetData();
  454. if (FAILED(hr))
  455. {
  456. ReportError(hWndParent, IDS_CANT_GET_PARTITIONS_INFORMATION, hr);
  457. return;
  458. }
  459. }
  460. pRootFolder->EnumerateRootFolder(this);
  461. }
  462. else // asked to enumerate a subfolder of the root
  463. {
  464. if (pRootFolder->HasData())
  465. {
  466. pRootFolder->EnumerateFolder(pFolderObject, pParent, this);
  467. }
  468. }
  469. }
  470. STDMETHODIMP CComponentDataImpl::GetDisplayInfo(SCOPEDATAITEM* pScopeDataItem)
  471. {
  472. ASSERT(pScopeDataItem != NULL);
  473. if (pScopeDataItem == NULL)
  474. return E_POINTER;
  475. CDomainObject* pDomain = reinterpret_cast<CDomainObject*>(pScopeDataItem->lParam);
  476. ASSERT(pScopeDataItem->mask & SDI_STR);
  477. pScopeDataItem->displayname = (LPWSTR)pDomain->GetDisplayString(0);
  478. ASSERT(pScopeDataItem->displayname != NULL);
  479. return S_OK;
  480. }
  481. class CCompareDomainObjectByDN
  482. {
  483. public:
  484. CCompareDomainObjectByDN(LPCWSTR lpszDN) { m_lpszDN = lpszDN;}
  485. bool operator()(CDomainObject* p)
  486. {
  487. // NOTICE-2002/03/07-ericb - SecurityPush: checking both strings for null before dereferencing.
  488. if (!m_lpszDN || !p || !p->GetNCName())
  489. {
  490. ASSERT(m_lpszDN);
  491. ASSERT(p);
  492. ASSERT(p->GetNCName());
  493. return false;
  494. }
  495. return (_wcsicmp(m_lpszDN, p->GetNCName()) == 0);
  496. }
  497. private:
  498. LPCWSTR m_lpszDN;
  499. };
  500. STDMETHODIMP CComponentDataImpl::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB)
  501. {
  502. if (lpDataObjectA == NULL || lpDataObjectB == NULL)
  503. return E_POINTER;
  504. CFolderObject *pFolderObjectA, *pFolderObjectB;
  505. DATA_OBJECT_TYPES typeA, typeB;
  506. CInternalFormatCracker dobjCrackerA(this), dobjCrackerB(this);
  507. if ( (!dobjCrackerA.GetContext(lpDataObjectA, &pFolderObjectA, &typeA)) ||
  508. (!dobjCrackerB.GetContext(lpDataObjectB, &pFolderObjectB, &typeB)) )
  509. return E_INVALIDARG; // something went wrong
  510. // must have valid cookies
  511. if ( (pFolderObjectA == NULL) || (pFolderObjectB == NULL) )
  512. {
  513. return S_FALSE;
  514. }
  515. if (pFolderObjectA == pFolderObjectB)
  516. {
  517. // same pointer, they are the same (either both from real nodes
  518. // or both from secondary pages)
  519. return S_OK;
  520. }
  521. // the two cookies are different, but one of them might be from a secondary property page
  522. // and another from a real node
  523. CDomainObject* pA = dynamic_cast<CDomainObject*>(pFolderObjectA);
  524. CDomainObject* pB = dynamic_cast<CDomainObject*>(pFolderObjectB);
  525. if ((pA == NULL) || (pB == NULL))
  526. {
  527. return S_FALSE;
  528. }
  529. BOOL bSecondaryA = m_secondaryPagesManager.IsCookiePresent(pA);
  530. BOOL bSecondaryB = m_secondaryPagesManager.IsCookiePresent(pB);
  531. BOOL bTheSame = FALSE;
  532. if (bSecondaryA && !bSecondaryB)
  533. {
  534. bTheSame = m_secondaryPagesManager.FindCookie(CCompareDomainObjectByDN(pB->GetNCName())) != NULL;
  535. }
  536. else if (!bSecondaryA && bSecondaryB)
  537. {
  538. bTheSame = m_secondaryPagesManager.FindCookie(CCompareDomainObjectByDN(pA->GetNCName())) != NULL;
  539. }
  540. return bTheSame ? S_OK : S_FALSE;
  541. }
  542. HRESULT CComponentDataImpl::AddFolder(CFolderObject* pFolderObject,
  543. HSCOPEITEM pParentScopeItem,
  544. BOOL bHasChildren)
  545. {
  546. TRACE(L"CComponentDataImpl::AddFolder(%s)\n", pFolderObject->GetDisplayString(0));
  547. SCOPEDATAITEM scopeItem;
  548. // NOTICE-2002/03/07-ericb - SecurityPush: zeroing a struct.
  549. memset(&scopeItem, 0, sizeof(SCOPEDATAITEM));
  550. // set parent scope item
  551. scopeItem.mask |= SDI_PARENT;
  552. scopeItem.relativeID = pParentScopeItem;
  553. // Add node name, we implement callback
  554. scopeItem.mask |= SDI_STR;
  555. scopeItem.displayname = MMC_CALLBACK;
  556. // Add the lParam
  557. scopeItem.mask |= SDI_PARAM;
  558. scopeItem.lParam = reinterpret_cast<LPARAM>(pFolderObject);
  559. // Add close image
  560. scopeItem.mask |= SDI_IMAGE;
  561. scopeItem.nImage = pFolderObject->GetImageIndex();
  562. // Add open image
  563. scopeItem.mask |= SDI_OPENIMAGE;
  564. scopeItem.nOpenImage = pFolderObject->GetImageIndex();
  565. // Add button to node if the folder has children
  566. if (bHasChildren == TRUE)
  567. {
  568. scopeItem.mask |= SDI_CHILDREN;
  569. scopeItem.cChildren = 1;
  570. }
  571. pFolderObject->SetScopeID(0);
  572. HRESULT hr = m_pConsoleNameSpace->InsertItem(&scopeItem);
  573. if (SUCCEEDED(hr))
  574. pFolderObject->SetScopeID(scopeItem.ID);
  575. return hr;
  576. }
  577. HRESULT CComponentDataImpl::AddDomainIcon()
  578. {
  579. if (m_hDomainIcon != NULL)
  580. return S_OK;
  581. m_hDomainIcon = GetBasePathsInfo()->GetIcon(L"domainDNS",
  582. DSGIF_ISNORMAL | DSGIF_GETDEFAULTICON,
  583. 0, 0);
  584. if (m_hDomainIcon == NULL)
  585. return S_OK;
  586. LPIMAGELIST lpScopeImage;
  587. HRESULT hr = m_pConsole->QueryScopeImageList(&lpScopeImage);
  588. ASSERT(SUCCEEDED(hr));
  589. if (FAILED(hr))
  590. return hr;
  591. // Set the images
  592. hr = lpScopeImage->ImageListSetIcon((LONG_PTR*)m_hDomainIcon,DOMAIN_IMAGE_IDX);
  593. lpScopeImage->Release();
  594. return hr;
  595. }
  596. HRESULT CComponentDataImpl::AddDomainIconToResultPane(LPIMAGELIST lpImageList)
  597. {
  598. if (m_hDomainIcon == NULL)
  599. return S_OK;
  600. return lpImageList->ImageListSetIcon((LONG_PTR*)m_hDomainIcon,DOMAIN_IMAGE_IDX);
  601. }
  602. int CComponentDataImpl::GetDomainImageIndex()
  603. {
  604. return (m_hDomainIcon != NULL) ? DOMAIN_IMAGE_IDX : DOMAIN_IMAGE_DEFAULT_IDX;
  605. }
  606. /////////////////////////////////////////////////////////////////////////////
  607. // IExtendPropertySheet Implementation
  608. //+----------------------------------------------------------------------------
  609. //
  610. // Function: AddPageProc
  611. //
  612. // Synopsis: The IShellPropSheetExt->AddPages callback.
  613. //
  614. //-----------------------------------------------------------------------------
  615. BOOL CALLBACK
  616. AddPageProc(HPROPSHEETPAGE hPage, LPARAM pCall)
  617. {
  618. TRACE(_T("xx.%03x> AddPageProc()\n"), GetCurrentThreadId());
  619. HRESULT hr;
  620. hr = ((LPPROPERTYSHEETCALLBACK)pCall)->AddPage(hPage);
  621. return hr == S_OK;
  622. }
  623. STDMETHODIMP CComponentDataImpl::CreatePropertyPages(LPPROPERTYSHEETCALLBACK lpProvider,
  624. LONG_PTR handle,
  625. LPDATAOBJECT lpIDataObject)
  626. {
  627. TRACE(_T("xx.%03x> CComponentDataImpl::CreatePropertyPages()\n"),
  628. GetCurrentThreadId());
  629. // Validate Inputs
  630. if (lpProvider == NULL)
  631. {
  632. return E_INVALIDARG;
  633. }
  634. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  635. HRESULT hr = S_OK;
  636. CWaitCursor wait;
  637. CFolderObject* pFolderObject = NULL;
  638. DATA_OBJECT_TYPES type;
  639. CInternalFormatCracker dobjCracker(this);
  640. if ( (!dobjCracker.GetContext(lpIDataObject, &pFolderObject, &type)) ||
  641. (pFolderObject == NULL))
  642. return E_NOTIMPL; // unknown format
  643. // special case the root
  644. if (pFolderObject == GetRootFolder())
  645. {
  646. return GetRootFolder()->OnAddPages(lpProvider, handle);
  647. }
  648. // See if a sheet is already up for this object.
  649. //
  650. if (IsSheetAlreadyUp(lpIDataObject))
  651. {
  652. return S_OK;
  653. }
  654. if (pFolderObject->GetParentFolder() == GetRootFolder())
  655. {
  656. TRACE(L"\t!!!!! This is the root domain\n");
  657. }
  658. // See if a PDC is available.
  659. //
  660. CDomainObject * pDomainObject = (CDomainObject *)pFolderObject;
  661. PCWSTR wzDomain = pDomainObject->GetDomainName();
  662. // If the domain name is null, then launching a secondary page. The domain
  663. // object properties have already been set in _OnSheetCreate.
  664. //
  665. if (wzDomain && *wzDomain)
  666. {
  667. TRACE(L"Calling DsGetDcName on %s\n", wzDomain);
  668. CString strCachedPDC;
  669. PDOMAIN_CONTROLLER_INFOW pDCInfo = NULL;
  670. // Get the cached PDC name for display later if the PDC can't be contacted.
  671. //
  672. DWORD dwRet = DsGetDcNameW(NULL, wzDomain, NULL, NULL, DS_PDC_REQUIRED, &pDCInfo);
  673. int nID = IDS_NO_PDC_MSG;
  674. if (ERROR_SUCCESS == dwRet)
  675. {
  676. strCachedPDC = pDCInfo->DomainControllerName + 2;
  677. NetApiBufferFree(pDCInfo);
  678. }
  679. // Now do a NetLogon cache update (with the force flag) to see if the PDC
  680. // is actually available.
  681. //
  682. dwRet = DsGetDcNameW(NULL, wzDomain, NULL, NULL,
  683. DS_PDC_REQUIRED | DS_FORCE_REDISCOVERY, &pDCInfo);
  684. if (ERROR_SUCCESS == dwRet)
  685. {
  686. CString strPDC;
  687. strPDC = pDCInfo->DomainControllerName + 2; // skip the UNC backslashes.
  688. NetApiBufferFree(pDCInfo);
  689. TRACE(L"PDC: %s\n", (PCWSTR)strPDC);
  690. if (strPDC.IsEmpty())
  691. {
  692. return E_OUTOFMEMORY;
  693. }
  694. pDomainObject->SetPDC(strPDC);
  695. pDomainObject->SetPdcAvailable(true);
  696. }
  697. else
  698. {
  699. pDomainObject->SetPdcAvailable(false);
  700. CString strMsg;
  701. if (strCachedPDC.IsEmpty())
  702. {
  703. strMsg.LoadString(IDS_UNKNOWN_PDC_MSG);
  704. }
  705. else
  706. {
  707. strMsg.Format(IDS_NO_PDC_MSG, strCachedPDC);
  708. }
  709. HWND hWndParent;
  710. GetMainWindow(&hWndParent);
  711. _MessageBox(hWndParent, strMsg, MB_OK | MB_ICONEXCLAMATION);
  712. }
  713. }
  714. //
  715. // Pass the Notify Handle to the data object.
  716. //
  717. PROPSHEETCFG SheetCfg = {handle};
  718. FORMATETC fe = {CDataObject::m_cfGetIPropSheetCfg, NULL, DVASPECT_CONTENT,
  719. -1, TYMED_HGLOBAL};
  720. STGMEDIUM sm = {TYMED_HGLOBAL, NULL, NULL};
  721. sm.hGlobal = (HGLOBAL)&SheetCfg;
  722. lpIDataObject->SetData(&fe, &sm, FALSE);
  723. //
  724. // Initialize and create the pages.
  725. //
  726. // Bind to the property sheet COM object at startup and hold its pointer
  727. // until shutdown so that its cache can live as long as us.
  728. //
  729. CComPtr<IShellExtInit> spShlInit;
  730. hr = CoCreateInstance(CLSID_DsPropertyPages, NULL, CLSCTX_INPROC_SERVER,
  731. IID_IShellExtInit, (void **)&spShlInit);
  732. if (FAILED(hr))
  733. {
  734. TRACE(TEXT("CoCreateInstance on CLSID_DsPropertyPages failed, hr: 0x%x\n "), hr);
  735. return hr;
  736. }
  737. hr = spShlInit->Initialize(NULL, lpIDataObject, 0);
  738. if (FAILED(hr))
  739. {
  740. TRACE(TEXT("spShlInit->Initialize failed, hr: 0x%x\n"), hr);
  741. return hr;
  742. }
  743. CComPtr<IShellPropSheetExt> spSPSE;
  744. hr = spShlInit->QueryInterface(IID_IShellPropSheetExt, (void **)&spSPSE);
  745. if (FAILED(hr))
  746. {
  747. TRACE(TEXT("spShlInit->QI for IID_IShellPropSheetExt failed, hr: 0x%x\n"), hr);
  748. return hr;
  749. }
  750. hr = spSPSE->AddPages(AddPageProc, (LONG_PTR)lpProvider);
  751. if (FAILED(hr))
  752. {
  753. TRACE(TEXT("pSPSE->AddPages failed, hr: 0x%x\n"), hr);
  754. return hr;
  755. }
  756. _SheetLockCookie(pFolderObject);
  757. return hr;
  758. }
  759. // Sheet locking and unlocking add by JEFFJON 1/26/99
  760. //
  761. void CComponentDataImpl::_OnSheetClose(CFolderObject* pCookie)
  762. {
  763. ASSERT(pCookie != NULL);
  764. _SheetUnlockCookie(pCookie);
  765. CDomainObject* pDomObj = dynamic_cast<CDomainObject*>(pCookie);
  766. if (pDomObj != NULL)
  767. m_secondaryPagesManager.OnSheetClose(pDomObj);
  768. }
  769. void CComponentDataImpl::_OnSheetCreate(PDSA_SEC_PAGE_INFO pDsaSecondaryPageInfo,
  770. PWSTR pwzDC)
  771. {
  772. ASSERT(pDsaSecondaryPageInfo != NULL);
  773. // get the info from the packed structure
  774. HWND hwndParent = pDsaSecondaryPageInfo->hwndParentSheet;
  775. LPCWSTR lpszTitle = (LPCWSTR)((BYTE*)pDsaSecondaryPageInfo + pDsaSecondaryPageInfo->offsetTitle);
  776. DSOBJECTNAMES* pDsObjectNames = &(pDsaSecondaryPageInfo->dsObjectNames);
  777. ASSERT(pDsObjectNames->cItems == 1);
  778. DSOBJECT* pDsObject = &(pDsObjectNames->aObjects[0]);
  779. LPCWSTR lpszName = (LPCWSTR)((BYTE*)pDsObject + pDsObject->offsetName);
  780. LPCWSTR lpszClass = (LPCWSTR)((BYTE*)pDsObject + pDsObject->offsetClass);
  781. // with the given info, create a cookie and set it
  782. CDomainObject* pNewCookie = new CDomainObject();
  783. pNewCookie->InitializeForSecondaryPage(lpszName, lpszClass, GetDomainImageIndex());
  784. // The parent sheet will be in read-only mode if a PDC is not available.
  785. pNewCookie->SetPdcAvailable(!(pDsObject->dwFlags & DSOBJECT_READONLYPAGES));
  786. if (pwzDC && !IsBadReadPtr(pwzDC, sizeof(PWSTR)))
  787. {
  788. pNewCookie->SetPDC(pwzDC);
  789. }
  790. // with the cookie, can call into ourselves to get a data object
  791. CComPtr<IDataObject> spDataObject;
  792. MMC_COOKIE cookie = reinterpret_cast<MMC_COOKIE>(pNewCookie);
  793. HRESULT hr = QueryDataObject(cookie, CCT_UNINITIALIZED, &spDataObject);
  794. if (FAILED(hr) || (spDataObject == NULL) || IsSheetAlreadyUp(spDataObject))
  795. {
  796. // we failed to create a data object (rare)
  797. // or the sheet is already up
  798. delete pNewCookie;
  799. return;
  800. }
  801. //
  802. // Pass the parent sheet handle to the data object.
  803. //
  804. PROPSHEETCFG SheetCfg = {0};
  805. SheetCfg.hwndParentSheet = hwndParent;
  806. FORMATETC fe = {CDataObject::m_cfGetIPropSheetCfg, NULL, DVASPECT_CONTENT,
  807. -1, TYMED_HGLOBAL};
  808. STGMEDIUM sm = {TYMED_HGLOBAL, NULL, NULL};
  809. sm.hGlobal = (HGLOBAL)&SheetCfg;
  810. hr = spDataObject->SetData(&fe, &sm, FALSE);
  811. ASSERT(SUCCEEDED(hr));
  812. // with the data object, call into MMC to get the sheet
  813. hr = m_secondaryPagesManager.CreateSheet(GetHiddenWindow(),
  814. m_pConsole,
  815. GetUnknown(),
  816. pNewCookie,
  817. spDataObject,
  818. lpszTitle);
  819. // if failed, the cookie can be discarded,
  820. // if succeeded, the cookie has been inserted into
  821. // the secondary pages manager cookie list
  822. if (FAILED(hr))
  823. {
  824. delete pNewCookie;
  825. }
  826. }
  827. void CComponentDataImpl::_SheetLockCookie(CFolderObject* pCookie)
  828. {
  829. pCookie->IncrementSheetLockCount();
  830. m_sheetCookieTable.Add(pCookie);
  831. }
  832. void CComponentDataImpl::_SheetUnlockCookie(CFolderObject* pCookie)
  833. {
  834. pCookie->DecrementSheetLockCount();
  835. m_sheetCookieTable.Remove(pCookie);
  836. }
  837. STDMETHODIMP CComponentDataImpl::QueryPagesFor(LPDATAOBJECT lpDataObject)
  838. {
  839. CFolderObject* pFolderObject;
  840. DATA_OBJECT_TYPES type;
  841. CInternalFormatCracker dobjCracker(this);
  842. if (!dobjCracker.GetContext(lpDataObject, &pFolderObject, &type))
  843. {
  844. // not internal format, not ours
  845. return S_FALSE;
  846. }
  847. // this is the MMC snzpin wizard, we do not have one
  848. if (type == CCT_SNAPIN_MANAGER)
  849. {
  850. return S_FALSE;
  851. }
  852. // if NULL no pages
  853. if (pFolderObject == NULL)
  854. {
  855. return S_FALSE;
  856. }
  857. // secondary pages data objects have to be checked first,
  858. // because they look like the root (no parents, but they
  859. // have CCT_UNINITIALIZED
  860. if ( (pFolderObject->GetParentFolder() == NULL) || (type == CCT_UNINITIALIZED) )
  861. {
  862. return S_OK;
  863. }
  864. // check if this is the root
  865. if (GetRootFolder() == pFolderObject)
  866. {
  867. // this is the root
  868. ASSERT(type == CCT_SCOPE);
  869. return S_OK;
  870. }
  871. // default case, have DSPROP property pages
  872. return S_OK;
  873. }
  874. BOOL CComponentDataImpl::IsScopePaneNode(LPDATAOBJECT lpDataObject)
  875. {
  876. CFolderObject* pFolderObject;
  877. DATA_OBJECT_TYPES type;
  878. CInternalFormatCracker dobjCracker(this);
  879. if (!dobjCracker.GetContext(lpDataObject, &pFolderObject, &type))
  880. return FALSE;
  881. return (dobjCracker.GetInternal()->m_type == CCT_SCOPE);
  882. }
  883. ///////////////////////////////////////////////////////////////////////////////
  884. // IExtendContextMenu implementation
  885. //
  886. STDMETHODIMP CComponentDataImpl::AddMenuItems(LPDATAOBJECT pDataObject,
  887. LPCONTEXTMENUCALLBACK pContextMenuCallback,
  888. long *pInsertionAllowed)
  889. {
  890. HRESULT hr = S_OK;
  891. CFolderObject* pFolderObject;
  892. DATA_OBJECT_TYPES type;
  893. CInternalFormatCracker dobjCracker(this);
  894. if (!dobjCracker.GetContext(pDataObject, &pFolderObject, &type))
  895. return E_FAIL;
  896. return pFolderObject->OnAddMenuItems(pContextMenuCallback, pInsertionAllowed);
  897. }
  898. STDMETHODIMP CComponentDataImpl::Command(long nCommandID, LPDATAOBJECT pDataObject)
  899. {
  900. // Note - snap-ins need to look at the data object and determine
  901. // in what context the command is being called.
  902. CFolderObject* pFolderObject;
  903. DATA_OBJECT_TYPES type;
  904. CInternalFormatCracker dobjCracker(this);
  905. if (!dobjCracker.GetContext(pDataObject, &pFolderObject, &type))
  906. return E_FAIL;
  907. return pFolderObject->OnCommand(this, nCommandID);
  908. }
  909. /////////////////////////////////////////////////////////////////////////////
  910. // CComponentDataImpl::ISnapinHelp2 members
  911. STDMETHODIMP CComponentDataImpl::GetHelpTopic(LPOLESTR* lpCompiledHelpFile)
  912. {
  913. if (lpCompiledHelpFile == NULL)
  914. {
  915. return E_INVALIDARG;
  916. }
  917. CString szHelpFilePath;
  918. LPTSTR lpszBuffer = szHelpFilePath.GetBuffer(2*MAX_PATH);
  919. UINT nLen = ::GetSystemWindowsDirectory(lpszBuffer, 2*MAX_PATH);
  920. if (nLen == 0)
  921. {
  922. return E_FAIL;
  923. }
  924. szHelpFilePath.ReleaseBuffer();
  925. szHelpFilePath += L"\\help\\";
  926. szHelpFilePath += DOMADMIN_SNAPIN_HELP_FILE;
  927. UINT nBytes = (szHelpFilePath.GetLength()+1) * sizeof(WCHAR);
  928. *lpCompiledHelpFile = (LPOLESTR)::CoTaskMemAlloc(nBytes);
  929. if (NULL == *lpCompiledHelpFile)
  930. {
  931. return E_OUTOFMEMORY;
  932. }
  933. // NOTICE-2002/03/07-ericb - SecurityPush: reviewed, usage is safe.
  934. memcpy(*lpCompiledHelpFile, (LPCWSTR)szHelpFilePath, nBytes);
  935. return S_OK;
  936. }
  937. // CODEWORK-2002/03/07-ericb - use a common helper for these two functions.
  938. STDMETHODIMP CComponentDataImpl::GetLinkedTopics(LPOLESTR* lpCompiledHelpFile)
  939. {
  940. if (lpCompiledHelpFile == NULL)
  941. {
  942. return E_INVALIDARG;
  943. }
  944. CString szHelpFilePath;
  945. LPTSTR lpszBuffer = szHelpFilePath.GetBuffer(2*MAX_PATH);
  946. UINT nLen = ::GetSystemWindowsDirectory(lpszBuffer, 2*MAX_PATH);
  947. if (nLen == 0)
  948. {
  949. return E_FAIL;
  950. }
  951. szHelpFilePath.ReleaseBuffer();
  952. szHelpFilePath += L"\\help\\";
  953. szHelpFilePath += DOMADMIN_LINKED_HELP_FILE;
  954. UINT nBytes = (szHelpFilePath.GetLength()+1) * sizeof(WCHAR);
  955. *lpCompiledHelpFile = (LPOLESTR)::CoTaskMemAlloc(nBytes);
  956. if (NULL == *lpCompiledHelpFile)
  957. {
  958. return E_OUTOFMEMORY;
  959. }
  960. // NOTICE-2002/03/07-ericb - SecurityPush: reviewed, usage is safe.
  961. memcpy(*lpCompiledHelpFile, (LPCWSTR)szHelpFilePath, nBytes);
  962. return S_OK;
  963. }
  964. /////////////////////////////////////////////////////////////////////
  965. void CComponentDataImpl::HandleStandardVerbsHelper(CComponentImpl* pComponentImpl,
  966. LPCONSOLEVERB pConsoleVerb,
  967. BOOL bScope, BOOL bSelect,
  968. CFolderObject* pFolderObject,
  969. DATA_OBJECT_TYPES type)
  970. {
  971. // You should crack the data object and enable/disable/hide standard
  972. // commands appropriately. The standard commands are reset everytime you get
  973. // called. So you must reset them back.
  974. ASSERT(pConsoleVerb != NULL);
  975. ASSERT(pComponentImpl != NULL);
  976. ASSERT(pFolderObject != NULL);
  977. // reset the selection
  978. pComponentImpl->SetSelection(NULL, CCT_UNINITIALIZED);
  979. if (bSelect)
  980. {
  981. // special case the root
  982. BOOL bIsRoot = (pFolderObject == GetRootFolder());
  983. // setting the selection, if any
  984. pComponentImpl->SetSelection(pFolderObject, type);
  985. // the default just disables all the non implemented verbs
  986. pConsoleVerb->SetVerbState(MMC_VERB_COPY, HIDDEN, TRUE);
  987. pConsoleVerb->SetVerbState(MMC_VERB_COPY, ENABLED, FALSE);
  988. pConsoleVerb->SetVerbState(MMC_VERB_PASTE, HIDDEN, TRUE);
  989. pConsoleVerb->SetVerbState(MMC_VERB_PASTE, ENABLED, FALSE);
  990. pConsoleVerb->SetVerbState(MMC_VERB_RENAME, HIDDEN, TRUE);
  991. pConsoleVerb->SetVerbState(MMC_VERB_RENAME, ENABLED, FALSE);
  992. pConsoleVerb->SetVerbState(MMC_VERB_PRINT, HIDDEN, TRUE);
  993. pConsoleVerb->SetVerbState(MMC_VERB_PRINT, ENABLED, FALSE);
  994. // handling of standard verbs
  995. // MMC_VERB_DELETE (always disabled)
  996. pConsoleVerb->SetVerbState(MMC_VERB_DELETE, ENABLED, FALSE);
  997. pConsoleVerb->SetVerbState(MMC_VERB_DELETE, HIDDEN, TRUE);
  998. // MMC_VERB_REFRESH (enabled only for root)
  999. if (bIsRoot)
  1000. {
  1001. pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, TRUE);
  1002. pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, FALSE);
  1003. }
  1004. else
  1005. {
  1006. pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, ENABLED, FALSE);
  1007. pConsoleVerb->SetVerbState(MMC_VERB_REFRESH, HIDDEN, TRUE);
  1008. }
  1009. // MMC_VERB_PROPERTIES
  1010. // passing NULL pFolderObject means multiple selection
  1011. BOOL bHasProperties = (pFolderObject != NULL);
  1012. BOOL bHideProperties = !bHasProperties;
  1013. pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, ENABLED, bHasProperties);
  1014. pConsoleVerb->SetVerbState(MMC_VERB_PROPERTIES, HIDDEN, bHideProperties);
  1015. // SET DEFAULT VERB
  1016. // assume only folders: only one default verb (i.e. will not have MMC_VERB_PROPERTIES)
  1017. pConsoleVerb->SetDefaultVerb(MMC_VERB_OPEN);
  1018. }
  1019. }
  1020. void CComponentDataImpl::OnRefreshVerbHandler(CFolderObject* pFolderObject,
  1021. CComponentImpl* pComponentImpl,
  1022. BOOL bBindAgain)
  1023. {
  1024. TRACE(L"CComponentDataImpl::OnRefreshVerbHandler(...,..., %d)\n", bBindAgain);
  1025. if (pFolderObject->_WarningOnSheetsUp(this))
  1026. return;
  1027. // make sure the DNS cache is flushed, in case a somain was added.
  1028. VERIFY(::DnsFlushResolverCache());
  1029. // NOTICE: only the root folder allows refresh
  1030. ASSERT(pFolderObject == GetRootFolder());
  1031. // remove all the children of the root from the UI
  1032. m_pConsoleNameSpace->DeleteItem(m_rootFolder.GetScopeID(), /*fDeleteThis*/ FALSE);
  1033. HRESULT hr = S_OK;
  1034. if (bBindAgain)
  1035. {
  1036. // the server name has changed
  1037. hr = m_rootFolder.Bind();
  1038. TRACE(L"m_rootFolder.Bind() returned hr = 0x%x\n", hr);
  1039. }
  1040. if (SUCCEEDED(hr))
  1041. {
  1042. // refresh the data from the server
  1043. hr = m_rootFolder.GetData();
  1044. TRACE(L"m_rootFolder.GetData() returned hr = 0x%x\n", hr);
  1045. }
  1046. if (FAILED(hr))
  1047. {
  1048. HWND hWndParent;
  1049. GetMainWindow(&hWndParent);
  1050. ReportError(hWndParent, IDS_CANT_GET_PARTITIONS_INFORMATION, hr);
  1051. }
  1052. if (FAILED(hr))
  1053. return;
  1054. // re-enumerate
  1055. m_rootFolder.EnumerateRootFolder(this);
  1056. }
  1057. //+---------------------------------------------------------------------------
  1058. //
  1059. // Function: LocaleStrCmp
  1060. //
  1061. // Synopsis: Do a case insensitive string compare that is safe for any
  1062. // locale.
  1063. //
  1064. // Arguments: [ptsz1] - strings to compare
  1065. // [ptsz2]
  1066. //
  1067. // Returns: -1, 0, or 1 just like lstrcmpi
  1068. //
  1069. // History: 10-28-96 DavidMun Created
  1070. //
  1071. // Notes: This is slower than lstrcmpi, but will work when sorting
  1072. // strings even in Japanese.
  1073. //
  1074. //----------------------------------------------------------------------------
  1075. int
  1076. LocaleStrCmp(LPCTSTR ptsz1, LPCTSTR ptsz2)
  1077. {
  1078. int iRet = 0;
  1079. iRet = CompareString(LOCALE_USER_DEFAULT,
  1080. NORM_IGNORECASE |
  1081. NORM_IGNOREKANATYPE |
  1082. NORM_IGNOREWIDTH,
  1083. ptsz1,
  1084. -1,
  1085. ptsz2,
  1086. -1);
  1087. if (iRet)
  1088. {
  1089. iRet -= 2; // convert to lstrcmpi-style return -1, 0, or 1
  1090. if ( 0 == iRet )
  1091. {
  1092. UNICODE_STRING unistr1;
  1093. unistr1.Length = (USHORT)(::lstrlen(ptsz1)*sizeof(WCHAR));
  1094. unistr1.MaximumLength = unistr1.Length;
  1095. unistr1.Buffer = (LPWSTR)ptsz1;
  1096. UNICODE_STRING unistr2;
  1097. unistr2.Length = (USHORT)(::lstrlen(ptsz2)*sizeof(WCHAR));
  1098. unistr2.MaximumLength = unistr2.Length;
  1099. unistr2.Buffer = (LPWSTR)ptsz2;
  1100. iRet = ::RtlCompareUnicodeString(
  1101. &unistr1,
  1102. &unistr2,
  1103. FALSE );
  1104. }
  1105. }
  1106. else
  1107. {
  1108. DWORD dwErr = GetLastError ();
  1109. if (dwErr != 0)
  1110. {
  1111. TRACE(L"CompareString (%s, %s) failed: 0x%x\n", ptsz1, ptsz2, dwErr);
  1112. }
  1113. }
  1114. return iRet;
  1115. }
  1116. ///////////////////////////////////////////////////////////////////////////////
  1117. ///////////////////// CComponentImpl (i.e. result pane side) //////////////////
  1118. ///////////////////////////////////////////////////////////////////////////////
  1119. STDMETHODIMP CComponentImpl::CompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB)
  1120. {
  1121. return S_FALSE;
  1122. }
  1123. //+---------------------------------------------------------------------------
  1124. //
  1125. // Function: CComponentImpl::IResultDataCompareEx::Compare
  1126. //
  1127. // Synopsis: This compare is used to sort the item's in the listview
  1128. //
  1129. // Note: Assume sort is ascending when comparing.
  1130. //
  1131. //----------------------------------------------------------------------------
  1132. STDMETHODIMP
  1133. CComponentImpl::Compare(RDCOMPARE* prdc, int* pnResult)
  1134. {
  1135. if (pnResult == NULL)
  1136. {
  1137. ASSERT(FALSE);
  1138. return E_POINTER;
  1139. }
  1140. if (prdc == NULL)
  1141. {
  1142. ASSERT(FALSE);
  1143. return E_POINTER;
  1144. }
  1145. *pnResult = 0;
  1146. LPCTSTR szStringA;
  1147. LPCTSTR szStringB;
  1148. CDomainObject* pDataA = reinterpret_cast<CDomainObject*>(prdc->prdch1->cookie);
  1149. CDomainObject* pDataB = reinterpret_cast<CDomainObject*>(prdc->prdch2->cookie);
  1150. ASSERT(pDataA != NULL && pDataB != NULL);
  1151. // Currently DomAdmin has just two columns, Name and Type. The value of
  1152. // the type column is always "DomainDNS", so there is nothing to compare
  1153. // for that column and the default *pnResult, set to zero above, is
  1154. // returned.
  1155. if (0 == prdc->nColumn)
  1156. {
  1157. szStringA = pDataA->GetDomainName();
  1158. szStringB = pDataB->GetDomainName();
  1159. ASSERT(szStringA != NULL);
  1160. ASSERT(szStringB != NULL);
  1161. *pnResult = LocaleStrCmp(szStringA, szStringB);
  1162. }
  1163. return S_OK;
  1164. }
  1165. void CComponentImpl::HandleStandardVerbs(BOOL bScope, BOOL bSelect,
  1166. CFolderObject* pFolderObject, DATA_OBJECT_TYPES type)
  1167. {
  1168. // delegate it to the IComponentData helper function
  1169. ASSERT(m_pCD != NULL);
  1170. m_pCD->HandleStandardVerbsHelper(
  1171. this, m_pConsoleVerb, bScope, bSelect, pFolderObject, type);
  1172. }
  1173. void CComponentImpl::Refresh(CFolderObject* pFolderObject)
  1174. {
  1175. ASSERT(m_pComponentData != NULL);
  1176. // delegate it to the IComponentData helper function
  1177. ((CComponentDataImpl*)m_pComponentData)->OnRefreshVerbHandler(pFolderObject, this);
  1178. }
  1179. // utility routines
  1180. ////////////////////////////////////////////////////////////////////
  1181. //
  1182. // Print the data depending on its type.
  1183. //
  1184. #ifdef DBG
  1185. void
  1186. PrintColumn(
  1187. PADS_SEARCH_COLUMN pColumn,
  1188. LPWSTR pszColumnName
  1189. )
  1190. {
  1191. ULONG i, j, k;
  1192. if (!pColumn) {
  1193. return;
  1194. }
  1195. TRACE(_T(
  1196. "%s = "),
  1197. pszColumnName
  1198. );
  1199. for (k=0; k < pColumn->dwNumValues; k++) {
  1200. if (k > 0)
  1201. TRACE(_T("# "));
  1202. switch(pColumn->dwADsType) {
  1203. case ADSTYPE_DN_STRING :
  1204. TRACE(_T(
  1205. "%s "),
  1206. (LPWSTR) pColumn->pADsValues[k].DNString
  1207. );
  1208. break;
  1209. case ADSTYPE_CASE_EXACT_STRING :
  1210. TRACE(_T(
  1211. "%s "),
  1212. (LPWSTR) pColumn->pADsValues[k].CaseExactString
  1213. );
  1214. break;
  1215. case ADSTYPE_CASE_IGNORE_STRING:
  1216. TRACE(_T(
  1217. "%s "),
  1218. (LPWSTR) pColumn->pADsValues[k].CaseIgnoreString
  1219. );
  1220. break;
  1221. case ADSTYPE_PRINTABLE_STRING :
  1222. TRACE(_T(
  1223. "%s "),
  1224. (LPWSTR) pColumn->pADsValues[k].PrintableString
  1225. );
  1226. break;
  1227. case ADSTYPE_NUMERIC_STRING :
  1228. TRACE(_T(
  1229. "%s "),
  1230. (LPWSTR) pColumn->pADsValues[k].NumericString
  1231. );
  1232. break;
  1233. case ADSTYPE_BOOLEAN :
  1234. TRACE(_T(
  1235. "%s "),
  1236. (DWORD) pColumn->pADsValues[k].Boolean ?
  1237. L"TRUE" : L"FALSE"
  1238. );
  1239. break;
  1240. case ADSTYPE_INTEGER :
  1241. TRACE(_T(
  1242. "%d "),
  1243. (DWORD) pColumn->pADsValues[k].Integer
  1244. );
  1245. break;
  1246. case ADSTYPE_OCTET_STRING :
  1247. for (j=0; j<pColumn->pADsValues[k].OctetString.dwLength; j++) {
  1248. TRACE(_T(
  1249. "%02x"),
  1250. ((BYTE *)pColumn->pADsValues[k].OctetString.lpValue)[j]
  1251. );
  1252. }
  1253. break;
  1254. case ADSTYPE_LARGE_INTEGER :
  1255. TRACE(_T(
  1256. "%e = "),
  1257. (double) pColumn->pADsValues[k].Integer
  1258. );
  1259. break;
  1260. case ADSTYPE_UTC_TIME :
  1261. TRACE(_T(
  1262. "(date value) "
  1263. ));
  1264. break;
  1265. case ADSTYPE_PROV_SPECIFIC :
  1266. TRACE(_T(
  1267. "(provider specific value) "
  1268. ));
  1269. break;
  1270. }
  1271. }
  1272. TRACE(_T("\n"));
  1273. }
  1274. #endif
  1275. /////////////////////////////////////////////////////////////////////////////
  1276. // Return TRUE if we are enumerating our main folder
  1277. BOOL CComponentImpl::IsEnumerating(LPDATAOBJECT lpDataObject)
  1278. {
  1279. BOOL bResult = FALSE;
  1280. STGMEDIUM stgmedium = { TYMED_HGLOBAL, NULL };
  1281. FORMATETC formatetc = { (CLIPFORMAT)CDataObject::m_cfNodeType, NULL,
  1282. DVASPECT_CONTENT, -1, TYMED_HGLOBAL
  1283. };
  1284. // Allocate memory for the stream
  1285. stgmedium.hGlobal = GlobalAlloc(GMEM_SHARE, sizeof(GUID));
  1286. // Attempt to get data from the object
  1287. do
  1288. {
  1289. if (stgmedium.hGlobal == NULL)
  1290. break;
  1291. if (FAILED(lpDataObject->GetDataHere(&formatetc, &stgmedium)))
  1292. break;
  1293. GUID* nodeType = reinterpret_cast<GUID*>(stgmedium.hGlobal);
  1294. if (nodeType == NULL)
  1295. break;
  1296. // Is this my main node (static folder node type)
  1297. if (*nodeType == cDefaultNodeType)
  1298. bResult = TRUE;
  1299. } while (FALSE);
  1300. // Free resources
  1301. if (stgmedium.hGlobal != NULL)
  1302. GlobalFree(stgmedium.hGlobal);
  1303. return bResult;
  1304. }
  1305. /////////////////////////////////////////////////////////////////////////////
  1306. // CComponentImpl's IComponent implementation
  1307. STDMETHODIMP CComponentImpl::GetResultViewType(MMC_COOKIE cookie, LPOLESTR* ppViewType,
  1308. long *pViewOptions)
  1309. {
  1310. // Use default view
  1311. *pViewOptions = 0;
  1312. return S_FALSE;
  1313. }
  1314. STDMETHODIMP CComponentImpl::Initialize(LPCONSOLE lpConsole)
  1315. {
  1316. ASSERT(lpConsole != NULL);
  1317. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1318. // Save the IConsole pointer
  1319. m_pConsole = lpConsole;
  1320. m_pConsole->AddRef();
  1321. // Load resource strings
  1322. LoadResources();
  1323. // QI for a IHeaderCtrl
  1324. HRESULT hr = m_pConsole->QueryInterface(IID_IHeaderCtrl,
  1325. reinterpret_cast<void**>(&m_pHeader));
  1326. // Give the console the header control interface pointer
  1327. if (SUCCEEDED(hr))
  1328. m_pConsole->SetHeader(m_pHeader);
  1329. m_pConsole->QueryInterface(IID_IResultData,
  1330. reinterpret_cast<void**>(&m_pResult));
  1331. hr = m_pConsole->QueryResultImageList(&m_pImageResult);
  1332. ASSERT(hr == S_OK);
  1333. hr = m_pConsole->QueryConsoleVerb(&m_pConsoleVerb);
  1334. ASSERT(hr == S_OK);
  1335. //InitializeHeaders(NULL);
  1336. //InitializeBitmaps(NULL);
  1337. return S_OK;
  1338. }
  1339. STDMETHODIMP CComponentImpl::Notify(LPDATAOBJECT lpDataObject, MMC_NOTIFY_TYPE event, LPARAM arg, LPARAM param)
  1340. {
  1341. HRESULT hr = S_OK;
  1342. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1343. if (event == MMCN_PROPERTY_CHANGE)
  1344. {
  1345. hr = OnPropertyChange(lpDataObject);
  1346. }
  1347. else if (event == MMCN_VIEW_CHANGE)
  1348. {
  1349. hr = OnUpdateView(lpDataObject);
  1350. }
  1351. else if (event == MMCN_CONTEXTHELP)
  1352. {
  1353. CComPtr<IDisplayHelp> spHelp;
  1354. hr = m_pConsole->QueryInterface(IID_IDisplayHelp, (void **)&spHelp);
  1355. ASSERT(SUCCEEDED(hr));
  1356. if (SUCCEEDED(hr))
  1357. {
  1358. TRACE(L"Setting the help topic to adconcepts.chm::/domadmin_top.htm\n");
  1359. spHelp->ShowTopic(L"adconcepts.chm::/domadmin_top.htm");
  1360. }
  1361. }
  1362. else
  1363. {
  1364. if (lpDataObject == NULL)
  1365. return S_OK;
  1366. CFolderObject* pFolderObject = NULL;
  1367. DATA_OBJECT_TYPES type;
  1368. CInternalFormatCracker dobjCracker(m_pCD);
  1369. if (!dobjCracker.GetContext(lpDataObject, &pFolderObject, &type))
  1370. {
  1371. // Extensions not supported.
  1372. ASSERT(FALSE);
  1373. return S_OK;
  1374. }
  1375. ASSERT(pFolderObject != NULL);
  1376. switch(event)
  1377. {
  1378. case MMCN_SHOW:
  1379. hr = OnShow(pFolderObject, arg, param);
  1380. break;
  1381. case MMCN_ADD_IMAGES:
  1382. hr = OnAddImages(pFolderObject, arg, param);
  1383. break;
  1384. case MMCN_SELECT:
  1385. if (IsMMCMultiSelectDataObject(lpDataObject) == TRUE)
  1386. pFolderObject = NULL;
  1387. HandleStandardVerbs( (BOOL) LOWORD(arg)/*bScope*/,
  1388. (BOOL) HIWORD(arg)/*bSelect*/, pFolderObject, type);
  1389. break;
  1390. case MMCN_REFRESH:
  1391. Refresh(pFolderObject);
  1392. break;
  1393. default:
  1394. break;
  1395. } // switch
  1396. } // else
  1397. if (m_pResult)
  1398. {
  1399. // should put something here, someday?
  1400. ;
  1401. }
  1402. return hr;
  1403. }
  1404. STDMETHODIMP CComponentImpl::Destroy(MMC_COOKIE cookie)
  1405. {
  1406. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1407. // Release the interfaces that we QI'ed
  1408. if (m_pConsole != NULL)
  1409. {
  1410. // Tell the console to release the header control interface
  1411. m_pConsole->SetHeader(NULL);
  1412. SAFE_RELEASE(m_pHeader);
  1413. SAFE_RELEASE(m_pResult);
  1414. SAFE_RELEASE(m_pImageResult);
  1415. // Release the IConsole interface last
  1416. SAFE_RELEASE(m_pConsole);
  1417. SAFE_RELEASE(m_pComponentData); // QI'ed in IComponentDataImpl::CreateComponent
  1418. SAFE_RELEASE(m_pConsoleVerb);
  1419. }
  1420. return S_OK;
  1421. }
  1422. STDMETHODIMP CComponentImpl::QueryDataObject(MMC_COOKIE cookie, DATA_OBJECT_TYPES type,
  1423. LPDATAOBJECT* ppDataObject)
  1424. {
  1425. // Delegate it to the IComponentData
  1426. ASSERT(m_pComponentData != NULL);
  1427. return m_pComponentData->QueryDataObject(cookie, type, ppDataObject);
  1428. }
  1429. /////////////////////////////////////////////////////////////////////////////
  1430. // CComponentImpl's implementation specific members
  1431. DEBUG_DECLARE_INSTANCE_COUNTER(CComponentImpl);
  1432. CComponentImpl::CComponentImpl()
  1433. {
  1434. DEBUG_INCREMENT_INSTANCE_COUNTER(CComponentImpl);
  1435. Construct();
  1436. }
  1437. CComponentImpl::~CComponentImpl()
  1438. {
  1439. #if DBG==1
  1440. ASSERT(dbg_cRef == 0);
  1441. #endif
  1442. DEBUG_DECREMENT_INSTANCE_COUNTER(CComponentImpl);
  1443. // Make sure the interfaces have been released
  1444. ASSERT(m_pConsole == NULL);
  1445. ASSERT(m_pHeader == NULL);
  1446. Construct();
  1447. }
  1448. void CComponentImpl::Construct()
  1449. {
  1450. #if DBG==1
  1451. dbg_cRef = 0;
  1452. #endif
  1453. m_pConsole = NULL;
  1454. m_pHeader = NULL;
  1455. m_pResult = NULL;
  1456. m_pImageResult = NULL;
  1457. m_pComponentData = NULL;
  1458. m_pCD = NULL;
  1459. m_pConsoleVerb = NULL;
  1460. m_selectedType = CCT_UNINITIALIZED;
  1461. m_pSelectedFolderObject = NULL;
  1462. }
  1463. void CComponentImpl::LoadResources()
  1464. {
  1465. // Load strings from resources
  1466. m_column1.LoadString(IDS_NAME);
  1467. m_column2.LoadString(IDS_TYPE);
  1468. }
  1469. HRESULT CComponentImpl::InitializeHeaders(CFolderObject* pFolderObject)
  1470. {
  1471. HRESULT hr = S_OK;
  1472. ASSERT(m_pHeader);
  1473. // NOTICE: we ignore the cookie, keep always the same columns
  1474. m_pHeader->InsertColumn(0, m_column1, LVCFMT_LEFT, 200); // Name
  1475. m_pHeader->InsertColumn(1, m_column2, LVCFMT_LEFT, 80); // Type
  1476. return hr;
  1477. }
  1478. HRESULT CComponentImpl::InitializeBitmaps(CFolderObject* pFolderObject)
  1479. {
  1480. ASSERT(m_pImageResult != NULL);
  1481. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1482. CBitmap bmp16x16;
  1483. CBitmap bmp32x32;
  1484. // Load the bitmaps from the dll
  1485. VERIFY(bmp16x16.LoadBitmap(IDB_DOMAIN_SMALL));
  1486. VERIFY(bmp32x32.LoadBitmap(IDB_DOMAIN_LARGE));
  1487. // Set the images
  1488. HRESULT hr = m_pImageResult->ImageListSetStrip(reinterpret_cast<LONG_PTR*>(static_cast<HBITMAP>(bmp16x16)),
  1489. reinterpret_cast<LONG_PTR*>(static_cast<HBITMAP>(bmp32x32)),
  1490. 0, RGB(128, 0, 0));
  1491. if (FAILED(hr))
  1492. return hr;
  1493. return ((CComponentDataImpl*)m_pComponentData)->AddDomainIconToResultPane(m_pImageResult);
  1494. }
  1495. STDMETHODIMP CComponentImpl::GetDisplayInfo(LPRESULTDATAITEM pResult)
  1496. {
  1497. ASSERT(pResult != NULL);
  1498. CDomainObject* pDomain = reinterpret_cast<CDomainObject*>(pResult->lParam);
  1499. if ( (pDomain != NULL) && (pResult->mask & RDI_STR) )
  1500. {
  1501. pResult->str = (LPWSTR)pDomain->GetDisplayString(pResult->nCol);
  1502. TRACE(L"pResult->str = %s\n", pResult->str);
  1503. }
  1504. if ((pResult->mask & RDI_IMAGE) && (pResult->nCol == 0))
  1505. {
  1506. pResult->nImage = pDomain->GetImageIndex();
  1507. }
  1508. return S_OK;
  1509. }
  1510. /////////////////////////////////////////////////////////////////////////////
  1511. // IExtendContextMenu Implementation
  1512. STDMETHODIMP CComponentImpl::AddMenuItems(LPDATAOBJECT pDataObject,
  1513. LPCONTEXTMENUCALLBACK pContextMenuCallback,
  1514. long * pInsertionAllowed)
  1515. {
  1516. return dynamic_cast<CComponentDataImpl*>(m_pComponentData)->
  1517. AddMenuItems(pDataObject, pContextMenuCallback, pInsertionAllowed);
  1518. }
  1519. STDMETHODIMP CComponentImpl::Command(long nCommandID, LPDATAOBJECT pDataObject)
  1520. {
  1521. return dynamic_cast<CComponentDataImpl*>(m_pComponentData)->
  1522. Command(nCommandID, pDataObject);
  1523. }
  1524. HRESULT CComponentImpl::OnShow(CFolderObject* pFolderObject, LPARAM arg, LPARAM param)
  1525. {
  1526. // Note - arg is TRUE when it is time to enumerate
  1527. if (arg == TRUE)
  1528. {
  1529. // Show the headers for this nodetype
  1530. InitializeHeaders(pFolderObject);
  1531. Enumerate(pFolderObject, param);
  1532. }
  1533. return S_OK;
  1534. }
  1535. HRESULT CComponentImpl::OnAddImages(CFolderObject* pFolderObject, LPARAM arg, LPARAM param)
  1536. {
  1537. return InitializeBitmaps(pFolderObject);
  1538. }
  1539. HRESULT CComponentImpl::OnPropertyChange(LPDATAOBJECT lpDataObject)
  1540. {
  1541. return S_OK;
  1542. }
  1543. HRESULT CComponentImpl::OnUpdateView(LPDATAOBJECT lpDataObject)
  1544. {
  1545. return S_OK;
  1546. }
  1547. void CComponentImpl::Enumerate(CFolderObject* pFolderObject, HSCOPEITEM pParent)
  1548. {
  1549. }
  1550. //////////////////////////////////////////////////////////////////////////
  1551. // CDomainSnapinAbout
  1552. CDomainSnapinAbout::CDomainSnapinAbout():
  1553. CSnapinAbout(IDS_SNAPINABOUT_DESCRIPTION,
  1554. IDI_DOMAIN,
  1555. IDB_DOMAIN_SMALL,
  1556. IDB_DOMAIN_SMALL,
  1557. IDB_DOMAIN_LARGE,
  1558. RGB(255,0,255))
  1559. {
  1560. }
  1561. ////////////////////////////////////////////////////////////////////
  1562. // CHiddenWnd
  1563. const UINT CHiddenWnd::s_SheetCloseNotificationMessage = WM_DSA_SHEET_CLOSE_NOTIFY;
  1564. const UINT CHiddenWnd::s_SheetCreateNotificationMessage = WM_DSA_SHEET_CREATE_NOTIFY;
  1565. BOOL CHiddenWnd::Create()
  1566. {
  1567. RECT rcPos;
  1568. // NOTICE-2002/03/07-ericb - SecurityPush: zeroing a struct
  1569. ZeroMemory(&rcPos, sizeof(RECT));
  1570. HWND hWnd = CWindowImpl<CHiddenWnd>::Create( NULL, //HWND hWndParent,
  1571. rcPos, //RECT& rcPos,
  1572. NULL, //LPCTSTR szWindowName = NULL,
  1573. WS_POPUP, //DWORD dwStyle = WS_CHILD | WS_VISIBLE,
  1574. 0x0, //DWORD dwExStyle = 0,
  1575. 0 //UINT nID = 0
  1576. );
  1577. if (!hWnd)
  1578. {
  1579. TRACE(L"Hidden Window creation failed with error %d\n", GetLastError());
  1580. return FALSE;
  1581. }
  1582. return TRUE;
  1583. }
  1584. LRESULT CHiddenWnd::OnSheetCloseNotification(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  1585. {
  1586. ASSERT(m_pCD != NULL);
  1587. CFolderObject* pCookie = reinterpret_cast<CFolderObject*>(wParam);
  1588. m_pCD->_OnSheetClose(pCookie);
  1589. return 1;
  1590. }
  1591. LRESULT CHiddenWnd::OnSheetCreateNotification(UINT nMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  1592. {
  1593. ASSERT(m_pCD != NULL);
  1594. PDSA_SEC_PAGE_INFO pDsaSecondaryPageInfo = reinterpret_cast<PDSA_SEC_PAGE_INFO>(wParam);
  1595. ASSERT(pDsaSecondaryPageInfo != NULL);
  1596. PWSTR pwzDC = (PWSTR)lParam;
  1597. m_pCD->_OnSheetCreate(pDsaSecondaryPageInfo, pwzDC);
  1598. ::LocalFree(pDsaSecondaryPageInfo);
  1599. if (pwzDC && !IsBadReadPtr(pwzDC, sizeof(PWSTR)))
  1600. {
  1601. ::LocalFree(pwzDC);
  1602. }
  1603. return 1;
  1604. }