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.

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