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.

1713 lines
60 KiB

  1. /*
  2. * basesnap.cxx
  3. *
  4. *
  5. * Copyright (c) 1998-1999 Microsoft Corporation
  6. *
  7. * PURPOSE: Defines CBaseSnapin.
  8. *
  9. *
  10. * OWNER: ptousig
  11. */
  12. #include "headers.hxx"
  13. #include "basesnap.rgs"
  14. // Some substitution strings used to create a registry script on the fly.
  15. #define szDLLName L"DLLName"
  16. #define szModule L"Module"
  17. #define szCLSID_Snapin L"CLSID_Snapin"
  18. #define szCLSID_About L"CLSID_About"
  19. #define szClassName L"ClassName"
  20. #define szSnapinName L"SnapinName"
  21. #define szCLSID_NodeType L"CLSID_NodeType"
  22. // -----------------------------------------------------------------------------
  23. CBaseSnapin::CBaseSnapin(void)
  24. {
  25. }
  26. // -----------------------------------------------------------------------------
  27. CBaseSnapin::~CBaseSnapin(void)
  28. {
  29. // Release all of our root items.
  30. while (m_ilRootItems.empty() == false)
  31. {
  32. static_cast<LPDATAOBJECT>(m_ilRootItems.back())->Release();
  33. m_ilRootItems.pop_back();
  34. }
  35. }
  36. // -----------------------------------------------------------------------------
  37. // The simple version of Pitem() simply calls the full version.
  38. //
  39. CBaseSnapinItem *CBaseSnapin::Pitem(LPDATAOBJECT lpDataObject, HSCOPEITEM hscopeitem, long cookie)
  40. {
  41. return Pitem(NULL, NULL, lpDataObject, hscopeitem, cookie);
  42. }
  43. // -----------------------------------------------------------------------------
  44. // The full version of Pitem() attempts to find an existing CBaseSnapinItem
  45. // that matches the given parameters. If it can't find any, it will create
  46. // one.
  47. //
  48. // Note: In order to create a new item, one of the two first parameters must
  49. // be provided.
  50. //
  51. CBaseSnapinItem *CBaseSnapin::Pitem(
  52. CComponentData * pComponentData,
  53. CComponent * pComponent,
  54. LPDATAOBJECT lpDataObject,
  55. HSCOPEITEM hscopeitem,
  56. long cookie)
  57. {
  58. SC sc;
  59. CBaseSnapinItem *pitem = NULL;
  60. ItemList::iterator iter;
  61. // For debugging purposes, I don't want to modify the 'hscopeitem' parameter,
  62. // so I make a copy of it.
  63. HSCOPEITEM hscopeitem2 = hscopeitem;
  64. if (cookie)
  65. {
  66. //
  67. // We can simply cast the cookie into a CBaseSnapinItem *.
  68. //
  69. pitem = reinterpret_cast<CBaseSnapinItem *>(cookie);
  70. ASSERT(dynamic_cast<CBaseSnapinItem *>(pitem));
  71. goto Cleanup;
  72. }
  73. if (hscopeitem2 == 0 && lpDataObject == NULL)
  74. {
  75. //
  76. // We are being asked for the stand-alone root.
  77. //
  78. ASSERT(pComponentData);
  79. pitem = pComponentData->PitemStandaloneRoot();
  80. if (pitem)
  81. goto Cleanup;
  82. }
  83. if (lpDataObject)
  84. {
  85. CLSID clsid;
  86. //
  87. // Are we the snapin who created this item ?
  88. //
  89. sc = CBaseDataObject::ScGetClassID(lpDataObject, &clsid);
  90. if (sc)
  91. goto Error;
  92. if (::IsEqualCLSID(*PclsidSnapin(), clsid))
  93. {
  94. //
  95. // We created this item, we can simply cast the pointer
  96. // to a CBaseSnapinItem.
  97. //
  98. pitem = dynamic_cast<CBaseSnapinItem *>(lpDataObject);
  99. ASSERT(pitem);
  100. goto Cleanup;
  101. }
  102. }
  103. if (lpDataObject && hscopeitem2 == 0)
  104. {
  105. //
  106. // We got an IDataObject *, but we were not given a HSCOPEITEM :-(
  107. // We'll get it from the CF_EXCHANGE_ADMIN_HSCOPEITEM clipboard format.
  108. //
  109. sc = CBaseDataObject::ScGetAdminHscopeitem(lpDataObject, &hscopeitem2);
  110. if (sc == DV_E_FORMATETC)
  111. {
  112. //
  113. // We don't own this item, we were not given a HSCOPEITEM and it
  114. // doesn't support CF_EXCHANGE_ADMIN_HSCOPEITEM.
  115. //
  116. // $REVIEW (ptousig) Does this ever happen ?
  117. //
  118. ASSERT("Does this ever happen ?" && FALSE);
  119. sc = S_OK;
  120. }
  121. else if (sc)
  122. goto Error;
  123. }
  124. // If the user adds the snapin twice in the same console, we will
  125. // be asked for two root items. If we are being asked for the same root
  126. // twice, then the "if (hscopeitem2 == 0 && lpDataObject == NULL)" above
  127. // will have caught it. If we get this far, it means we are being asked
  128. // for another root item. So we want to search through our existing
  129. // list of roots only if we have a HSCOPEITEM.
  130. if (hscopeitem2)
  131. {
  132. //
  133. // We are going to search through our list of existing root items
  134. // to find one with this HSCOPEITEM.
  135. // We can't really use a STL map here because the HSCOPEITEM of the items
  136. // will change after the root is added to the list. Besides, we don't expect
  137. // more than a handful of roots anyway.
  138. //
  139. for (iter = m_ilRootItems.begin(); iter != m_ilRootItems.end(); iter++)
  140. {
  141. if ((*iter)->Hscopeitem() == hscopeitem2)
  142. {
  143. pitem = *iter;
  144. goto Cleanup; // We found it, stop looking
  145. }
  146. }
  147. }
  148. //
  149. // If we reach this point it's because we couldn't find this node.
  150. // So we create a new one and append it to the end of the list.
  151. //
  152. sc = ScCreateRootItem(lpDataObject, hscopeitem2, &pitem);
  153. if (sc)
  154. goto Error;
  155. ASSERT(pitem);
  156. //
  157. // Initialize the new root
  158. //
  159. if (pComponentData)
  160. pitem->SetComponentData(pComponentData);
  161. sc = pitem->ScInit(this, NULL, 0, TRUE);
  162. if (sc)
  163. goto Error;
  164. // Add this new item to our list of roots.
  165. static_cast<LPDATAOBJECT>(pitem)->AddRef();
  166. m_ilRootItems.push_back(pitem);
  167. // If this is a standalone root, better tell the component data about it.
  168. if (hscopeitem2 == 0 && lpDataObject == NULL)
  169. {
  170. ASSERT(pComponentData);
  171. pComponentData->SetPitemStandaloneRoot(pitem);
  172. }
  173. if (lpDataObject)
  174. {
  175. BOOL fIsOwned = FALSE;
  176. CNodeType *pnodetype = NULL;
  177. // $REVIEW (ptousig) There's a better way of doing this.
  178. // We know we don't own that node, but ScInitializeNamespaceExtension expects
  179. // a CNodeType so we have to call this to get one.
  180. sc = ScIsOwnedDataObject(lpDataObject, &fIsOwned, &pnodetype);
  181. if (sc)
  182. goto Error;
  183. // Initialize the root item's code from the dataobject of the parent item.
  184. pitem->SetIsGhostRoot(TRUE);
  185. sc = pitem->ScInitializeNamespaceExtension(lpDataObject, hscopeitem2, pnodetype);
  186. if (sc)
  187. goto Error;
  188. }
  189. Cleanup:
  190. // Make sure this item knows its HSCOPEITEM
  191. if (hscopeitem2)
  192. pitem->SetHscopeitem(hscopeitem2);
  193. ASSERT(pitem);
  194. return pitem;
  195. Error:
  196. TraceError(_T("CBaseSnapin::Pitem"), sc);
  197. MMCErrorBox(sc);
  198. goto Cleanup;
  199. }
  200. // -----------------------------------------------------------------------------
  201. // Returns whether a dataobject is "owned" by this snapin. It does that
  202. // by looking at the list of nodetypes this snapin says it can create, if
  203. // this node is one of these, we assume we own it.
  204. // As a side-effect, this function also returns the nodetype of the node.
  205. //
  206. // $REVIEW (ptousig) This is not an accurate test, we need to use the CCF_SNAPIN_CLASSID.
  207. //
  208. SC CBaseSnapin::ScIsOwnedDataObject(LPDATAOBJECT pdataobject, BOOL *pfIsOwned, CNodeType **ppnodetype)
  209. {
  210. SC sc;
  211. BOOL fIsOwned = FALSE;
  212. CNodeType * pnodetype = NULL;
  213. CLSID clsid;
  214. INT isnr = 0;
  215. ASSERT(pdataobject);
  216. ASSERT(pfIsOwned);
  217. ASSERT(ppnodetype);
  218. // Get the nodetype, in guid format, of the data object.
  219. sc = CBaseDataObject::ScGetNodeType(pdataobject, &clsid);
  220. if (sc)
  221. goto Error;
  222. for (isnr = 0; isnr < Csnr(); isnr ++)
  223. {
  224. if (IsEqualCLSID(*(Psnr(isnr)->pnodetype->PclsidNodeType()), clsid))
  225. {
  226. // We found the CLSID, keep track of its nodetype.
  227. pnodetype = Psnr(isnr)->pnodetype;
  228. SNRTypes snrtypes = Psnr(isnr)->snrtypes;
  229. // Do we enumerate nodes of this type? If so, we must be the owner.
  230. if ((snrtypes & snrEnumSP) || (snrtypes & snrEnumRP) || (snrtypes & snrEnumSM))
  231. fIsOwned = TRUE;
  232. break; // exit the loop.
  233. }
  234. }
  235. Cleanup:
  236. *pfIsOwned = fIsOwned;
  237. *ppnodetype = pnodetype;
  238. return sc;
  239. Error:
  240. TraceError(_T("CBaseSnapin::ScIsOwnedDataObject"), sc);
  241. goto Cleanup;
  242. }
  243. #ifdef _DEBUG
  244. // -----------------------------------------------------------------------------
  245. // Debug menu options
  246. //
  247. SnapinMenuItem CBaseSnapin::s_rgmenuitemBase[] =
  248. {
  249. {IDS_Test, IDS_Test, 0, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, 0, dwMenuNeverGray, dwMenuNeverChecked},
  250. #if 0
  251. {idsBarfTraces, idsBarfTracesStatusText, idmBarfTraces, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
  252. {idsBarfClearDbgScreen, idsBarfClearDbgScreenStatusText, idmBarfClearDbgScreen, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
  253. {idsBarfSCDescription, idsBarfSCDescriptionStatusText, idmBarfSCDescription, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
  254. {NULL, idsBarfSeparatorStatusText, idmBarfSeparator1, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, MF_SEPARATOR, dwMenuNeverGray, dwMenuNeverChecked},
  255. {idsBarfSettings, idsBarfSettingsStatusText, idmBarfSettings, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
  256. {idsBarfAll, idsBarfAllStatusText, idmBarfAll, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
  257. {idsBarfMemoryChkpoint, idsBarfMemoryChkpointStatusText, idmBarfMemoryChkpoint, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
  258. {idsBarfMemoryDiff, idsBarfMemoryDiffStatusText, idmBarfMemoryDiff, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
  259. {idsBarfValidateMemory, idsBarfValidateMemoryStatusText, idmBarfValidateMemory, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
  260. {idsBarfTotalMemAllocd, idsBarfTotalMemAllocdStatusText, idmBarfTotalMemAllocd, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
  261. {NULL, idsBarfSeparatorStatusText, idmBarfSeparator3, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, MF_SEPARATOR, dwMenuNeverGray, dwMenuNeverChecked},
  262. {idsBarfDebugBreak, idsBarfDebugBreakStatusText, idmBarfDebugBreak, CCM_INSERTIONPOINTID_PRIMARY_TASK, NULL, dwMenuAlwaysEnable, dwMenuNeverGray, dwMenuNeverChecked},
  263. #endif
  264. };
  265. INT CBaseSnapin::s_cMenuItemBase = CMENUITEM(s_rgmenuitemBase);
  266. // -----------------------------------------------------------------------------
  267. SnapinMenuItem *CBaseSnapin::PmenuitemBase(void)
  268. {
  269. return s_rgmenuitemBase;
  270. }
  271. // -----------------------------------------------------------------------------
  272. INT CBaseSnapin::CMenuItemBase(void)
  273. {
  274. return s_cMenuItemBase;
  275. }
  276. #endif // _DEBUG
  277. // -----------------------------------------------------------------------------
  278. // This table allows us to map a MMC verb to a specific bit in a dword.
  279. //
  280. VerbMap CBaseSnapin::s_rgverbmap[] =
  281. {
  282. { vmOpen, MMC_VERB_OPEN},
  283. { vmCopy, MMC_VERB_COPY},
  284. { vmPaste, MMC_VERB_PASTE},
  285. { vmDelete, MMC_VERB_DELETE},
  286. { vmProperties, MMC_VERB_PROPERTIES},
  287. { vmRename, MMC_VERB_RENAME},
  288. { vmRefresh, MMC_VERB_REFRESH},
  289. { vmPrint, MMC_VERB_PRINT},
  290. { vmCut, MMC_VERB_CUT},
  291. };
  292. // -----------------------------------------------------------------------------
  293. // Accesses a given entry in the VerbMap table.
  294. //
  295. VerbMap *CBaseSnapin::Pverbmap(INT i)
  296. {
  297. ASSERT(i>=0 && i<Cverbmap());
  298. return &(s_rgverbmap[i]);
  299. }
  300. // -----------------------------------------------------------------------------
  301. // Returns the number of entries in the VerbMap table.
  302. //
  303. INT CBaseSnapin::Cverbmap(void)
  304. {
  305. return(sizeof(s_rgverbmap) / sizeof(VerbMap));
  306. }
  307. // -----------------------------------------------------------------------------
  308. // Has the icon information been initialized ?
  309. BOOL CBaseSnapin::s_fBaseSnapinInitialized = FALSE;
  310. // -----------------------------------------------------------------------------
  311. // The bitmaps containing all the icons
  312. WTL::CBitmap CBaseSnapin::s_bmpImage16;
  313. WTL::CBitmap CBaseSnapin::s_bmpImage32;
  314. // -----------------------------------------------------------------------------
  315. // The Registrar
  316. //
  317. CRegistrar CBaseSnapin::s_registrar;
  318. // -----------------------------------------------------------------------------
  319. // Initializes the global bitmaps (once) as well as the per-snapin bitmaps.
  320. //
  321. SC CBaseSnapin::ScInitBitmaps(void)
  322. {
  323. DECLARE_SC(sc, _T("CBaseSnapin::ScInitBitmaps"));
  324. // Once for the whole app...
  325. if (s_fBaseSnapinInitialized == FALSE)
  326. {
  327. sc = BmpImage16().LoadBitmap(IDB_NODES16) ? S_OK : E_FAIL;
  328. if (sc)
  329. return sc;
  330. sc = BmpImage32().LoadBitmap(IDB_NODES32) ? S_OK : E_FAIL;
  331. if (sc)
  332. return sc;
  333. s_fBaseSnapinInitialized = TRUE;
  334. }
  335. if (BitmapSmall().IsNull())
  336. {
  337. sc = BitmapSmall().LoadBitmap(IDB_NODES16) ? S_OK : E_FAIL;
  338. if (sc)
  339. return sc;
  340. }
  341. if (BitmapLarge().IsNull())
  342. {
  343. sc = BitmapLarge().LoadBitmap(IDB_NODES32) ? S_OK : E_FAIL;
  344. if (sc)
  345. return sc;
  346. }
  347. if (BitmapStaticSmall().IsNull())
  348. {
  349. sc = BitmapStaticSmall().LoadBitmap(IDB_FOLDER16) ? S_OK : E_FAIL;
  350. if (sc)
  351. return sc;
  352. }
  353. if (BitmapStaticSmallOpen().IsNull())
  354. {
  355. sc = BitmapStaticSmallOpen().LoadBitmap(IDB_FOLDER16OP) ? S_OK : E_FAIL;
  356. if (sc)
  357. return sc;
  358. }
  359. if (BitmapStaticLarge().IsNull())
  360. {
  361. sc = BitmapStaticLarge().LoadBitmap(IDB_FOLDER32) ? S_OK : E_FAIL;
  362. if (sc)
  363. return sc;
  364. }
  365. return sc;
  366. }
  367. inline HBITMAP CopyBitmap (HBITMAP hbm)
  368. {
  369. return ((HBITMAP) CopyImage ((HANDLE) hbm, IMAGE_BITMAP, 0, 0, 0));
  370. }
  371. // -----------------------------------------------------------------------------
  372. // MMC wants icons to persist in the .msc file.
  373. //
  374. SC CBaseSnapin::ScGetStaticFolderImage(HBITMAP *phSmallImage, HBITMAP *phSmallImageOpen, HBITMAP *phLargeImage, COLORREF *pcMask)
  375. {
  376. ASSERT(phSmallImage && phSmallImageOpen && phLargeImage && pcMask);
  377. *phSmallImage = CopyBitmap (BitmapStaticSmall());
  378. *phSmallImageOpen = CopyBitmap (BitmapStaticSmallOpen());
  379. *phLargeImage = CopyBitmap (BitmapStaticLarge());
  380. *pcMask = RGB (255, 0, 255);
  381. return S_OK;
  382. }
  383. // -----------------------------------------------------------------------------
  384. // Compares two fields for sorting by MMC. This applies to regular result items, i.e. not to virtual
  385. // list snapin items. Our snapins can override the compare and impact the sort. We use a smart compare
  386. // to guess if the field is numeric. If so, we perform a numeric compare.
  387. // Otherwise we use case insensitive string compare.
  388. //
  389. // On input, *pnResult contains the column number to compare.
  390. // On output, *pnResult contains the result of our comparison:
  391. // -1 means A is smaller than B
  392. // 0 means A is equal to B
  393. // 1 means A is greater than B
  394. //
  395. SC CBaseSnapin::ScCompare(MMC_COOKIE cookieA, MMC_COOKIE cookieB, INT nColumn, INT * pnResult)
  396. {
  397. // Declarations
  398. SC sc; // execution code
  399. CBaseSnapinItem * pitemA = NULL; // snapin item A
  400. CBaseSnapinItem * pitemB = NULL; // snapin item B
  401. tstring strBufferA; // field A
  402. tstring strBufferB; // field B
  403. LONG lValueA = 0; // numeric value for field A
  404. LONG lValueB = 0; // numeric value for field B
  405. // Validate data
  406. ASSERT(pnResult);
  407. // Check that these cookies are not special cookies
  408. ASSERT(IS_SPECIAL_COOKIE(cookieA) == FALSE);
  409. ASSERT(IS_SPECIAL_COOKIE(cookieB) == FALSE);
  410. // Cast the cookies into snapin items
  411. pitemA = reinterpret_cast<CBaseSnapinItem *>(cookieA);
  412. pitemB = reinterpret_cast<CBaseSnapinItem *>(cookieB);
  413. // Get the fields from the snapin items
  414. sc = pitemA->ScGetField(pitemA->PcolinfoexDisplay(nColumn)->Dat(), strBufferA);
  415. if (sc)
  416. goto Error;
  417. sc = pitemB->ScGetField(pitemB->PcolinfoexDisplay(nColumn)->Dat(), strBufferB);
  418. if (sc)
  419. goto Error;
  420. ASSERT(FALSE && "Use Dat and compare data type properly");
  421. // Use the default string compare (case-insensitive)
  422. *pnResult = _tcsicmp(strBufferA.data(), strBufferB.data());
  423. if (*pnResult < 0)
  424. *pnResult = -1; // string A < string B
  425. else if (*pnResult > 0)
  426. *pnResult = 1;
  427. else
  428. *pnResult = 0;
  429. Cleanup:
  430. return sc;
  431. Error:
  432. TraceError(_T("CBaseSnapin::ScCompare()"), sc);
  433. goto Cleanup;
  434. }
  435. /* CBaseMultiSelectSnapinItem::ScCreateMultiSelectionDataObject
  436. *
  437. * PURPOSE: Creates a multiselect data object - we store a list of selected object in this special object.
  438. *
  439. * PARAMETERS:
  440. * LPDATAOBJECT * ppDataObject Pointer to a pointer to the multiselect snapin item to create.
  441. * CComponent * pComponent Pointer to the component object.
  442. *
  443. * RETURNS:
  444. * SC Execution code
  445. */
  446. SC
  447. CBaseSnapin::ScCreateMultiSelectionDataObject(LPDATAOBJECT * ppDataObject, CComponent * pComponent)
  448. {
  449. // Declarations
  450. SC sc ; // execution code
  451. HRESULT hr = S_FALSE; // local execution code
  452. RESULTDATAITEM rdi; // a selected item
  453. BOOL fFoundASelection = FALSE; // did we find at least one selected item
  454. CBaseMultiSelectSnapinItem * pBaseMultiSelectSnapinItem = NULL; // multiselect dataobject
  455. // are we processing the first object of the selected object set
  456. // Data validation
  457. ASSERT(ppDataObject);
  458. ASSERT(*ppDataObject == NULL);
  459. ASSERT(pComponent);
  460. // Allocate a typed multiselection data object
  461. sc = ScAllocateMultiSelectionDataObject(&pBaseMultiSelectSnapinItem);
  462. if (sc)
  463. goto Error;
  464. ASSERT(pBaseMultiSelectSnapinItem);
  465. // Assign the snapin - important for some clipboard formats
  466. pBaseMultiSelectSnapinItem->SetSnapin(this);
  467. // Identify the selected items
  468. ::ZeroMemory(&rdi, sizeof(rdi));
  469. rdi.nIndex = -1; // first item requested
  470. rdi.nState = LVIS_SELECTED; // only the selected items requested
  471. rdi.mask = RDI_STATE | RDI_INDEX | RDI_PARAM; // state, cookie and index
  472. // Get the result data interface
  473. ASSERT(pComponent->IpResultData()); // verify we have an IResultData interface
  474. while (S_OK == (hr = pComponent->IpResultData()->GetNextItem(&rdi)))
  475. {
  476. // Local declarations
  477. CBaseSnapinItem * pitem = NULL;
  478. // Make sure we got a cookie for the item
  479. ASSERT(rdi.lParam);
  480. pitem = reinterpret_cast<CBaseSnapinItem *>(rdi.lParam);
  481. ASSERT(pitem);
  482. // Add the item to the list managed by our multiselect data object
  483. ASSERT(pBaseMultiSelectSnapinItem->PivSelectedItems());
  484. pBaseMultiSelectSnapinItem->PivSelectedItems()->push_back(pitem);
  485. // Remember we found a selected object
  486. fFoundASelection = TRUE;
  487. }
  488. if (FAILED(hr))
  489. {
  490. sc = hr;
  491. goto Error;
  492. }
  493. // Let the component it is in multiselect mode
  494. *(pComponent->PpMultiSelectSnapinItem()) = pBaseMultiSelectSnapinItem;
  495. // Make sure we found at least one selected object, otherwise we should never have been called in the first place
  496. ASSERT(fFoundASelection);
  497. // Set the result
  498. *ppDataObject = pBaseMultiSelectSnapinItem;
  499. Cleanup:
  500. return sc;
  501. Error:
  502. if (pBaseMultiSelectSnapinItem)
  503. delete pBaseMultiSelectSnapinItem;
  504. pBaseMultiSelectSnapinItem = NULL;
  505. TraceError(_T("CBaseSnapin::ScCreateMultiSelectionDataObject()"), sc);
  506. goto Cleanup;
  507. }
  508. /* CBaseMultiSelectSnapinItem::ScAllocateMultiSelectionDataObject
  509. *
  510. * PURPOSE: Allocates a multiselect data object - we store a list of selected object in this special object.
  511. *
  512. * PARAMETERS:
  513. * CBaseMultiSelectSnapinItem ** ppBaseMultiSelectSnapinItem Pointer to a pointer to the multiselect snapin item to allocate.
  514. *
  515. * RETURNS:
  516. * SC Execution code
  517. */
  518. SC
  519. CBaseSnapin::ScAllocateMultiSelectionDataObject(CBaseMultiSelectSnapinItem ** ppBaseMultiSelectSnapinItem)
  520. {
  521. // Declarations
  522. SC sc ;
  523. t_itemBaseMultiSelectSnapinItem * pBaseMultiSelectSnapinItem = NULL; // create multiselect snapin item
  524. // Data validation
  525. ASSERT(ppBaseMultiSelectSnapinItem);
  526. ASSERT(!*ppBaseMultiSelectSnapinItem);
  527. // Allocate the object
  528. sc = ScCreateItemQuick(&pBaseMultiSelectSnapinItem);
  529. if (sc)
  530. goto Error;
  531. // Assign the result
  532. *ppBaseMultiSelectSnapinItem = pBaseMultiSelectSnapinItem;
  533. Cleanup:
  534. return sc;
  535. Error:
  536. TraceError(_T("CBaseSnapin::ScAllocateMultiSelectionDataObject()"), sc);
  537. goto Cleanup;
  538. }
  539. // -----------------------------------------------------------------------------
  540. // Returns the version information string for the snapin.
  541. // The output string must be allocated with CoTaskMemAlloc.
  542. //
  543. SC CBaseSnapin::ScGetSnapinVersion(LPOLESTR *lpVersion)
  544. {
  545. DECLARE_SC(sc, _T("CBaseSnapin::ScGetSnapinVersion"));
  546. sc = ScCheckPointers(lpVersion);
  547. if (sc)
  548. return sc;
  549. *lpVersion = CoTaskDupString(L"");
  550. if ((*lpVersion) == NULL)
  551. return (E_OUTOFMEMORY);
  552. return sc;
  553. }
  554. SC CBaseSnapin::ScGetProvider(LPOLESTR *lpName)
  555. {
  556. DECLARE_SC(sc, _T("CBaseSnapin::ScGetProvider"));
  557. sc = ScCheckPointers(lpName);
  558. if (sc)
  559. return sc;
  560. *lpName = CoTaskDupString(L"Microsoft");
  561. if ((*lpName) == NULL)
  562. return (E_OUTOFMEMORY);
  563. return sc;
  564. }
  565. // -----------------------------------------------------------------------------
  566. // Creates an ATL Registrar script for the snapin and registers/unregisters it.
  567. // If fRegister is TRUE then we are registering, FALSE we are unregistering.
  568. //
  569. SC CBaseSnapin::ScRegister(BOOL fRegister)
  570. {
  571. SC sc ;
  572. HRESULT hr = S_OK;
  573. INT i = 0;
  574. const INT cchMaxLen = 256;
  575. TCHAR szFileName[cchMaxLen];
  576. CStr cstrTemp;
  577. tstring strVersion;
  578. const INT cchMaxRegScript = 10000;
  579. tstring strRegScript;
  580. tstring strFmtSnapinRegScript;
  581. tstring strSnapinAboutRegScript;
  582. tstring strSnapinNodeTypes;
  583. tstring strExtensionScript;
  584. tstring strPropertySheetScript;
  585. tstring strToolBarScript;
  586. tstring strNameSpaceScript;
  587. tstring strContextMenuScript;
  588. tstring strTemp;
  589. tstring strSnapinName;
  590. tstring strStandalone;
  591. // Hacks for version, snapin name.
  592. // Version number eg 6.3523.0.0
  593. strVersion = _T("6.3523.0.0");
  594. strSnapinAboutRegScript = szSnapinAboutRegScript + strVersion;
  595. cstrTemp.Format(szSnapinAboutRegScript, strVersion.data());
  596. strSnapinAboutRegScript = cstrTemp;
  597. strSnapinName.LoadString(_Module.GetModuleInstance(), IdsName());
  598. // strSnapinName = _T("Sample Framework Snapin");
  599. GetModuleFileName(_Module.GetModuleInstance(), szFileName, cchMaxLen);
  600. // Create the Standalone key only if we're a standalone snapin.
  601. if (FStandalone())
  602. strStandalone = szStandalone;
  603. // Format all the extension node stuff.
  604. for (i = 0; i<Csnr(); i++)
  605. {
  606. tstring strNodeTypeName;
  607. CNodeType *pnodetype = Psnr()[i].pnodetype;
  608. SNRTypes snrtypes = Psnr()[i].snrtypes;
  609. // Get the name of the node type
  610. if (! pnodetype->StrName().empty())
  611. {
  612. strTemp = pnodetype->StrName();
  613. strNodeTypeName = pnodetype->StrClsidNodeType();
  614. strNodeTypeName += _T(" = s '");
  615. strNodeTypeName += pnodetype->StrName();
  616. strNodeTypeName += _T("'");
  617. }
  618. else
  619. strNodeTypeName = pnodetype->StrClsidNodeType();
  620. // Add the ID of the node to the NodeTypes key if we enumerate it.
  621. tstring strSnapinNodeTypesTemp;
  622. if ( (snrtypes & snrEnumSP) || (snrtypes & snrEnumRP) || (snrtypes & snrEnumSM))
  623. {
  624. // Add the opening brace the first time around.
  625. if (strSnapinNodeTypes.empty())
  626. strSnapinNodeTypes = szSnapinNodeTypeOpen;
  627. cstrTemp.Format(szFmtSnapinNodeType, pnodetype->StrClsidNodeType().data());
  628. strSnapinNodeTypesTemp = cstrTemp;
  629. strSnapinNodeTypes += strSnapinNodeTypesTemp;
  630. }
  631. // Needed because this is a for loop.
  632. strContextMenuScript = _T("");
  633. // Menu extensions
  634. if ( snrtypes & snrExtCM)
  635. {
  636. cstrTemp.Format(szfmtSingleExtension, szSingleExtension);
  637. strContextMenuScript = cstrTemp;
  638. }
  639. // Property Page extensions
  640. strPropertySheetScript = _T("");
  641. if ( snrtypes & snrExtPS)
  642. {
  643. cstrTemp.Format(szfmtSingleExtension, szSingleExtension);
  644. strPropertySheetScript = cstrTemp;
  645. }
  646. // Toolbar extensions
  647. strToolBarScript = _T("");
  648. if ( snrtypes & snrExtTB)
  649. {
  650. cstrTemp.Format(szfmtSingleExtension, szSingleExtension);
  651. strToolBarScript = cstrTemp;
  652. }
  653. // Namespace extensions
  654. strNameSpaceScript = _T("");
  655. if ( snrtypes & snrExtNS)
  656. {
  657. cstrTemp.Format(szfmtSingleExtension, szSingleExtension);
  658. strNameSpaceScript = cstrTemp;
  659. }
  660. cstrTemp.Format(szfmtAllExtensions, strNodeTypeName.data(), strNameSpaceScript.data() , strContextMenuScript.data() , strPropertySheetScript.data() , strToolBarScript.data());
  661. strExtensionScript += cstrTemp;
  662. }
  663. // Add a closing brace to the NodeTypes key if needed
  664. if (! strSnapinNodeTypes.empty())
  665. strSnapinNodeTypes += szSnapinNodeTypeClose;
  666. // Need to concatenate these to form the real fmt string!
  667. strFmtSnapinRegScript = szfmtSnapinRegScript1;
  668. strFmtSnapinRegScript += szfmtSnapinRegScript2;
  669. cstrTemp.Format(strFmtSnapinRegScript.data(), strVersion.data(), strVersion.data(), strStandalone.data(), strSnapinNodeTypes.data(), strExtensionScript.data());
  670. strRegScript = strSnapinAboutRegScript;
  671. strRegScript += cstrTemp;
  672. USES_CONVERSION;
  673. // Set all the replacement parameter values.
  674. // $REVIEW (ptousig) DLLName is always set to Exadmin !!!
  675. sc = Registrar().ClearReplacements( );
  676. sc = Registrar().AddReplacement(szDLLName, L"Snapins");
  677. sc = Registrar().AddReplacement(szModule, T2COLE(szFileName));
  678. sc = Registrar().AddReplacement(szCLSID_Snapin, T2COLE(StrClsidSnapin().data()));
  679. sc = Registrar().AddReplacement(szCLSID_About, T2COLE(StrClsidAbout().data()));
  680. sc = Registrar().AddReplacement(szClassName, T2COLE(StrClassName().data()));
  681. sc = Registrar().AddReplacement(szSnapinName, T2COLE(strSnapinName.data()));
  682. sc = Registrar().AddReplacement(szCLSID_NodeType, L"");
  683. if (fRegister)
  684. {
  685. LPCOLESTR lpOleStr = T2COLE(strRegScript.data());
  686. sc = Registrar().StringRegister(lpOleStr);
  687. if (sc)
  688. goto Error;
  689. }
  690. else
  691. {
  692. hr = Registrar().StringUnregister(strRegScript.data());
  693. if (hr == DISP_E_EXCEPTION)
  694. {
  695. //
  696. // When trying to unregister a snapin that wasn't registered in
  697. // the first place, the Registrar returns a DISP_E_EXCEPTION.
  698. // I don't know why, seems to be a bug in the Registrar. Our
  699. // solution for now is to ignore the error, not very clean but
  700. // effective. We are un-registering a snapin that wasn't registered
  701. // anyway.
  702. //
  703. hr = S_OK;
  704. }
  705. else if (FAILED(hr))
  706. {
  707. //
  708. // Some other error occured
  709. //
  710. sc = hr;
  711. goto Error;
  712. }
  713. }
  714. Cleanup:
  715. return sc;
  716. Error:
  717. TraceError(_T("CBaseSnapin::ScRegister"), sc);
  718. goto Cleanup;
  719. }
  720. #if 0
  721. #ifdef _DEBUG
  722. // -----------------------------------------------------------------------------
  723. // Displays the Traces menu (in debug only)
  724. //
  725. SC CBaseSnapin::ScOnMenuTraces(void)
  726. {
  727. DoTraceDialog();
  728. return S_OK;
  729. }
  730. // -----------------------------------------------------------------------------
  731. // Provides a description of a given SC Code (in debug only)
  732. //
  733. SC CBaseSnapin::ScOnMenuSCDescription(void)
  734. {
  735. CStr strPrompt(_T("Enter the Status Code (sc)"));
  736. CSTR (strAnswer, 10);
  737. CAskStringDialog dlg;
  738. ID id;
  739. SC sc;
  740. dlg.SetPrompt(&strPrompt);
  741. dlg.SetAnswer(&strAnswer);
  742. strAnswer.BlankString();
  743. id = dlg.IdModal();
  744. if (id != IDOK)
  745. return(sc = S_OK);
  746. //
  747. // Convert the text the user entered into a SC.
  748. //
  749. sc = (SC) strAnswer.strtoul(NULL, 16);
  750. MbbErrorBox(sc);
  751. return sc;
  752. }
  753. // -----------------------------------------------------------------------------
  754. // Debug stuff (in debug only)
  755. //
  756. SC CBaseSnapin::ScOnMenuMemoryDiff(void)
  757. {
  758. #ifdef USE_BARFMEM
  759. CBaseWaitCursor wc;
  760. CBarfMemory::DumpMarked();
  761. #endif // USE_BARFMEM
  762. return S_OK;
  763. }
  764. // -----------------------------------------------------------------------------
  765. // Validates Memory (in debug only)
  766. //
  767. SC CBaseSnapin::ScOnMenuValidateMemory(void)
  768. {
  769. #ifdef USE_BARFMEM
  770. CBaseWaitCursor wc;
  771. //Ensure output even if tagMemoryCorruption not turned on
  772. Trace(&tagAlways, _T("CBaseSnapin::ScOnMenuValidateMemory() - Validating memory ..."));
  773. ValidateMemory(&tagAlways);
  774. Trace(&tagAlways, _T("CBaseSnapin::ScOnMenuValidateMemory() - ... Done validating memory."));
  775. #endif // USE_BARFMEM
  776. return S_OK;
  777. }
  778. // -----------------------------------------------------------------------------
  779. // Displays Dialog Box of Total Memory Allocated (in debug only)
  780. //
  781. SC CBaseSnapin::ScOnMenuTotalMemory(void)
  782. {
  783. #ifdef USE_BARFMEM
  784. INT nAlloc;
  785. INT nBytes;
  786. CSTR (str, cchMaxLine);
  787. CBaseWaitCursor wc;
  788. TotalMemory(&nAlloc, &nBytes);
  789. str.Format(_T("Memory currently allocated:\n\n%d allocations\n%d bytes"), nAlloc, nBytes);
  790. MbbErrorBox(str.Sz(), MB_OK | MB_ICONINFORMATION);
  791. #endif // USE_BARFMEM
  792. return S_OK;
  793. }
  794. #endif
  795. #endif //#if 0
  796. // -----------------------------------------------------------------------------
  797. // Given two pointers to dataObjects, are they the same?
  798. // Returns S_OK if objects A and B are the same, S_FALSE if they are different.
  799. //
  800. // $REVIEW (ptousig) Will there ever be a case where two different
  801. // dataobjects should be considered equal ?
  802. //
  803. SC CBaseSnapin::ScCompareObjects(LPDATAOBJECT lpDataObjectA, LPDATAOBJECT lpDataObjectB)
  804. {
  805. SC sc = S_FALSE;
  806. BOOL fOwnedA = FALSE;
  807. BOOL fOwnedB = FALSE;
  808. CNodeType *pnodetypeA = NULL;
  809. CNodeType *pnodetypeB = NULL;
  810. // Check if one of the pointers is NULL.
  811. if (!lpDataObjectA || !lpDataObjectB)
  812. {
  813. // This happens when one of the objects is new.
  814. // See bug 117170.
  815. sc = S_FALSE;
  816. goto Cleanup;
  817. }
  818. if (lpDataObjectA == lpDataObjectB)
  819. {
  820. // If both pointers are the same, then obviously they are
  821. // the same object.
  822. sc = S_OK;
  823. goto Cleanup;
  824. }
  825. // Do we own both dataobjects.
  826. sc = ScIsOwnedDataObject(lpDataObjectA, &fOwnedA, &pnodetypeA);
  827. if (sc)
  828. goto Error;
  829. sc = ScIsOwnedDataObject(lpDataObjectB, &fOwnedB, &pnodetypeB);
  830. if (sc)
  831. goto Error;
  832. if (fOwnedA == FALSE || fOwnedB == FALSE)
  833. {
  834. // We don't own at least of the dataobjects. They are either
  835. // different or we are not qualified to compare them.
  836. sc = S_FALSE;
  837. goto Cleanup;
  838. }
  839. // Since we own both dataobjects, and the pointers are different
  840. // then we can conclude that they represent different objects.
  841. sc = S_FALSE;
  842. Cleanup:
  843. return sc;
  844. Error:
  845. TraceError(_T("CBaseSnapin::ScCompareObjects"), sc);
  846. goto Cleanup;
  847. }
  848. // -----------------------------------------------------------------------------
  849. // Handler of AddMenuItems we ask the item for its menu items. And in debug
  850. // mode we add debug menu items if the item wants us to.
  851. //
  852. SC CBaseSnapin::ScAddMenuItems(LPDATAOBJECT lpDataObject, LPCONTEXTMENUCALLBACK ipContextMenuCallback, long *pInsertionAllowed)
  853. {
  854. // Declarations
  855. SC sc;
  856. CBaseSnapinItem * pitem = NULL;
  857. CBaseMultiSelectSnapinItem * pBaseMultiSelectSnapinItem = NULL;
  858. // Data validation
  859. ASSERT(lpDataObject);
  860. ASSERT(ipContextMenuCallback);
  861. ASSERT(pInsertionAllowed);
  862. // See if we can extract the multi select data object from the composite data object
  863. sc = CBaseMultiSelectSnapinItem::ScExtractMultiSelectDataObject(this, lpDataObject, &pBaseMultiSelectSnapinItem);
  864. if (sc)
  865. goto Error;
  866. // If we actually had a composite data object and we were able to find our multiselect snapin item
  867. if (pBaseMultiSelectSnapinItem)
  868. {
  869. // Call ScAddMenuItems for the multiselect object for menu merging
  870. sc = pBaseMultiSelectSnapinItem->ScAddMenuItems(this, lpDataObject, ipContextMenuCallback, pInsertionAllowed);
  871. if (sc)
  872. goto Error;
  873. }
  874. else
  875. {
  876. // Handle the normal case - PItem() does more work than a simple cast to verify that the snapin item belongs to the snapin etc.
  877. pitem = Pitem(lpDataObject);
  878. ASSERT(pitem);
  879. sc = ScAddMenuItems(pitem, *pInsertionAllowed, ipContextMenuCallback, pitem->Pmenuitem(), pitem->CMenuItem());
  880. if (sc)
  881. goto Error;
  882. }
  883. Cleanup:
  884. return sc;
  885. Error:
  886. TraceError(_T("CBaseSnapin::ScAddMenuItems"), sc);
  887. goto Cleanup;
  888. }
  889. // -----------------------------------------------------------------------------
  890. // Constructor for CSnapinContextMenuItem
  891. //
  892. CSnapinContextMenuItem::CSnapinContextMenuItem(void)
  893. {
  894. // Initialize members
  895. ::ZeroMemory(&cm, sizeof(cm));
  896. }
  897. // -----------------------------------------------------------------------------
  898. // Destructor for CSnapinContextMenuItemVectorWrapper
  899. //
  900. CSnapinContextMenuItemVectorWrapper::~CSnapinContextMenuItemVectorWrapper(void)
  901. {
  902. // Declarations
  903. INT nIterator = 0;
  904. // Go through all the referenced CSnapinContextMenuItem objects and delete them
  905. for (nIterator=0; nIterator < cmiv.size(); nIterator++)
  906. {
  907. if (cmiv[nIterator])
  908. {
  909. delete cmiv[nIterator];
  910. cmiv[nIterator] = NULL;
  911. }
  912. }
  913. }
  914. // -----------------------------------------------------------------------------
  915. // Adds menu items to the context menu.
  916. //
  917. SC
  918. CBaseSnapin::ScAddMenuItems(CBaseSnapinItem * pitem, long lInsertionAllowed, LPCONTEXTMENUCALLBACK ipContextMenuCallback, SnapinMenuItem * rgmenuitem, INT cmenuitem)
  919. {
  920. // Declarations
  921. SC sc ;
  922. BOOL fAllowed = TRUE;
  923. INT nIterator = 0;
  924. // Data validation
  925. ASSERT(pitem);
  926. ASSERT(ipContextMenuCallback);
  927. // ASSERT(rgmenuitem); sometimes there is no menu
  928. // Go through the different menu items
  929. for (nIterator=0; nIterator < cmenuitem; nIterator++)
  930. {
  931. // Local declarations
  932. CSnapinContextMenuItem cmi;
  933. // Get the menu item
  934. sc = ScGetMenuItem(&cmi, pitem, &(rgmenuitem[nIterator]), &fAllowed, lInsertionAllowed);
  935. if (sc)
  936. goto Error;
  937. // If the menu item is allowed, then add it
  938. if (fAllowed)
  939. {
  940. sc = ipContextMenuCallback->AddItem(&(cmi.cm));
  941. if (sc)
  942. goto Error;
  943. }
  944. }
  945. Cleanup:
  946. return sc;
  947. Error:
  948. TraceError(_T("CBaseSnapin::ScAddMenuItems"), sc);
  949. goto Cleanup;
  950. };
  951. /* CBaseSnapin::ScGetMenuItem
  952. *
  953. * PURPOSE: Sets a menu item struct for a particular snapin item and for a particular source menu item of that snapin item.
  954. *
  955. * PARAMETERS:
  956. * CSnapinContextMenuItem * pcmiReturned Menu item struct to set
  957. * CBaseSnapinItem * pitem Snapin item from which the source menu item comes
  958. * MenuItem * pMenuItemSource Source menu item
  959. * BOOL * pfAllowed TRUE if the menu item allowed?
  960. *
  961. * RETURNS:
  962. * SC Execution code
  963. */
  964. SC
  965. CBaseSnapin::ScGetMenuItem(CSnapinContextMenuItem * pcmiReturned, CBaseSnapinItem * pitem, SnapinMenuItem * pMenuItemSource, BOOL * pfAllowed, long lInsertionAllowed)
  966. {
  967. // Declarations
  968. SC sc ;
  969. LONG fFlags = 0;
  970. DWORD dwFlagsMenuDisable = 0;
  971. DWORD dwFlagsMenuGray = 0;
  972. DWORD dwFlagsMenuChecked = 0;
  973. // Data validation
  974. ASSERT(pcmiReturned);
  975. ASSERT(pitem);
  976. ASSERT(pMenuItemSource);
  977. ASSERT(pfAllowed);
  978. // Set default
  979. *pfAllowed = TRUE;
  980. // Get the flags from the snapin item
  981. dwFlagsMenuDisable = pitem->DwFlagsMenuDisable();
  982. dwFlagsMenuGray = pitem->DwFlagsMenuGray();
  983. dwFlagsMenuChecked = pitem->DwFlagsMenuChecked();
  984. // Disabled means don't show at all. Not the same as MMC's MF_DISABLED.
  985. if (dwFlagsMenuDisable & pMenuItemSource->dwFlagsDisable)
  986. {
  987. *pfAllowed = FALSE;
  988. goto Cleanup;
  989. }
  990. // Check if the menu item should be allowed
  991. switch (pMenuItemSource->lInsertionPointID)
  992. {
  993. case CCM_INSERTIONPOINTID_PRIMARY_TOP:
  994. *pfAllowed = (lInsertionAllowed & CCM_INSERTIONALLOWED_TOP) != 0;
  995. break;
  996. case CCM_INSERTIONPOINTID_PRIMARY_NEW:
  997. case CCM_INSERTIONPOINTID_3RDPARTY_NEW:
  998. *pfAllowed = ((lInsertionAllowed & CCM_INSERTIONALLOWED_NEW) != 0) && pitem->FHasComponentData();
  999. break;
  1000. case CCM_INSERTIONPOINTID_PRIMARY_TASK:
  1001. case CCM_INSERTIONPOINTID_3RDPARTY_TASK:
  1002. *pfAllowed = (lInsertionAllowed & CCM_INSERTIONALLOWED_TASK) != 0;
  1003. break;
  1004. case CCM_INSERTIONPOINTID_PRIMARY_VIEW:
  1005. *pfAllowed = (lInsertionAllowed & CCM_INSERTIONALLOWED_VIEW) != 0;
  1006. break;
  1007. }
  1008. // If the menu item is not to be enabled, then discard
  1009. if (!*pfAllowed)
  1010. goto Cleanup;
  1011. // Set flags
  1012. if (dwFlagsMenuGray & pMenuItemSource->dwFlagsGray)
  1013. fFlags |= MF_GRAYED;
  1014. else
  1015. fFlags |= MF_ENABLED;
  1016. if (dwFlagsMenuChecked & pMenuItemSource->dwFlagsChecked)
  1017. fFlags |= MF_CHECKED;
  1018. else
  1019. fFlags |= MF_UNCHECKED;
  1020. // Set other parameters
  1021. if (pMenuItemSource->idsName)
  1022. pcmiReturned->strName.LoadString(_Module.GetResourceInstance(), pMenuItemSource->idsName);
  1023. if (pMenuItemSource->idsStatusBarText)
  1024. pcmiReturned->strStatusBarText.LoadString(_Module.GetResourceInstance(), pMenuItemSource->idsStatusBarText);
  1025. pcmiReturned->cm.strName = (LPWSTR)pcmiReturned->strName.data();
  1026. pcmiReturned->cm.strStatusBarText = (LPWSTR)pcmiReturned->strStatusBarText.data();
  1027. pcmiReturned->cm.lCommandID = pMenuItemSource->lCommandID;
  1028. pcmiReturned->cm.lInsertionPointID = pMenuItemSource->lInsertionPointID;
  1029. pcmiReturned->cm.fFlags = fFlags;
  1030. pcmiReturned->cm.fSpecialFlags = pMenuItemSource->fSpecialFlags;
  1031. Cleanup:
  1032. return sc;
  1033. }
  1034. // -----------------------------------------------------------------------------
  1035. // Load the icon for the snapin and return it to MMC.
  1036. //
  1037. SC CBaseSnapin::ScGetSnapinImage(HICON *phAppIcon)
  1038. {
  1039. SC sc ;
  1040. ASSERT(phAppIcon);
  1041. if (phAppIcon == NULL)
  1042. {
  1043. sc = E_INVALIDARG;
  1044. goto Error;
  1045. }
  1046. if (Idi() == 0)
  1047. {
  1048. // There is no icon for this snapin
  1049. *phAppIcon = NULL;
  1050. goto Cleanup;
  1051. }
  1052. *phAppIcon = ::LoadIcon(_Module.GetModuleInstance(), MAKEINTRESOURCE(Idi()));
  1053. if (*phAppIcon == NULL)
  1054. {
  1055. sc = ScFromWin32(GetLastError());
  1056. goto Error;
  1057. }
  1058. Cleanup:
  1059. return sc;
  1060. Error:
  1061. TraceError(_T("CBaseSnapin::ScGetSnapinImage"), sc);
  1062. goto Cleanup;
  1063. }
  1064. // -----------------------------------------------------------------------------
  1065. // Release the given item, but only if it is one of the root items.
  1066. // Used during MMCN_REMOVE_CHILDREN. We are being told that the item
  1067. // that we are "ghosting" is either being destroyed or all of its children
  1068. // are being destroyed. In either case, we don't need the ghost item
  1069. // anymore.
  1070. //
  1071. SC CBaseSnapin::ScReleaseIfRootItem(CBaseSnapinItem *pitem)
  1072. {
  1073. SC sc ;
  1074. ItemList::iterator iter;
  1075. ASSERT(pitem);
  1076. for (iter = m_ilRootItems.begin(); iter != m_ilRootItems.end(); iter++)
  1077. {
  1078. if (pitem == (*iter))
  1079. {
  1080. m_ilRootItems.erase(iter);
  1081. static_cast<LPDATAOBJECT>(pitem)->Release();
  1082. break;
  1083. }
  1084. }
  1085. return sc;
  1086. }
  1087. // -----------------------------------------------------------------------------
  1088. // Determines whether the specified dataobject is pastable.
  1089. //
  1090. SC
  1091. CBaseSnapin::ScIsPastableDataObject(CBaseSnapinItem * pitemTarget, LPDATAOBJECT lpDataObject, BOOL * pfPastable)
  1092. {
  1093. // Declarations
  1094. SC sc ;
  1095. BOOL fPastable = FALSE;
  1096. CNodeType * pnodetype = NULL;
  1097. CLSID clsid;
  1098. INT isnr = 0;
  1099. // Validate parameters
  1100. ASSERT(pitemTarget);
  1101. ASSERT(lpDataObject);
  1102. ASSERT(pfPastable);
  1103. // Is this an MMC node?
  1104. // Get the nodetype, in guid format, of the data object.
  1105. sc = CBaseDataObject::ScGetNodeType(lpDataObject, &clsid);
  1106. if (sc == DV_E_FORMATETC || sc == E_NOTIMPL)
  1107. {
  1108. // Not an MMC Node
  1109. fPastable = FALSE;
  1110. sc = S_FALSE; // override the execution code
  1111. goto Cleanup;
  1112. }
  1113. if (sc)
  1114. goto Error;
  1115. // Verify that the snapin item class type is acceptable to the destination
  1116. for (isnr=0; isnr < Csnr(); isnr++)
  1117. {
  1118. // Find a class id match
  1119. if (IsEqualCLSID(*(Psnr(isnr)->pnodetype->PclsidNodeType()), clsid)) // found the CLSID
  1120. {
  1121. // SNR verification
  1122. SNRTypes snrtypes = Psnr(isnr)->snrtypes;
  1123. // $REVIEW (ptousig) So all nodes are pastable ? Sounds to me like
  1124. // snrEnumSP and snrEnumRP shouldn't be in here.
  1125. if ( (snrtypes & snrEnumSP) || (snrtypes & snrEnumRP) || (snrtypes & snrPaste))
  1126. fPastable = TRUE;
  1127. break; // exit the loop.
  1128. }
  1129. }
  1130. // If it seems we can paste, ask the target item if we can paste here
  1131. if (fPastable)
  1132. {
  1133. sc = pitemTarget->ScOnQueryPaste(lpDataObject, &fPastable);
  1134. if (sc)
  1135. goto Error;
  1136. }
  1137. Cleanup:
  1138. // Assign result
  1139. *pfPastable = fPastable;
  1140. return sc;
  1141. Error:
  1142. fPastable = FALSE;
  1143. TraceError(_T("CBaseSnapin::ScIsPastableDataObject()"), sc);
  1144. goto Cleanup;
  1145. }
  1146. // -----------------------------------------------------------------------------
  1147. // Find out which verb should be the default.
  1148. //
  1149. MMC_CONSOLE_VERB CBaseSnapin::MmcverbDefault(LPDATAOBJECT lpDataObject)
  1150. {
  1151. // Ask the item.
  1152. return Pitem(lpDataObject)->MmcverbDefault();
  1153. }
  1154. // -----------------------------------------------------------------------------
  1155. // Find out the verbs that are allowed on this item.
  1156. //
  1157. SC CBaseSnapin::ScGetVerbs(LPDATAOBJECT lpDataObject, DWORD * pdwVerbs)
  1158. {
  1159. // Ask the item.
  1160. return Pitem(lpDataObject)->ScGetVerbs(pdwVerbs);
  1161. }
  1162. // -----------------------------------------------------------------------------
  1163. // Returns the path to the help file for this snapin.
  1164. //
  1165. SC CBaseSnapin::ScGetHelpTopic(tstring& strCompiledHelpFile)
  1166. {
  1167. DECLARE_SC(sc, _T("CBaseSnapin::ScGetHelpTopic"));
  1168. DWORD dwLen = 0;
  1169. const int cchMaxLen = 256;
  1170. TCHAR szFileName[cchMaxLen];
  1171. //
  1172. // Get the full path to the current module
  1173. //
  1174. dwLen = ::GetModuleFileName(_Module.GetModuleInstance() , szFileName, cchMaxLen);
  1175. if (dwLen == 0)
  1176. return (ScFromWin32(GetLastError()));
  1177. strCompiledHelpFile = szFileName;
  1178. //
  1179. // Replace the extension with .CHM
  1180. //
  1181. int nDotPos = strCompiledHelpFile.rfind(_T("."));
  1182. strCompiledHelpFile.erase(nDotPos);
  1183. strCompiledHelpFile += _T(".CHM");
  1184. return sc;
  1185. }
  1186. // -----------------------------------------------------------------------------
  1187. // We are being told that something has changed on the item pointed
  1188. // by lParam.
  1189. //
  1190. SC CBaseSnapin::ScOnPropertyChange(BOOL fScope, LPARAM lParam, IConsoleNameSpace *ipConsoleNameSpace, IConsole *ipConsole)
  1191. {
  1192. SC sc ;
  1193. LPDATAOBJECT pdataobject = NULL;
  1194. CBaseSnapinItem * pitem = NULL;
  1195. pdataobject = reinterpret_cast<LPDATAOBJECT>(lParam);
  1196. ASSERT(pdataobject);
  1197. pitem = Pitem(pdataobject);
  1198. ASSERT(pitem);
  1199. sc = pitem->ScOnPropertyChange();
  1200. if (sc)
  1201. goto Error;
  1202. if (pitem->FIsContainer())
  1203. {
  1204. // Container items should be updated just once.
  1205. sc = pitem->ScUpdateScopeItem(ipConsoleNameSpace);
  1206. if (sc)
  1207. goto Error;
  1208. }
  1209. else
  1210. {
  1211. // Result item. Need to update the item in all views.
  1212. // Call out to all the views to update themselves.
  1213. sc = ipConsole->UpdateAllViews(pdataobject, 0, ONVIEWCHANGE_UPDATERESULTITEM);
  1214. if (sc)
  1215. goto Error;
  1216. }
  1217. Cleanup:
  1218. return sc;
  1219. Error:
  1220. TraceError(_T("CBaseSnapin::ScOnPropertyChange"), sc);
  1221. goto Cleanup;
  1222. }
  1223. // -----------------------------------------------------------------------------
  1224. // The user has changed the name of an item.
  1225. //
  1226. SC CBaseSnapin::ScOnRename(LPDATAOBJECT lpDataObject, const tstring& strNewName, IConsole *ipConsole)
  1227. {
  1228. SC sc= S_FALSE;
  1229. CBaseSnapinItem *pitem = NULL;
  1230. ASSERT(lpDataObject);
  1231. pitem = Pitem(lpDataObject);
  1232. ASSERT(pitem);
  1233. if (strNewName.empty())
  1234. {
  1235. // ScOnQueryPaste should prevent this from ever happening
  1236. sc = E_UNEXPECTED;
  1237. goto Error;
  1238. }
  1239. if (strNewName.length() == 0)
  1240. goto Cleanup;
  1241. // Tell the object to rename
  1242. // If it returns S_FALSE, the rename was not done.
  1243. sc = pitem->ScOnRename(strNewName);
  1244. if (sc)
  1245. goto Error;
  1246. if (sc == S_OK)
  1247. {
  1248. // If this was renamed, reload our children
  1249. sc = ipConsole->UpdateAllViews(static_cast<IDataObject *>(pitem), 0, ONVIEWCHANGE_REFRESHCHILDREN);
  1250. if (sc)
  1251. goto Error;
  1252. }
  1253. Cleanup:
  1254. return sc;
  1255. Error:
  1256. TraceError(_T("CBaseSnapin::ScOnRename"), sc);
  1257. goto Cleanup;
  1258. }
  1259. // -----------------------------------------------------------------------------
  1260. // Received on a paste command.
  1261. //
  1262. // lpDataObject is the node receiving the past command.
  1263. // lpDataObjectList are the nodes being pasted.
  1264. // ppDataObjectPasted is where we answer the list of nodes that were successfully pasted.
  1265. //
  1266. SC CBaseSnapin::ScOnPaste(LPDATAOBJECT lpDataObject, LPDATAOBJECT lpDataObjectList, LPDATAOBJECT * ppDataObjectPasted, IConsole * ipConsole)
  1267. {
  1268. // Declarations
  1269. SC sc ;
  1270. CBaseSnapinItem * pitemTarget = NULL;
  1271. DWORD dwCanCopyCut = 0;
  1272. BOOL fPasted = FALSE;
  1273. CBaseMultiSelectSnapinItem * pBaseMultiSelectSnapinItem = NULL;
  1274. // Handle special case
  1275. if (!lpDataObjectList)
  1276. {
  1277. // ScOnQueryPaste should prevent this from ever happening
  1278. sc = E_UNEXPECTED;
  1279. goto Error;
  1280. }
  1281. // Data validation
  1282. ASSERT(lpDataObject);
  1283. ASSERT(lpDataObjectList);
  1284. ASSERT(ipConsole);
  1285. // other parameters can not be ASSERTed
  1286. // Get the target item
  1287. pitemTarget = Pitem(lpDataObject);
  1288. ASSERT(pitemTarget);
  1289. // Determine if this is a multiselect data object
  1290. sc = CBaseMultiSelectSnapinItem::ScGetMultiSelectDataObject(lpDataObjectList, &pBaseMultiSelectSnapinItem);
  1291. if (sc)
  1292. goto Error;
  1293. // If we received a multiselect snapin item
  1294. if (pBaseMultiSelectSnapinItem)
  1295. {
  1296. // Call ScOnPaste for the multiselect object for dispatch
  1297. sc = pBaseMultiSelectSnapinItem->ScOnPaste(this, pitemTarget, lpDataObjectList, ppDataObjectPasted, ipConsole);
  1298. if (sc)
  1299. goto Error;
  1300. }
  1301. else
  1302. {
  1303. // Ask the item to copy the underlying object
  1304. sc = pitemTarget->ScOnPaste(lpDataObjectList, ppDataObjectPasted ? TRUE : FALSE, &fPasted);
  1305. if (sc)
  1306. goto Error;
  1307. // If the object was pasted
  1308. if (fPasted)
  1309. {
  1310. // If this was a cut, we need to return to MMC the items that were pasted
  1311. // (do not delete the dropped item if we are just adding it to a policy)
  1312. if (ppDataObjectPasted && !pitemTarget->FIsPolicy())
  1313. {
  1314. *ppDataObjectPasted = lpDataObjectList;
  1315. (*ppDataObjectPasted)->AddRef();
  1316. }
  1317. // Reload our children
  1318. sc = ipConsole->UpdateAllViews(static_cast<IDataObject *>(pitemTarget), 0, ONVIEWCHANGE_REFRESHCHILDREN);
  1319. if (sc)
  1320. goto Error;
  1321. }
  1322. }
  1323. Cleanup:
  1324. return sc;
  1325. Error:
  1326. TraceError(_T("CBaseSnapin::ScOnPaste"), sc);
  1327. goto Cleanup;
  1328. }
  1329. // -----------------------------------------------------------------------------
  1330. // We need to figure out whether we will allow pasting of this object.
  1331. // lpDataObject is the target object.
  1332. // lpDataObjectList are the objects being pasted.
  1333. //
  1334. SC CBaseSnapin::ScOnQueryPaste(LPDATAOBJECT lpDataObject, LPDATAOBJECT lpDataObjectList, LPDWORD pdwFlags)
  1335. {
  1336. // Declarations
  1337. SC sc ;
  1338. CBaseSnapinItem * pitemTarget = NULL;
  1339. BOOL fCanPaste = FALSE;
  1340. CNodeType * pnodetype = NULL;
  1341. CBaseMultiSelectSnapinItem * pBaseMultiSelectSnapinItem = NULL;
  1342. // Data validation
  1343. ASSERT(lpDataObject);
  1344. ASSERT(lpDataObjectList);
  1345. ASSERT(pdwFlags);
  1346. // Get the target item
  1347. pitemTarget = Pitem(lpDataObject);
  1348. ASSERT(pitemTarget);
  1349. // Determine if this is a multiselect data object
  1350. // Determine if this is a multiselect data object
  1351. sc = CBaseMultiSelectSnapinItem::ScGetMultiSelectDataObject(lpDataObjectList, &pBaseMultiSelectSnapinItem);
  1352. if (sc == SC(DV_E_FORMATETC) )
  1353. {
  1354. sc = S_FALSE; // Cant paste.
  1355. return sc;
  1356. }
  1357. if (sc)
  1358. goto Error;
  1359. // If we received a multiselect snapin item
  1360. if (pBaseMultiSelectSnapinItem)
  1361. {
  1362. // Call ScOnCutOrMove for the multiselect object for dispatch
  1363. sc = pBaseMultiSelectSnapinItem->ScIsPastableDataObject(this, pitemTarget, lpDataObjectList, &fCanPaste);
  1364. if (sc)
  1365. goto Error;
  1366. }
  1367. else
  1368. {
  1369. // Determine if the parse operation is acceptable
  1370. // Here lpDataObjectList is only one item
  1371. sc = ScIsPastableDataObject(pitemTarget, lpDataObjectList, &fCanPaste);
  1372. if (sc)
  1373. goto Error;
  1374. }
  1375. // Determine if we can paste
  1376. if (!fCanPaste)
  1377. sc = S_FALSE; // indicate no pasting
  1378. Cleanup:
  1379. return sc;
  1380. Error:
  1381. TraceError(_T("CBaseSnapin::ScOnQueryPaste()"), sc);
  1382. goto Cleanup;
  1383. }
  1384. // -----------------------------------------------------------------------------
  1385. // We need to figure out whether we can handle the given dataobject that is from
  1386. // different process.
  1387. // lpDataObject is the target object.
  1388. // lpDataObjectList are the objects being pasted.
  1389. //
  1390. SC CBaseSnapin::ScOnCanPasteOutOfProcDataObject(LPBOOL pbCanHandle)
  1391. {
  1392. // Declarations
  1393. DECLARE_SC(sc, TEXT("CBaseSnapin::ScOnCanPasteOutOfProcDataObject"));
  1394. sc = ScCheckPointers(pbCanHandle);
  1395. if (sc)
  1396. return sc;
  1397. *pbCanHandle = TRUE;
  1398. return sc;
  1399. }
  1400. // -----------------------------------------------------------------------------
  1401. SC CBaseSnapin::ScOnCutOrMove(LPDATAOBJECT lpDataObjectList, IConsoleNameSpace * ipConsoleNameSpace, IConsole * ipConsole)
  1402. {
  1403. // Declarations
  1404. SC sc ;
  1405. CBaseSnapinItem * pitem = NULL;
  1406. CBaseMultiSelectSnapinItem * pBaseMultiSelectSnapinItem = NULL;
  1407. // Data validation
  1408. ASSERT(lpDataObjectList);
  1409. ASSERT(ipConsoleNameSpace);
  1410. ASSERT(ipConsole);
  1411. // Determine if this is a multiselect data object
  1412. sc = CBaseMultiSelectSnapinItem::ScGetMultiSelectDataObject(lpDataObjectList, &pBaseMultiSelectSnapinItem);
  1413. if (sc)
  1414. goto Error;
  1415. // If we received a multiselect snapin item
  1416. if (pBaseMultiSelectSnapinItem)
  1417. {
  1418. // Call ScOnCutOrMove for the multiselect object for dispatch
  1419. sc = pBaseMultiSelectSnapinItem->ScOnCutOrMove(this, lpDataObjectList, ipConsoleNameSpace, ipConsole);
  1420. if (sc)
  1421. goto Error;
  1422. }
  1423. else
  1424. {
  1425. // Handle the normal case - PItem() does more work than a simple cast to verify that the snapin item belongs to the snapin etc.
  1426. pitem = Pitem(lpDataObjectList);
  1427. ASSERT(pitem);
  1428. // Ask the item to delete the underlying object.
  1429. sc = pitem->ScOnCutOrMove();
  1430. if (sc)
  1431. goto Error;
  1432. if (sc == S_FALSE)
  1433. goto Cleanup;
  1434. if (pitem->FIsContainer())
  1435. {
  1436. // Container items need to be deleted from the document
  1437. // Delete the item and everything below it.
  1438. if (pitem->Hscopeitem())
  1439. {
  1440. sc = ipConsoleNameSpace->DeleteItem(pitem->Hscopeitem(), TRUE);
  1441. if (sc)
  1442. goto Error;
  1443. pitem->SetHscopeitem(0);
  1444. }
  1445. }
  1446. else
  1447. {
  1448. // Leaf items need to be deleted from the views.
  1449. sc = ipConsole->UpdateAllViews(lpDataObjectList, 0, ONVIEWCHANGE_DELETESINGLEITEM);
  1450. if (sc)
  1451. goto Error;
  1452. }
  1453. // Delete this item, MMC is still using it. Below ScDeleteSubTree
  1454. // will release the object so Addref it. We got this through
  1455. // the Pitem() call which just type cast the dataobject.
  1456. pitem->AddRef();
  1457. sc = pitem->ScDeleteSubTree(TRUE);
  1458. if (sc)
  1459. goto Error;
  1460. }
  1461. Cleanup:
  1462. return sc;
  1463. Error:
  1464. TraceError(_T("CBaseSnapin::ScOnCutOrMove"), sc);
  1465. goto Cleanup;
  1466. }
  1467. // -----------------------------------------------------------------------------
  1468. // This method allows a CComponentData to tell us it is being
  1469. // destroyed. Any item referring to this CD as its owner will
  1470. // have their owner pointer nulled.
  1471. SC CBaseSnapin::ScOwnerDying(CComponentData *pComponentData)
  1472. {
  1473. ItemList::iterator iter;
  1474. for (iter = m_ilRootItems.begin(); iter != m_ilRootItems.end(); iter++)
  1475. {
  1476. if ((*iter)->FHasComponentData() && (*iter)->PComponentData() == pComponentData)
  1477. (*iter)->SetComponentData(NULL);
  1478. }
  1479. return S_OK;
  1480. }