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.

2204 lines
81 KiB

  1. /*
  2. * snapinitem.cxx
  3. *
  4. *
  5. * Copyright (c) 1998-1999 Microsoft Corporation
  6. *
  7. * PURPOSE: Defines the CSnapinItem class.
  8. *
  9. *
  10. * OWNER: ptousig
  11. */
  12. #include <headers.hxx>
  13. #include <atlhost.h>
  14. // class CBaseSnapinItem
  15. // -----------------------------------------------------------------------------
  16. CBaseSnapinItem::CBaseSnapinItem()
  17. {
  18. Trace(tagBaseSnapinItemTracker, _T("0x%08lX: %S: Creation"), this, SzGetSnapinItemClassName());
  19. m_type = CCT_UNINITIALIZED;
  20. m_hscopeitem = 0;
  21. m_pComponentData = NULL;
  22. m_pitemParent = NULL;
  23. m_pitemNext = NULL;
  24. m_pitemPrevious = NULL;
  25. m_pitemChild = NULL;
  26. m_fInserted = FALSE;
  27. m_fIsRoot = FALSE;
  28. m_fIsGhostRoot = FALSE;
  29. m_fWasExpanded = FALSE;
  30. }
  31. // -----------------------------------------------------------------------------
  32. // Cleans up the subtree below the item.
  33. //
  34. CBaseSnapinItem::~CBaseSnapinItem()
  35. {
  36. // Declarations
  37. SC sc = S_OK;
  38. // Do not do anything below if the object is a multiselect data object.
  39. // We can not call FIsMultiSelectDataObject(). Use another criteria.
  40. // $REVIEW (dominicp) Is it possible to have a type set to CCT_UNINITIALIZED and not be a multiselect snapin item?
  41. if (CCT_UNINITIALIZED != m_type)
  42. {
  43. Trace(tagBaseSnapinItemTracker, _T("0x%08lX: %S: Destroyed"), this, SzGetSnapinItemClassName());
  44. sc = ScDeleteSubTree(FALSE);
  45. if (sc)
  46. goto Error;
  47. // Remove the item from the tree.
  48. Unlink();
  49. // The Pcookielist is in CBaseSnapin.
  50. if (Psnapin())
  51. {
  52. // Root nodes do not addref the frame and so should not release them.
  53. if (FIsRoot() == FALSE)
  54. {
  55. // Remove the cookie from the list of available cookies.
  56. Pcookielist()->erase(Cookie());
  57. }
  58. }
  59. }
  60. Cleanup:
  61. return;
  62. Error:
  63. sc.Throw ();
  64. goto Cleanup;
  65. }
  66. // -----------------------------------------------------------------------------
  67. // Set the HSCOPEITEM of this node.
  68. //
  69. void CBaseSnapinItem::SetHscopeitem(HSCOPEITEM hscopeitem)
  70. {
  71. // If we already have a HSCOPEITEM, we don't want it to change.
  72. ASSERT(m_hscopeitem == 0 || hscopeitem == 0 || m_hscopeitem == hscopeitem);
  73. m_hscopeitem = hscopeitem;
  74. }
  75. // -----------------------------------------------------------------------------
  76. // This is the CCF_DISPLAY_NAME clipboard format.
  77. //
  78. SC CBaseSnapinItem::ScWriteDisplayName(IStream *pstream)
  79. {
  80. SC sc = S_OK;
  81. ASSERT(PstrDisplayName());
  82. sc = pstream->Write(PstrDisplayName()->data(), (PstrDisplayName()->length()+1)*sizeof(TCHAR), NULL);
  83. if (sc)
  84. goto Error;
  85. Cleanup:
  86. return sc;
  87. Error:
  88. TraceError(_T("CBaseSnapinItem::ScWriteDisplayName"), sc);
  89. goto Cleanup;
  90. }
  91. SC CBaseSnapinItem::ScWriteAnsiName(IStream *pStream )
  92. {
  93. SC sc = S_OK;
  94. ASSERT(PstrDisplayName());
  95. USES_CONVERSION;
  96. sc = pStream->Write( T2A(PstrDisplayName()->data()), (PstrDisplayName()->length()+1), NULL);
  97. if (sc)
  98. goto Error;
  99. Cleanup:
  100. return sc;
  101. Error:
  102. TraceError(_T("CBaseSnapinItem::ScWriteAnsiName"), sc);
  103. goto Cleanup;
  104. }
  105. // -----------------------------------------------------------------------------
  106. // Write the Node type's GUID out to a stream in CLSID form.
  107. // This is the CCF_NODETYPE clipboard format.
  108. //
  109. SC CBaseSnapinItem::ScWriteNodeType(IStream *pstream)
  110. {
  111. return pstream->Write(Pnodetype()->PclsidNodeType(), sizeof(CLSID), NULL);
  112. }
  113. // -----------------------------------------------------------------------------
  114. // Write a unique ID to represent this node. This implementation uses the 'this'
  115. // pointer. A SNodeID is simply a blob prefixed by its length (as a DWORD).
  116. //
  117. SC CBaseSnapinItem::ScWriteNodeID(IStream *pstream)
  118. {
  119. SC sc = S_OK;
  120. CBaseSnapinItem *pitemThis = this;
  121. DWORD dwSize = sizeof(pitemThis);
  122. // Write the size of the data
  123. sc = pstream->Write(&dwSize, sizeof(dwSize), NULL);
  124. if (sc)
  125. goto Error;
  126. // Write the data itself.
  127. sc = pstream->Write(&pitemThis, sizeof(pitemThis), NULL);
  128. if (sc)
  129. goto Error;
  130. Cleanup:
  131. return sc;
  132. Error:
  133. TraceError(_T("CBaseSnapinItem::ScWriteNodeID"), sc);
  134. goto Cleanup;
  135. }
  136. // -----------------------------------------------------------------------------
  137. // Write the Node type's Column Set ID. We use the node guid
  138. // as a default implementation.
  139. //
  140. SC CBaseSnapinItem::ScWriteColumnSetId(IStream *pstream)
  141. {
  142. SC sc = S_OK;
  143. DWORD dwFlags = 0;
  144. DWORD dwSize = sizeof(GUID);
  145. // write out an MMC SColumnSetID structure
  146. sc = pstream->Write(&dwFlags, sizeof(dwFlags), NULL);
  147. if (sc)
  148. goto Error;
  149. sc = pstream->Write(&dwSize, sizeof(dwSize), NULL);
  150. if (sc)
  151. goto Error;
  152. sc = pstream->Write(Pnodetype()->PclsidNodeType(), sizeof(GUID), NULL);
  153. if (sc)
  154. goto Error;
  155. Cleanup:
  156. return sc;
  157. Error:
  158. TraceError(_T("CBaseSnapinItem::ScWriteColumnSetId"), sc);
  159. goto Cleanup;
  160. }
  161. // -----------------------------------------------------------------------------
  162. // Write the HSCOPEITEM of this node out to a stream.
  163. // This is the CF_EXCHANGE_ADMIN_HSCOPEITEM clipboard format.
  164. //
  165. SC CBaseSnapinItem::ScWriteAdminHscopeitem(IStream *pstream)
  166. {
  167. return pstream->Write(&m_hscopeitem, sizeof(m_hscopeitem), NULL);
  168. }
  169. // -----------------------------------------------------------------------------
  170. // Write the class ID of the Snapin out to a stream.
  171. // This is the CCF_SNAPIN_CLASSID clipboard format.
  172. //
  173. SC CBaseSnapinItem::ScWriteClsid(IStream *pstream)
  174. {
  175. return pstream->Write(PclsidSnapin(), sizeof(CLSID), NULL);
  176. }
  177. // -----------------------------------------------------------------------------
  178. // Returns the snapin to which this item belongs.
  179. //
  180. CBaseSnapin *CBaseSnapinItem::Psnapin(void)
  181. {
  182. return m_pSnapin;
  183. }
  184. // -----------------------------------------------------------------------------
  185. // Get an IConsole interface.
  186. // It is possible that this item is not associated with a ComponentData. We
  187. // cannot ASSERT in this case, because in many situations we don't mind if it's NULL.
  188. // Without an ASSERT, the worst that will happen is that you will hit an AV
  189. // (which would happen in retail builds anyway) and that is as easy to debug as
  190. // an ASSERT.
  191. //
  192. IConsole *CBaseSnapinItem::IpConsole(void)
  193. {
  194. if (m_pComponentData)
  195. return m_pComponentData->IpConsole();
  196. else
  197. return NULL;
  198. }
  199. // -----------------------------------------------------------------------------
  200. // Get an IPropertySheetProvider interface.
  201. //
  202. IPropertySheetProvider *CBaseSnapinItem::IpPropertySheetProvider(void)
  203. {
  204. ASSERT(m_pComponentData);
  205. return m_pComponentData->IpPropertySheetProvider();
  206. }
  207. // -----------------------------------------------------------------------------
  208. // Get the CComponentData that is associated with this node.
  209. //
  210. CComponentData *CBaseSnapinItem::PComponentData(void)
  211. {
  212. ASSERT(m_pComponentData);
  213. return m_pComponentData;
  214. }
  215. // -----------------------------------------------------------------------------
  216. // Set the given CComponentData as the "owner" of this node.
  217. //
  218. void CBaseSnapinItem::SetComponentData(CComponentData *pComponentData)
  219. {
  220. if (pComponentData == NULL)
  221. {
  222. // We are being told to forget our owner
  223. m_pComponentData = NULL;
  224. }
  225. else if (pComponentData->FIsRealComponentData())
  226. {
  227. // Once the "real" owner is set, it shouldn't be changed.
  228. ASSERT(m_pComponentData == NULL || m_pComponentData == pComponentData);
  229. m_pComponentData = pComponentData;
  230. }
  231. }
  232. // -----------------------------------------------------------------------------
  233. // Is the given item one of the children of this node.
  234. //
  235. BOOL CBaseSnapinItem::FIncludesChild(CBaseSnapinItem *pitem)
  236. {
  237. CBaseSnapinItem *pitemIter = PitemChild();
  238. while (pitemIter)
  239. {
  240. if (pitemIter == pitem)
  241. return TRUE;
  242. pitemIter = pitemIter->PitemNext();
  243. }
  244. return FALSE;
  245. }
  246. // -----------------------------------------------------------------------------
  247. // Add a child to this node.
  248. //
  249. SC CBaseSnapinItem::ScAddChild(CBaseSnapinItem *pitem)
  250. {
  251. SC sc = S_OK;
  252. CBaseSnapinItem *pitemPrevious = NULL;
  253. pitemPrevious = PitemChild();
  254. if (pitemPrevious)
  255. {
  256. while (pitemPrevious->PitemNext())
  257. pitemPrevious = pitemPrevious->PitemNext();
  258. pitemPrevious->SetNext(pitem);
  259. pitem->m_pitemParent = this;
  260. // Successfully inserted.
  261. }
  262. else
  263. {
  264. // First child item
  265. SetChild(pitem);
  266. }
  267. return sc;
  268. }
  269. // -----------------------------------------------------------------------------
  270. // This node will be used to represent another node (aka Ghost root node).
  271. // We don't own the other node, it might not even be from this DLL, the only
  272. // information we can get about this other node has to come from clipboard
  273. // data from the provided 'lpDataObject'.
  274. //
  275. SC CBaseSnapinItem::ScInitializeNamespaceExtension(LPDATAOBJECT lpDataObject, HSCOPEITEM item, CNodeType *pnodetype)
  276. {
  277. return S_OK;
  278. }
  279. // -----------------------------------------------------------------------------
  280. // Called to ask this node to create its children.
  281. //
  282. SC CBaseSnapinItem::ScCreateChildren(void)
  283. {
  284. return S_OK;
  285. }
  286. // -----------------------------------------------------------------------------
  287. // Removes an item from the linked list. Links up the previous and next items,
  288. // if any. If this is the first item in the list, set the parent's child pointer
  289. // to the next item (if it exists.)
  290. //
  291. void CBaseSnapinItem::Unlink()
  292. {
  293. // Make sure that this item has no children. Wouldn't know what to do with them.
  294. ASSERT(PitemChild() == NULL);
  295. // A real clear way of checking all cases: 8 in all.
  296. if (PitemPrevious())
  297. {
  298. if (PitemParent())
  299. {
  300. if (PitemNext()) // PitemPrevious() && PitemParent() && PitemNext()
  301. PitemPrevious()->SetNext(PitemNext());
  302. else // PitemPrevious() && PitemParent() && !PitemNext()
  303. PitemPrevious()->SetNext(NULL);
  304. }
  305. else // !PitemParent()
  306. {
  307. if (PitemNext()) // PitemPrevious() && !PitemParent() && PitemNext()
  308. PitemPrevious()->SetNext(PitemNext());
  309. else // PitemPrevious() && !PitemParent() && !PitemNext()
  310. PitemPrevious()->SetNext(NULL);
  311. }
  312. }
  313. else // !PitemPrevious() - this is the first item in the list.
  314. {
  315. if (PitemParent())
  316. {
  317. if (PitemNext()) // !PitemPrevious() && PitemParent() && PitemNext()
  318. {
  319. PitemParent()->SetChild(PitemNext());
  320. PitemNext()->SetPrevious(NULL);
  321. }
  322. else // !PitemPrevious() && PitemParent() && !PitemNext()
  323. {
  324. // Set the Parent's Child pointer to NULL if we are the (only) child of the parent.
  325. if (PitemParent()->PitemChild() == static_cast<CBaseSnapinItem*>(this))
  326. PitemParent()->SetChild(NULL);
  327. }
  328. }
  329. else // !PitemParent()
  330. {
  331. if (PitemNext()) // !PitemPrevious() && !PitemParent() && PitemNext()
  332. PitemNext()->SetPrevious(NULL);
  333. else // !PitemPrevious() && !PitemParent() && !PitemNext()
  334. ; // do nothing - already an orphan.
  335. }
  336. }
  337. // Clear all the link pointers.
  338. SetNext(NULL);
  339. SetPrevious(NULL);
  340. // Can't use SetParent() because it ASSERTs.
  341. m_pitemParent = NULL;
  342. }
  343. // -----------------------------------------------------------------------------
  344. // Initializes the snapinitem.
  345. //
  346. // The 'pcolinfoex' and 'ccolinfoex' are no longer used. The derived class is
  347. // now responsible for maintaining per-item column information. The default
  348. // implementation of the accessors will get the column information from the
  349. // CBaseSnapin-derived class.
  350. //
  351. SC CBaseSnapinItem::ScInit(CBaseSnapin *pSnapin, CColumnInfoEx *pcolinfoex, INT ccolinfoex, BOOL fIsRoot)
  352. {
  353. SC sc = S_OK;
  354. m_pSnapin = pSnapin;
  355. m_fIsRoot = fIsRoot;
  356. // Add the cookie to the list of available cookies.
  357. pSnapin->Pcookielist()->insert(Cookie());
  358. return sc;
  359. }
  360. // -----------------------------------------------------------------------------
  361. // Initializes a child item.
  362. //
  363. SC CBaseSnapinItem::ScInitializeChild(CBaseSnapinItem* pitem)
  364. {
  365. return pitem->ScInit(Psnapin(), NULL, 0);
  366. }
  367. // -----------------------------------------------------------------------------
  368. // Information obtained from Psnapin().
  369. //
  370. const tstring& CBaseSnapinItem::StrClassName(void) { return Psnapin()->StrClassName();}
  371. const CLSID * CBaseSnapinItem::PclsidSnapin(void) { return Psnapin()->PclsidSnapin();}
  372. const tstring& CBaseSnapinItem::StrClsidSnapin(void) { return Psnapin()->StrClsidSnapin();}
  373. WTL::CBitmap* CBaseSnapinItem::PbitmapImageListSmall(void) { return Psnapin()->PbitmapImageListSmall();}
  374. WTL::CBitmap* CBaseSnapinItem::PbitmapImageListLarge(void) { return Psnapin()->PbitmapImageListLarge();}
  375. CCookieList * CBaseSnapinItem::Pcookielist(void) { return Psnapin()->Pcookielist();}
  376. // -----------------------------------------------------------------------------
  377. // Deletes the entire subtree rooted at this node, thereby freeing up all the cookies.
  378. // If fDeleteRoot is TRUE we need to delete the root node as well.
  379. //
  380. SC CBaseSnapinItem::ScDeleteSubTree(BOOL fDeleteRoot)
  381. {
  382. SC sc = S_OK;
  383. CBaseSnapinItem * pitem = PitemChild();
  384. CBaseSnapinItem * pitemNext = NULL;
  385. while (pitem)
  386. {
  387. // We are about to delete 'pitem', keep a pointer to the next one.
  388. pitemNext = pitem->PitemNext();
  389. // Delete the entire subtree including the root node.
  390. sc = pitem->ScDeleteSubTree(TRUE);
  391. if (sc)
  392. goto Error;
  393. pitem = pitemNext;
  394. }
  395. // We don't have any children left.
  396. m_pitemChild = NULL;
  397. m_fWasExpanded = FALSE;
  398. // if we have not removed the scope item, do it now
  399. if (fDeleteRoot)
  400. {
  401. if (m_hscopeitem)
  402. {
  403. sc = PComponentData()->IpConsoleNameSpace()->DeleteItem(m_hscopeitem, TRUE);
  404. if (sc)
  405. goto Error;
  406. }
  407. Unlink();
  408. // Since we are no longer known by MMC we have to forget our HSCOPEITEM
  409. // so that it doesn't get mis-used. This can happen if you refresh a parent
  410. // of a node that has properties open.
  411. m_hscopeitem = 0;
  412. static_cast<IDataObject *>(this)->Release();
  413. }
  414. Cleanup:
  415. return sc;
  416. Error:
  417. TraceError(_T("CBaseSnapinItem::ScDeleteSubTree"), sc);
  418. goto Cleanup;
  419. }
  420. // -----------------------------------------------------------------------------
  421. // Get the root of this item tree.
  422. //
  423. CBaseSnapinItem *CBaseSnapinItem::PitemRoot(void)
  424. {
  425. if (m_pitemParent)
  426. return m_pitemParent->PitemRoot();
  427. else
  428. return this;
  429. }
  430. // -----------------------------------------------------------------------------
  431. // We are the data object. We just return a pointer to the IDataObject of
  432. // ourselves.
  433. //
  434. SC CBaseSnapinItem::ScQueryDataObject(long cookie, DATA_OBJECT_TYPES type, LPDATAOBJECT* ppDataObject)
  435. {
  436. SC sc = S_OK;
  437. //
  438. // The item will remember what type it is at the moment.
  439. //
  440. m_type = type;
  441. //
  442. // This seems like a very twisted way of getting a pointer to ourselves,
  443. // but it is actualy because we want to make sure we play within ATL rules.
  444. // In a way, QueryDataObject is the same thing as a QueryInterface.
  445. //
  446. sc = static_cast<IDataObject *>(this)->QueryInterface(IID_IDataObject, reinterpret_cast<void**>(ppDataObject));
  447. if (sc)
  448. goto Error;
  449. Cleanup:
  450. return sc;
  451. Error:
  452. TraceError(_T("CBaseSnapinItem::ScQueryDataObject"), sc);
  453. goto Cleanup;
  454. }
  455. // -----------------------------------------------------------------------------
  456. // Handles the MMCN_SHOW notification. Initializes the default result view headers.
  457. //
  458. SC CBaseSnapinItem::ScOnShow(CComponent *pComponent, BOOL fSelect)
  459. {
  460. SC sc = S_OK;
  461. ASSERT(pComponent);
  462. if (fSelect)
  463. {
  464. sc = ScInitializeResultView(pComponent);
  465. if (sc)
  466. goto Error;
  467. }
  468. Cleanup:
  469. return sc;
  470. Error:
  471. TraceError(_T("CBaseSnapinItem::ScOnShow"), sc);
  472. goto Cleanup;
  473. }
  474. // -----------------------------------------------------------------------------
  475. // Called during the MMCN_EXPAND notification sent to IComponentData::Notify. Inserts
  476. // the current item into the scope pane (if it is a container item) using IConsoleNameSpace
  477. // methods. If fExpand is FALSE, don't do anything.
  478. // Chains all sibling items.
  479. //
  480. SC CBaseSnapinItem::ScInsertScopeItem(CComponentData *pComponentData, BOOL fExpand, HSCOPEITEM item)
  481. {
  482. SC sc = S_OK;
  483. CBaseSnapinItem* pitem = this;
  484. SCOPEDATAITEM scopedataitem;
  485. if (fExpand == FALSE)
  486. goto Cleanup;
  487. while (pitem)
  488. {
  489. // Only add container items.
  490. if (pitem->FIsContainer())
  491. {
  492. pitem->SetComponentData(pComponentData);
  493. ZeroMemory(&scopedataitem, sizeof(SCOPEDATAITEM));
  494. scopedataitem.lParam = pitem->Cookie();
  495. scopedataitem.mask = SDI_STR | SDI_PARAM | SDI_PARENT | SDI_CHILDREN;
  496. if (pitem->Iconid() != iconNil)
  497. scopedataitem.mask |= SDI_IMAGE;
  498. if (pitem->OpenIconid() != iconNil)
  499. scopedataitem.mask |= SDI_OPENIMAGE;
  500. // Callback for the display name.
  501. // $REVIEW (ptousig) Why don't we take advantage of the displayname ?
  502. // Callbacks can be pretty inefficient.
  503. scopedataitem.displayname = MMC_CALLBACK;
  504. scopedataitem.nImage = pitem->Iconid();
  505. scopedataitem.nOpenImage = pitem->OpenIconid();
  506. scopedataitem.relativeID = item;
  507. // If there are no children, MMC will suppress the "+" sign
  508. scopedataitem.cChildren = pitem->FHasChildren() ? 1 : 0;
  509. ASSERT(pComponentData);
  510. sc = pComponentData->IpConsoleNameSpace()->InsertItem(&scopedataitem);
  511. if (sc)
  512. goto Error;
  513. pitem->SetHscopeitem(scopedataitem.ID);
  514. }
  515. pitem = pitem->PitemNext();
  516. }
  517. Cleanup:
  518. return sc;
  519. Error:
  520. TraceError(_T("CBaseSnapinItem::ScInsertScopeItem"), sc);
  521. goto Cleanup;
  522. }
  523. // -----------------------------------------------------------------------------
  524. // Inserts all child items into the default result list view.
  525. //
  526. SC CBaseSnapinItem::ScInsertResultItem(CComponent *pComponent)
  527. {
  528. SC sc = S_OK;
  529. RESULTDATAITEM resultdataitem;
  530. ASSERT(pComponent && pComponent->IpResultData());
  531. // Add this item
  532. ZeroMemory(&resultdataitem, sizeof(resultdataitem));
  533. resultdataitem.lParam = Cookie();
  534. resultdataitem.mask = RDI_STR | RDI_PARAM | RDI_IMAGE;
  535. // Callback for the display name.
  536. resultdataitem.str = MMC_CALLBACK;
  537. // Custom icon
  538. resultdataitem.nImage = (int) MMC_CALLBACK;
  539. sc = pComponent->IpResultData()->InsertItem(&resultdataitem);
  540. if (sc)
  541. goto Error;
  542. Cleanup:
  543. return sc;
  544. Error:
  545. TraceError(_T("CBaseSnapinItem::ScInsertResultItem"), sc);
  546. goto Cleanup;
  547. }
  548. // -----------------------------------------------------------------------------
  549. // Asks MMC to update the display of this item in the result pane.
  550. //
  551. SC CBaseSnapinItem::ScUpdateResultItem(IResultData *ipResultData)
  552. {
  553. DECLARE_SC(sc, _T("CBaseSnapinItem::ScUpdateResultItem"));
  554. HRESULTITEM item = NULL;
  555. ASSERT(ipResultData);
  556. sc = ipResultData->FindItemByLParam(Cookie(), &item);
  557. if (sc)
  558. return (sc);
  559. // If not found, does not exist in this view. Ignore.
  560. if (!item)
  561. return (sc);
  562. // $REVIEW (ptousig) Why are we ignoring errors ?
  563. ipResultData->UpdateItem(item);
  564. return sc;
  565. }
  566. // -----------------------------------------------------------------------------
  567. // Asks MMC to update the display of this item in the scope pane.
  568. //
  569. SC CBaseSnapinItem::ScUpdateScopeItem(IConsoleNameSpace *ipConsoleNameSpace)
  570. {
  571. SC sc = S_OK;
  572. SCOPEDATAITEM scopedataitem;
  573. ASSERT(FIsContainer());
  574. //
  575. // If this item doesn't have a HSCOPEITEM, then it is not known by MMC
  576. // therefore we would get an "invalid arg" error from the call to SetItem.
  577. //
  578. if (Hscopeitem() == 0)
  579. goto Cleanup;
  580. ZeroMemory(&scopedataitem, sizeof(SCOPEDATAITEM));
  581. scopedataitem.ID = Hscopeitem();
  582. scopedataitem.lParam = Cookie();
  583. scopedataitem.mask = SDI_PARAM;
  584. if (Iconid() != iconNil)
  585. {
  586. scopedataitem.mask |= SDI_IMAGE;
  587. ASSERT(FALSE && "Bitmap");
  588. //scopedataitem.nImage = PbitmapImageListSmall()->GetIndex(Iconid());
  589. }
  590. if (OpenIconid() != iconNil)
  591. {
  592. scopedataitem.mask |= SDI_OPENIMAGE;
  593. ASSERT(FALSE && "Bitmap");
  594. //scopedataitem.nOpenImage = PbitmapImageListSmall()->GetIndex(OpenIconid());
  595. }
  596. ASSERT(ipConsoleNameSpace);
  597. sc = ipConsoleNameSpace->SetItem(&scopedataitem);
  598. if (sc)
  599. goto Error;
  600. // Send a notification to update the result pane description bar.
  601. IpConsole()->UpdateAllViews(Pdataobject(), 0, ONVIEWCHANGE_UPDATEDESCRIPTIONBAR);
  602. Cleanup:
  603. return sc;
  604. Error:
  605. TraceError(_T("CBaseSnapinItem::ScUpdateScopeItem"), sc);
  606. goto Cleanup;
  607. }
  608. // -----------------------------------------------------------------------------
  609. // This is where we should tell MMC to remove all the items in the result pane.
  610. //
  611. // $REVIEW (ptousig) Why aren't we doing anything ?
  612. //
  613. SC CBaseSnapinItem::ScRemoveResultItems(LPRESULTDATA ipResultData)
  614. {
  615. return S_OK;
  616. }
  617. // -----------------------------------------------------------------------------
  618. // Provides (to MMC) the display string (or icon) for a given node in the
  619. // scope pane.
  620. //
  621. SC CBaseSnapinItem::ScGetDisplayInfo(LPSCOPEDATAITEM pScopeItem)
  622. {
  623. SC sc = S_OK;
  624. #ifdef _DEBUG
  625. static tstring str;
  626. #endif
  627. ASSERT(pScopeItem);
  628. if (pScopeItem->mask & SDI_STR)
  629. {
  630. pScopeItem->displayname = (LPTSTR)PstrDisplayName()->data();
  631. #ifdef _DEBUG
  632. if (tagBaseSnapinDebugDisplay.FAny())
  633. {
  634. USES_CONVERSION;
  635. str = OLE2T(pScopeItem->displayname);
  636. str += A2T(SzGetSnapinItemClassName());
  637. // str += this;
  638. // str += Hscopeitem();
  639. pScopeItem->displayname = T2OLE((LPTSTR)str.data());
  640. }
  641. #endif
  642. }
  643. if (pScopeItem->mask & SDI_IMAGE)
  644. {
  645. ASSERT(FALSE && "Bitmap");
  646. //pScopeItem->nImage = PbitmapImageListSmall()->GetIndex(Iconid());
  647. }
  648. return sc;
  649. }
  650. // -----------------------------------------------------------------------------
  651. // Provides (to MMC) the display string (or icon) for a given node in the
  652. // result pane.
  653. //
  654. SC CBaseSnapinItem::ScGetDisplayInfo(LPRESULTDATAITEM pResultItem)
  655. {
  656. DECLARE_SC(sc, _T("CBaseSnapinItem::ScGetDisplayInfo"));
  657. static tstring s_sz;
  658. ASSERT(pResultItem);
  659. if (pResultItem->mask & RDI_STR)
  660. {
  661. // Need to do this explicitly because the same buffer is reused.
  662. pResultItem->str = (LPTSTR)s_sz.data();
  663. // "Old" snapins might be referring to columns that don't exist.
  664. if (pResultItem->nCol < CcolinfoexDisplay())
  665. {
  666. Trace(tagBaseSnapinItemTracker, _T("Requesting field data - requested DAT is %d"), PcolinfoexDisplay(pResultItem->nCol)->Dat());
  667. sc= ScGetField( PcolinfoexDisplay(pResultItem->nCol)->Dat(), s_sz);
  668. if (sc)
  669. return sc;
  670. #ifdef _DEBUG
  671. if (pResultItem->nCol == 0 && tagBaseSnapinDebugDisplay.FAny())
  672. {
  673. s_sz = pResultItem->str;
  674. // s_sz += this;
  675. }
  676. #endif
  677. USES_CONVERSION;
  678. pResultItem->str = T2OLE((LPTSTR)s_sz.data());
  679. }
  680. }
  681. if (pResultItem->mask & RDI_IMAGE) // $REVIEW for extension snapins.
  682. {
  683. pResultItem->nImage = Iconid();
  684. }
  685. return sc;
  686. }
  687. // -----------------------------------------------------------------------------
  688. // Fills in result pane item information needed by MMC. This
  689. // method is used when the results pane is in virtual list mode
  690. // and we will be asking for data by index.
  691. //
  692. SC CBaseSnapinItem::ScGetVirtualDisplayInfo(LPRESULTDATAITEM pResultItem, IResultData *ipResultData)
  693. {
  694. DECLARE_SC(sc, _T("CBaseSnapinItem::ScGetDisplayInfo"));
  695. static tstring s_sz; //$REVIEW
  696. ASSERT(FVirtualResultsPane() && pResultItem);
  697. if (pResultItem->mask & RDI_STR)
  698. {
  699. sc= ScGetField(pResultItem->nIndex, PcolinfoexDisplay(pResultItem->nCol)->Dat(), s_sz, ipResultData);
  700. if (sc)
  701. return sc;
  702. pResultItem->str = (LPTSTR)s_sz.data();
  703. }
  704. if (pResultItem->mask & RDI_IMAGE) // $REVIEW for extension snapins.
  705. {
  706. pResultItem->nImage = Iconid();
  707. }
  708. return sc;
  709. }
  710. // -----------------------------------------------------------------------------
  711. // Returns the default icon ID : Folder
  712. //
  713. LONG CBaseSnapinItem::Iconid(void)
  714. {
  715. ASSERT(FALSE);
  716. return 0;
  717. }
  718. // -----------------------------------------------------------------------------
  719. // Returns the default open icon ID : Handles open folder / open RO folder / custom
  720. //
  721. LONG CBaseSnapinItem::OpenIconid(void)
  722. {
  723. ASSERT(FALSE);
  724. return 0;
  725. }
  726. // -----------------------------------------------------------------------------
  727. // Initializes the result view. This implementation requires a column info
  728. // structure, and creates the default set of columns.
  729. //
  730. SC CBaseSnapinItem::ScInitializeResultView(CComponent *pComponent)
  731. {
  732. SC sc = S_OK;
  733. INT i = 0;
  734. ASSERT(pComponent && pComponent->IpHeaderCtrl());
  735. // Remove any old column headers (on refresh / view change)
  736. while (!sc)
  737. sc = pComponent->IpHeaderCtrl()->DeleteColumn(0);
  738. sc = S_OK;
  739. for (i = 0; i < CcolinfoexHeaders(); i++)
  740. {
  741. Trace(tagBaseSnapinItemTracker, _T("Inserting column with title %s"), PcolinfoexHeaders(i)->strTitle().data());
  742. sc = pComponent->IpHeaderCtrl()->InsertColumn(i,
  743. PcolinfoexHeaders(i)->strTitle().data(),
  744. PcolinfoexHeaders(i)->NFormat(),
  745. PcolinfoexHeaders(i)->NWidth());
  746. // Will get fail if items are already in result pane. This is not an error, happens on refresh.
  747. // $REVIEW (ptousig) Maybe we should remove the items before re-initializing the columns.
  748. if (sc.ToHr() == E_FAIL)
  749. sc = S_OK;
  750. if (sc)
  751. goto Error;
  752. }
  753. // remove the NOSORTHEADER option - by default all items will have push-button header controls
  754. sc = pComponent->IpResultData()->ModifyViewStyle((MMC_RESULT_VIEW_STYLE)0, MMC_NOSORTHEADER);
  755. if (sc)
  756. goto Error;
  757. Cleanup:
  758. return sc;
  759. Error:
  760. TraceError(_T("CBaseSnapinItem::ScInitializeResultView"), sc);
  761. goto Cleanup;
  762. }
  763. // -----------------------------------------------------------------------------
  764. // MMC wants to know the image strip that should be used for the result pane.
  765. //
  766. SC CBaseSnapinItem::ScOnAddImages(IImageList* ipResultImageList)
  767. {
  768. SC sc = S_OK;
  769. ASSERT(ipResultImageList);
  770. sc = ipResultImageList->ImageListSetStrip(
  771. reinterpret_cast<long*>(static_cast<HBITMAP>(*PbitmapImageListSmall())),
  772. reinterpret_cast<long*>(static_cast<HBITMAP>(*PbitmapImageListLarge())),
  773. 0, RGB(255, 0, 255));
  774. if (sc)
  775. goto Error;
  776. Cleanup:
  777. return sc;
  778. Error:
  779. TraceError(_T("CBaseSnapinItem::ScOnAddImages"), sc);
  780. goto Cleanup;
  781. }
  782. // -----------------------------------------------------------------------------
  783. // Cause this node to refresh itself.
  784. //
  785. // WARNING: The "flicker" effect of this call is very annoying to look at. Do
  786. // not use this as a "silver bullet" solution. If you are adding,
  787. // removing or updating a child then use the appropriate ONVIEWCHANGE_*
  788. // notification.
  789. //
  790. SC CBaseSnapinItem::ScRefreshNode(void)
  791. {
  792. SC sc = S_OK;
  793. sc = IpConsole()->UpdateAllViews(this, 0, ONVIEWCHANGE_REFRESHCHILDREN);
  794. if (sc)
  795. goto Error;
  796. Cleanup:
  797. return sc;
  798. Error:
  799. TraceError(_T("CBaseSnapinItem::ScRefreshNode"), sc);
  800. goto Cleanup;
  801. }
  802. // -----------------------------------------------------------------------------
  803. // MMC is asking us the type of result pane we want
  804. //
  805. SC CBaseSnapinItem::ScGetResultViewType(LPOLESTR *ppViewType, long *pViewOptions)
  806. {
  807. DECLARE_SC(sc, TEXT("CBaseSnapinItem::ScGetResultViewType"));
  808. // Validate parameters
  809. ASSERT(ppViewType);
  810. ASSERT(pViewOptions);
  811. if ( FResultPaneIsOCX())
  812. {
  813. tstring strclsidOCX;
  814. sc = ScGetOCXCLSID(strclsidOCX);
  815. if (sc == S_FALSE) // default to listview.
  816. return sc;
  817. *ppViewType = (LPOLESTR)CoTaskMemAlloc( (strclsidOCX.length()+1) * sizeof(WCHAR));
  818. USES_CONVERSION;
  819. wcscpy(*ppViewType, T2COLE(strclsidOCX.data()));
  820. return sc;
  821. }
  822. if (FResultPaneIsWeb())
  823. {
  824. tstring strURL;
  825. sc = ScGetWebURL(strURL);
  826. if (sc == S_FALSE) // default to listview.
  827. return sc;
  828. *ppViewType = (LPOLESTR)CoTaskMemAlloc( (strURL.length()+1) * sizeof(WCHAR));
  829. USES_CONVERSION;
  830. wcscpy(*ppViewType, T2COLE(strURL.data()));
  831. return sc;
  832. }
  833. // Set the default
  834. *pViewOptions = MMC_VIEW_OPTIONS_NONE;
  835. // Check if we are displaying a virtual result pane list
  836. if (FVirtualResultsPane())
  837. // Ask for owner data listview (virtual list box mode).
  838. *pViewOptions = MMC_VIEW_OPTIONS_OWNERDATALIST;
  839. // Check if we should enable multiselect
  840. if (FAllowMultiSelectionForChildren())
  841. *pViewOptions = *pViewOptions | MMC_VIEW_OPTIONS_MULTISELECT;
  842. //
  843. // Return S_FALSE to indicate we want the standard result view.
  844. //
  845. return S_FALSE;
  846. }
  847. // -----------------------------------------------------------------------------
  848. // MMC is asking us the type of result pane we want using IComponent2
  849. //
  850. SC CBaseSnapinItem::ScGetResultViewType2(IConsole *pConsole, PRESULT_VIEW_TYPE_INFO pResultViewType)
  851. {
  852. DECLARE_SC(sc, _T("CBaseSnapinItem::ScGetResultViewType2"));
  853. // Validate parameters
  854. ASSERT(pResultViewType);
  855. ASSERT(PstrDisplayName());
  856. LPOLESTR pszViewDesc = (LPOLESTR)CoTaskMemAlloc((PstrDisplayName()->length()+1) * sizeof(WCHAR));
  857. if (! pszViewDesc)
  858. return (sc = E_OUTOFMEMORY);
  859. USES_CONVERSION;
  860. wcscpy(pszViewDesc, T2COLE(PstrDisplayName()->data()));
  861. pResultViewType->pstrPersistableViewDescription = pszViewDesc;
  862. if ( FResultPaneIsOCX())
  863. {
  864. tstring strclsidOCX;
  865. sc = ScGetOCXCLSID(strclsidOCX);
  866. if (sc == S_FALSE) // default to listview.
  867. return sc;
  868. pResultViewType->eViewType = MMC_VIEW_TYPE_OCX;
  869. pResultViewType->dwOCXOptions = RVTI_OCX_OPTIONS_NOLISTVIEW;
  870. pResultViewType->pUnkControl = NULL;
  871. if (FCacheOCX())
  872. {
  873. pResultViewType->dwOCXOptions = RVTI_OCX_OPTIONS_CACHE_OCX;
  874. pResultViewType->pUnkControl = GetCachedOCX(pConsole);
  875. }
  876. CComQIPtr<IConsole2> spConsole2(pConsole);
  877. if (! pResultViewType->pUnkControl)
  878. {
  879. CLSID clsidOCX;
  880. USES_CONVERSION;
  881. sc = CLSIDFromString(T2OLE(const_cast<LPTSTR>(strclsidOCX.data())), &clsidOCX);
  882. if (sc)
  883. return sc;
  884. LPUNKNOWN pUnkControl = NULL;
  885. sc = CoCreateInstance(clsidOCX, NULL, CLSCTX_SERVER, IID_IUnknown, (LPVOID*)&pUnkControl);
  886. if (sc)
  887. return sc;
  888. sc = ScInitOCX(pUnkControl, pConsole);
  889. pResultViewType->pUnkControl = pUnkControl;
  890. if (spConsole2)
  891. {
  892. tstring strStatusText = L"OCX: ";
  893. strStatusText += strclsidOCX;
  894. strStatusText += L" Created";
  895. spConsole2->SetStatusText(const_cast<LPOLESTR>(T2COLE(strStatusText.data())));
  896. }
  897. }
  898. else
  899. {
  900. pResultViewType->pUnkControl->AddRef();
  901. if (spConsole2)
  902. {
  903. tstring strStatusText = L"OCX: ";
  904. strStatusText += strclsidOCX;
  905. strStatusText += L" cached is used";
  906. spConsole2->SetStatusText(const_cast<LPOLESTR>(T2COLE(strStatusText.data())));
  907. }
  908. }
  909. return sc;
  910. }
  911. if (FResultPaneIsWeb())
  912. {
  913. tstring strURL = TEXT("msw");
  914. sc = ScGetWebURL(strURL);
  915. if (sc == S_FALSE) // default to listview.
  916. return sc;
  917. pResultViewType->eViewType = MMC_VIEW_TYPE_HTML;
  918. pResultViewType->dwHTMLOptions = RVTI_HTML_OPTIONS_NONE | RVTI_HTML_OPTIONS_NOLISTVIEW;
  919. LPOLESTR lpszURL = (LPOLESTR)CoTaskMemAlloc( (strURL.length()+1) * sizeof(WCHAR));
  920. USES_CONVERSION;
  921. wcscpy(lpszURL, T2COLE(strURL.data()));
  922. pResultViewType->pstrURL = lpszURL;
  923. return sc;
  924. }
  925. // Set the default
  926. pResultViewType->dwMiscOptions = RVTI_LIST_OPTIONS_NONE;
  927. // Check if we are displaying a virtual result pane list
  928. if (FVirtualResultsPane())
  929. // Ask for owner data listview (virtual list box mode).
  930. pResultViewType->dwListOptions = RVTI_LIST_OPTIONS_OWNERDATALIST;
  931. // Check if we should enable multiselect
  932. if (FAllowMultiSelectionForChildren())
  933. pResultViewType->dwListOptions |= RVTI_LIST_OPTIONS_MULTISELECT;
  934. if (FAllowPasteForResultItems())
  935. pResultViewType->dwListOptions |= RVTI_LIST_OPTIONS_ALLOWPASTE;
  936. //
  937. // Return S_FALSE to indicate we want the standard result view.
  938. //
  939. return S_FALSE;
  940. }
  941. // -----------------------------------------------------------------------------
  942. // MMC is trying to restore the view, see if it is our view description.
  943. //
  944. SC CBaseSnapinItem::ScRestoreResultView(PRESULT_VIEW_TYPE_INFO pResultViewType)
  945. {
  946. DECLARE_SC(sc, _T("CBaseSnapinItem::ScRestoreResultView"));
  947. // Validate parameters
  948. ASSERT(pResultViewType);
  949. ASSERT(pResultViewType->pstrPersistableViewDescription);
  950. ASSERT(PstrDisplayName());
  951. LPOLESTR pszViewDesc = pResultViewType->pstrPersistableViewDescription;
  952. if (! pszViewDesc)
  953. return (sc = E_OUTOFMEMORY);
  954. USES_CONVERSION;
  955. if ( 0 != wcscmp(pszViewDesc, T2COLE(PstrDisplayName()->data())) )
  956. return (sc = S_FALSE);
  957. if (! pResultViewType->dwMiscOptions & RVTI_LIST_OPTIONS_NONE)
  958. return (sc = S_FALSE);
  959. // Check if we are displaying a virtual result pane list
  960. if (FVirtualResultsPane())
  961. {
  962. if (! (pResultViewType->dwListOptions & RVTI_LIST_OPTIONS_OWNERDATALIST))
  963. return (sc = S_FALSE);
  964. }
  965. // Check if we should enable multiselect
  966. if (FAllowMultiSelectionForChildren())
  967. {
  968. if (! (pResultViewType->dwListOptions & RVTI_LIST_OPTIONS_MULTISELECT) )
  969. return (sc = S_FALSE);
  970. }
  971. // Check if result pane items allow paste.
  972. if (FAllowPasteForResultItems())
  973. {
  974. if (! (pResultViewType->dwListOptions & RVTI_LIST_OPTIONS_ALLOWPASTE) )
  975. return (sc = S_FALSE);
  976. }
  977. return S_OK;
  978. }
  979. // -----------------------------------------------------------------------------
  980. // Used to create a property sheet for an item. This uses MMC trickery to
  981. // display property pages on an object that has not yet been added to the MMC
  982. // result view.
  983. //
  984. SC CBaseSnapinItem::ScDisplayPropertySheet(void)
  985. {
  986. SC sc = S_OK;
  987. IPropertySheetCallbackPtr ipPropertySheetCallback;
  988. // If fCleanup == TRUE, we need to call Show(-1, 0) on an error.
  989. BOOL fCleanup = FALSE;
  990. TCHAR strTitle[256];
  991. CComPtr<IUnknown> spIUnknown;
  992. // Get a pointer to the IPropertySheetProvider interface.
  993. ipPropertySheetCallback = IpPropertySheetProvider();
  994. ASSERT(NULL != ipPropertySheetCallback);
  995. // Create the property pages for this object.
  996. // TRUE for property sheet, not wizard
  997. sc = IpPropertySheetProvider()->CreatePropertySheet(strTitle, TRUE, Cookie(), Pdataobject(), 0);
  998. if (sc)
  999. goto Error;
  1000. // If failure occurs after a successful call to CreatePropertySheet, need to call Show(-1,0). See MMC docs.
  1001. fCleanup = TRUE;
  1002. sc = ((IComponentData *)PComponentData())->QueryInterface(IID_IUnknown, (void **)&spIUnknown);
  1003. if (sc)
  1004. goto Error;
  1005. // Add the primary pages for the object.
  1006. sc = IpPropertySheetProvider()->AddPrimaryPages(spIUnknown, TRUE, NULL, TRUE);
  1007. if (sc)
  1008. goto Error;
  1009. //$REVIEW (ptousig) Why is this commented out ?
  1010. //sc = IpPropertySheetProvider()->AddExtensionPages();
  1011. if (sc)
  1012. goto Error;
  1013. sc = IpPropertySheetProvider()->Show((long) GetActiveWindow(), 0);
  1014. if (sc)
  1015. goto Error;
  1016. Cleanup:
  1017. return sc;
  1018. Error:
  1019. // If failure occurs after a successful call to CreatePropertySheet, need to call Show(-1,0). See MMC docs.
  1020. if (fCleanup)
  1021. IpPropertySheetProvider()->Show(-1, 0);
  1022. TraceError(_T("CBaseSnapinItem::ScDisplayPropertySheet"), sc);
  1023. goto Cleanup;
  1024. }
  1025. // -----------------------------------------------------------------------------
  1026. void CBaseSnapinItem::SetParent(CBaseSnapinItem *pitemParent)
  1027. {
  1028. ASSERT(pitemParent);
  1029. m_pitemParent = pitemParent;
  1030. }
  1031. // -----------------------------------------------------------------------------
  1032. void CBaseSnapinItem::SetNext(CBaseSnapinItem *pitemNext)
  1033. {
  1034. m_pitemNext = pitemNext;
  1035. if (pitemNext)
  1036. pitemNext->m_pitemPrevious = this;
  1037. }
  1038. // -----------------------------------------------------------------------------
  1039. void CBaseSnapinItem::SetPrevious(CBaseSnapinItem *pitemPrevious)
  1040. {
  1041. m_pitemPrevious = pitemPrevious;
  1042. if (pitemPrevious)
  1043. pitemPrevious->m_pitemNext = this;
  1044. }
  1045. // -----------------------------------------------------------------------------
  1046. void CBaseSnapinItem::SetChild(CBaseSnapinItem *pitemChild)
  1047. {
  1048. m_pitemChild = pitemChild;
  1049. if (pitemChild)
  1050. pitemChild->m_pitemParent = this;
  1051. }
  1052. // -----------------------------------------------------------------------------
  1053. // A context menu option was selected.
  1054. //
  1055. SC CBaseSnapinItem::ScCommand(long nCommandID, CComponent *pComponent)
  1056. {
  1057. SC sc = S_OK;
  1058. switch (nCommandID)
  1059. {
  1060. case IDS_Test:
  1061. break;
  1062. #if 0
  1063. case idmBarfTraces:
  1064. sc = Psnapin()->ScOnMenuTraces();
  1065. break;
  1066. case idmBarfClearDbgScreen:
  1067. Trace(tagAlways, _T("\x1B[2J"));
  1068. break;
  1069. case idmBarfSCDescription:
  1070. sc = Psnapin()->ScOnMenuSCDescription();
  1071. break;
  1072. case idmBarfSettings:
  1073. DoBarfDialog();
  1074. break;
  1075. case idmBarfAll:
  1076. BarfAll();
  1077. break;
  1078. case idmBarfMemoryDiff:
  1079. sc = Psnapin()->ScOnMenuMemoryDiff();
  1080. break;
  1081. case idmBarfValidateMemory:
  1082. sc = Psnapin()->ScOnMenuMemoryDiff();
  1083. break;
  1084. case idmBarfTotalMemAllocd:
  1085. sc = Psnapin()->ScOnMenuTotalMemory();
  1086. break;
  1087. case idmBarfDebugBreak:
  1088. DebugBreak();
  1089. break;
  1090. #endif
  1091. default:
  1092. break;
  1093. }
  1094. if (sc)
  1095. goto Error;
  1096. Cleanup:
  1097. return sc;
  1098. Error:
  1099. TraceError(_T("CBaseSnapinItem::ScCommand"), sc);
  1100. goto Cleanup;
  1101. }
  1102. // -----------------------------------------------------------------------------
  1103. // Determines whether any property pages are open on this item. As a side-effect
  1104. // if any property sheet is found, it will be given focus. MMC does that by
  1105. // itself, we don't have any way of stopping it.
  1106. // If the item is a result pane item, we must provide an IComponent to MMC, this
  1107. // is the component that will receive then CompareObjects call. In our
  1108. // implementation, we don't care which IComponent does the comparison, so pass
  1109. // in any IComponent you can get your hands on.
  1110. //
  1111. SC CBaseSnapinItem::ScIsPropertySheetOpen(BOOL *pfPagesUp, IComponent *ipComponent)
  1112. {
  1113. SC sc = S_OK;
  1114. ASSERT(pfPagesUp);
  1115. *pfPagesUp = FALSE;
  1116. if (FIsContainer())
  1117. {
  1118. // Scope pane nodes are owned by the MMC.
  1119. // Note: MMC docs says first parameter is the cookie. It is in fact the HSCOPEITEM.
  1120. sc = IpPropertySheetProvider()->FindPropertySheet(Hscopeitem(), NULL, Pdataobject());
  1121. if (sc)
  1122. goto Error;
  1123. }
  1124. else
  1125. {
  1126. // Result pane nodes are owned by the IComponent.
  1127. ASSERT(ipComponent);
  1128. sc = IpPropertySheetProvider()->FindPropertySheet(Cookie(), ipComponent, Pdataobject());
  1129. if (sc)
  1130. goto Error;
  1131. }
  1132. if (sc == S_FALSE)
  1133. *pfPagesUp = FALSE;
  1134. else if (sc == S_OK)
  1135. *pfPagesUp = TRUE;
  1136. Cleanup:
  1137. return sc;
  1138. Error:
  1139. TraceError(_T("CBaseSnapinItem::ScIsPropertySheetOpen"), sc);
  1140. goto Cleanup;
  1141. }
  1142. // =============================================================================
  1143. // Class CBaseMultiSelectSnapinItem
  1144. // =============================================================================
  1145. UINT CBaseMultiSelectSnapinItem::s_cfMultiSelectSnapins = RegisterClipboardFormat(CCF_MULTI_SELECT_SNAPINS); // Multiselect - list of multi select snapin items in a composite data object
  1146. UINT CBaseMultiSelectSnapinItem::s_cfCompositeDataObject = RegisterClipboardFormat(CCF_MMC_MULTISELECT_DATAOBJECT); // Multi select - used to determine if an object is a composite data object
  1147. // -----------------------------------------------------------------------------
  1148. // Constructor for CBaseMultiSelectSnapinItem
  1149. // -----------------------------------------------------------------------------
  1150. CBaseMultiSelectSnapinItem::CBaseMultiSelectSnapinItem() : CBaseSnapinItem()
  1151. {
  1152. // Remember we created a multiselect snapin item
  1153. Trace(tagBaseMultiSelectSnapinItemTracker, _T("0x%08lX: Creation"), this);
  1154. // By default, a multiselect object is not involved in copy/paste operations
  1155. // Set the pointer to an array indicating the pasted items to NULL
  1156. m_pfPastedWithCut = NULL;
  1157. }
  1158. // -----------------------------------------------------------------------------
  1159. // Destructor for CBaseMultiSelectSnapinItem
  1160. // -----------------------------------------------------------------------------
  1161. CBaseMultiSelectSnapinItem::~CBaseMultiSelectSnapinItem()
  1162. {
  1163. // Delete the array indicating the pasted items (if any was allocated)
  1164. if (m_pfPastedWithCut)
  1165. {
  1166. delete [] m_pfPastedWithCut;
  1167. m_pfPastedWithCut = NULL;
  1168. }
  1169. }
  1170. /* CBaseMultiSelectSnapinItem::ScWriteMultiSelectionItemTypes
  1171. *
  1172. * PURPOSE: Implement the CCF_OBJECT_TYPES_IN_MULTI_SELECT clipboard format.
  1173. * The clipboard data info indicates the types of nodes selected by a multi-select operation.
  1174. *
  1175. * PARAMETERS:
  1176. * IStream * pstream The stream to write to.
  1177. *
  1178. * RETURNS:
  1179. * SC Execution code.
  1180. */
  1181. SC
  1182. CBaseMultiSelectSnapinItem::ScWriteMultiSelectionItemTypes(IStream * pstream)
  1183. {
  1184. // Declarations
  1185. SC sc = S_OK;
  1186. INT nIterator = 0;
  1187. GUIDSet gsItemTypes;
  1188. // Data validation
  1189. ASSERT(pstream);
  1190. // Remember we created a multiselect snapin item
  1191. Trace(tagBaseMultiSelectSnapinItemTracker, _T("Received a request for clipboard data on node types"), this);
  1192. // First determine how many GUIDs we have - note that the selection of snapin items was obtained for a particular component
  1193. // Therefore the selection contains snapin items which were instanciated from the same snapin and does not include items which may have been added by other snapins
  1194. for (nIterator=0; nIterator < PivSelectedItems()->size(); nIterator++)
  1195. {
  1196. // Local declarations
  1197. LPGUID pGuidItemType = (LPGUID)((*PivSelectedItems())[nIterator])->Pnodetype()->PclsidNodeType();
  1198. // Determine if the guid can be located in the guid set and if not add it
  1199. ASSERT(pGuidItemType);
  1200. if (gsItemTypes.find(*pGuidItemType) == gsItemTypes.end()) // means not found
  1201. gsItemTypes.insert(*pGuidItemType);
  1202. }
  1203. // Write a SMMCObjectTypes data structure
  1204. // First: number of found types
  1205. {
  1206. // Local declarations
  1207. DWORD dwcItemTypes = 0;
  1208. ASSERT(gsItemTypes.size() > 0);
  1209. dwcItemTypes = gsItemTypes.size();
  1210. sc = pstream->Write(&dwcItemTypes, sizeof(DWORD), NULL); // need l-value
  1211. if (sc)
  1212. goto Error;
  1213. }
  1214. // Write a SMMCObjectTypes data structure
  1215. // Second: the guids
  1216. {
  1217. for (GUIDSet::iterator p = gsItemTypes.begin(); p != gsItemTypes.end(); p++)
  1218. {
  1219. sc = pstream->Write(&p, sizeof(GUID), NULL);
  1220. if (sc)
  1221. goto Error;
  1222. }
  1223. }
  1224. Cleanup:
  1225. return sc;
  1226. Error:
  1227. TraceError(_T("CBaseMultiSelectSnapinItem::ScWriteMultiSelectionItemTypes()"), sc);
  1228. goto Cleanup;
  1229. }
  1230. /* CBaseMultiSelectSnapinItem::ScOnSelect
  1231. *
  1232. * PURPOSE: Forward a selection notification to selected items - select verbs.
  1233. *
  1234. * PARAMETERS:
  1235. * CComponent * pComponent Pointer to the component object.
  1236. * LPDATAOBJECT lpDataObject Pointer to the multiselect snapin item.
  1237. * BOOL fScope TRUE if selection in the scope pane.
  1238. * BOOL fSelect TRUE if selected.
  1239. *
  1240. * RETURNS:
  1241. * SC Execution code
  1242. */
  1243. SC
  1244. CBaseMultiSelectSnapinItem::ScOnSelect(CComponent * pComponent, LPDATAOBJECT lpDataObject, BOOL fScope, BOOL fSelect)
  1245. {
  1246. // Declarations
  1247. SC sc = S_OK;
  1248. INT nIterator = 0;
  1249. // Data validation
  1250. ASSERT(pComponent);
  1251. ASSERT(lpDataObject);
  1252. // Forward the request to the component as if only the first snapin item had been selected (this will allow us to select verbs)
  1253. // MMC finds will select these verbs for all selected snapin items
  1254. ASSERT(PivSelectedItemsFirst());
  1255. // For this call we have to go back to the component as there is some work to do at the snapin level
  1256. // We contact only the first snapin item to select verbs
  1257. // $REVIEW (dominicp) MMC recommends doing this. We should probably merge verbs only though. This would be smarter.
  1258. sc = pComponent->ScOnSelect(PivSelectedItemsFirst(), fScope, fSelect);
  1259. if (sc)
  1260. goto Error;
  1261. // We just let the other snapin items know they have been selected
  1262. for (nIterator=1; nIterator < PivSelectedItems()->size(); nIterator++) // start at index 1
  1263. {
  1264. // Get the next item
  1265. ASSERT((*PivSelectedItems())[nIterator]);
  1266. // Call ScOnSelect for each snapin item - pass pitem as an lpDataObject parameter
  1267. sc = (*PivSelectedItems())[nIterator]->ScOnSelect(pComponent, (*PivSelectedItems())[nIterator], fScope, fSelect);
  1268. if (sc)
  1269. goto Error;
  1270. }
  1271. Cleanup:
  1272. return sc;
  1273. Error:
  1274. TraceError(_T("CBaseMultiSelectSnapinItem::ScOnSelect()"), sc);
  1275. goto Cleanup;
  1276. }
  1277. /* CBaseMultiSelectSnapinItem::ScAddMenuItems
  1278. *
  1279. * PURPOSE: Computes the merged context menu items and sets them.
  1280. *
  1281. * PARAMETERS:
  1282. * CBaseSnapin * pSnapin Pointer to the snapin object.
  1283. * LPDATAOBJECT lpDataObject Pointer to the multiselect snapin item.
  1284. * LPCONTEXTMENUCALLBACK ipContextMenuCallback Context menu callback to add menu items.
  1285. * long * pInsertionAllowed Pointer to insertion flags.
  1286. *
  1287. * RETURNS:
  1288. * SC Execution code
  1289. */
  1290. SC
  1291. CBaseMultiSelectSnapinItem::ScAddMenuItems(CBaseSnapin * pSnapin, LPDATAOBJECT pDataObject, LPCONTEXTMENUCALLBACK ipContextMenuCallback, long * pInsertionAllowed)
  1292. {
  1293. // Declarations
  1294. SC sc = S_OK;
  1295. CBaseSnapinItem * pitem = NULL;
  1296. INT nIterator = 0;
  1297. INT nIteratorMenuItems = 0;
  1298. CSnapinContextMenuItemVectorWrapper cmivwMerged; // vector of merged context menu items
  1299. // Data validation
  1300. ASSERT(pSnapin);
  1301. ASSERT(pDataObject);
  1302. ASSERT(ipContextMenuCallback);
  1303. ASSERT(pInsertionAllowed);
  1304. // Iterate through the snapin items and retrieve a list of context menus - combine the menus across snapin items
  1305. for (nIterator=0; nIterator < PivSelectedItems()->size(); nIterator++) // start at index 1
  1306. {
  1307. // Get the snapin item
  1308. pitem = (*PivSelectedItems())[nIterator];
  1309. ASSERT(pitem);
  1310. // Create a vector of menu items
  1311. CSnapinContextMenuItemVectorWrapper cmivw; // we will have to merge these context menu item`s
  1312. // Determine the menu items for the snapin item
  1313. for (nIteratorMenuItems=0; nIteratorMenuItems < pitem->CMenuItem(); nIteratorMenuItems++)
  1314. {
  1315. // Declarations
  1316. CSnapinContextMenuItem * pcmi = NULL;
  1317. BOOL fAllowed = FALSE;
  1318. // Create a new context menu item
  1319. pcmi = new CSnapinContextMenuItem();
  1320. if (!pcmi)
  1321. goto MemoryError;
  1322. // Get the context menu item
  1323. ASSERT(pitem->Pmenuitem());
  1324. sc = pSnapin->ScGetMenuItem(pcmi, pitem, &((pitem->Pmenuitem())[nIteratorMenuItems]), &fAllowed, *pInsertionAllowed);
  1325. if (sc)
  1326. goto Error;
  1327. // If the context menu item is allowed, add it to the vector
  1328. if (fAllowed)
  1329. {
  1330. if (nIterator > 0)
  1331. cmivw.cmiv.push_back(pcmi); // for other items, set a new array and then merge
  1332. else
  1333. cmivwMerged.cmiv.push_back(pcmi); // for the first item, set the merge
  1334. }
  1335. // Otherwise delete the context menu item
  1336. else
  1337. {
  1338. if (pcmi)
  1339. {
  1340. delete pcmi;
  1341. pcmi = NULL;
  1342. }
  1343. }
  1344. }
  1345. // Now combine the menus we found with the merged menus
  1346. if (nIterator > 0)
  1347. MergeMenuItems(&cmivwMerged, &cmivw);
  1348. }
  1349. // Now add the merged menu items
  1350. for (nIteratorMenuItems=0; nIteratorMenuItems < cmivwMerged.cmiv.size(); nIteratorMenuItems++)
  1351. {
  1352. sc = ipContextMenuCallback->AddItem(&(cmivwMerged.cmiv[nIteratorMenuItems]->cm));
  1353. if (sc)
  1354. goto Error;
  1355. }
  1356. Cleanup:
  1357. return sc;
  1358. MemoryError:
  1359. sc = E_OUTOFMEMORY;
  1360. goto Error;
  1361. Error:
  1362. TraceError(_T("CBaseMultiSelectSnapinItem::ScAddMenuItems()"), sc);
  1363. goto Cleanup;
  1364. }
  1365. /* CBaseMultiSelectSnapinItem::ScCommand
  1366. *
  1367. * PURPOSE: Forward an add menu request to selected items.
  1368. *
  1369. * PARAMETERS:
  1370. * CComponent * pComponent Pointer to the component object.
  1371. * long nCommandID Id of the invoked command.
  1372. * LPDATAOBJECT pDataObject Pointer to the multiselect snapin item.
  1373. *
  1374. * RETURNS:
  1375. * SC Execution code
  1376. */
  1377. SC
  1378. CBaseMultiSelectSnapinItem::ScCommand(CComponent * pComponent, long nCommandID, LPDATAOBJECT pDataObject)
  1379. {
  1380. // Declarations
  1381. SC sc = S_OK;
  1382. CBaseSnapinItem * pitem = NULL;
  1383. INT nIterator = 0;
  1384. // Data validation
  1385. ASSERT(pComponent);
  1386. ASSERT(pDataObject);
  1387. // We forward the call to all items in the default implementation
  1388. // This can be overriden if you want to provide bulk operation behaviour
  1389. // You will then have to create you own CBaseMultiSelectSnapinItem based multiselect data object
  1390. for (nIterator=0; nIterator < PivSelectedItems()->size(); nIterator++)
  1391. {
  1392. // Get the next item
  1393. ASSERT((*PivSelectedItems())[nIterator]);
  1394. // Call the menu by going back to the component
  1395. sc = pComponent->ScCommand(nCommandID, (*PivSelectedItems())[nIterator]);
  1396. if (sc)
  1397. goto Error;
  1398. }
  1399. Cleanup:
  1400. return sc;
  1401. Error:
  1402. TraceError(_T("CBaseMultiSelectSnapinItem::ScCommand()"), sc);
  1403. goto Cleanup;
  1404. }
  1405. /* CBaseMultiSelectSnapinItem::ScQueryPagesFor
  1406. *
  1407. * PURPOSE: Indicate that there are properties for a multi selection (in fact a page saying that there are no properties available).
  1408. *
  1409. * PARAMETERS:
  1410. * CComponent * pComponent Pointer to the component object.
  1411. * LPDATAOBJECT lpDataObject Pointer to the multiselect snapin item.
  1412. *
  1413. * RETURNS:
  1414. * SC Execution code
  1415. */
  1416. SC
  1417. CBaseMultiSelectSnapinItem::ScQueryPagesFor(CComponent * pComponent, LPDATAOBJECT lpDataObject)
  1418. {
  1419. // Declarations
  1420. SC sc = S_OK;
  1421. INT nIterator = 0;
  1422. // Data validation
  1423. ASSERT(pComponent);
  1424. ASSERT(lpDataObject);
  1425. // By default, no page for a multiselection
  1426. return S_FALSE;
  1427. }
  1428. /* CBaseMultiSelectSnapinItem::ScCreatePropertyPages
  1429. *
  1430. * PURPOSE: Display a page saying that there are no properties available.
  1431. *
  1432. * PARAMETERS:
  1433. * CComponent * pComponent Pointer to the component object.
  1434. * LPDATAOBJECT lpDataObject Pointer to the multiselect snapin item.
  1435. *
  1436. * RETURNS:
  1437. * SC Execution code
  1438. */
  1439. SC
  1440. CBaseMultiSelectSnapinItem::ScCreatePropertyPages(CComponent * pComponent, LPPROPERTYSHEETCALLBACK ipPropertySheetCallback, long handle, LPDATAOBJECT lpDataObject)
  1441. {
  1442. // Data validation
  1443. ASSERT(pComponent);
  1444. ASSERT(ipPropertySheetCallback);
  1445. ASSERT(lpDataObject);
  1446. // By default, no page for a multiselection
  1447. return S_FALSE;
  1448. }
  1449. /* CBaseMultiSelectSnapinItem::ScOnPaste
  1450. *
  1451. * PURPOSE: We receive a multiselect snapin item and we must determine which items are okay with the paste.
  1452. * Also, if the operation involves a cut, we have to return a list of items to be pasted.
  1453. * We use an array of boolean to indicate the items for which a cut notification has to be sent.
  1454. * We reuse the existing multiselect snapin item as the multiselect snapin item sent to MMC to identify
  1455. * the objects which should receive a cut notification.
  1456. *
  1457. * PARAMETERS:
  1458. * CBaseSnapin * psnapin Pointer to the snapin.
  1459. * CBaseSnapinItem * pitemTarget Target item for the paste.
  1460. * LPDATAOBJECT lpDataObjectList Pointer to the multiselect snapin item.
  1461. * LPDATAOBJECT * ppDataObjectPasted If not NULL, we must set this pointer to the multiselect snapin item indicating the objects which need a cut notification.
  1462. * IConsole * ipConsole Pointer to the console interface.
  1463. *
  1464. * RETURNS:
  1465. * SC Execution code
  1466. */
  1467. SC
  1468. CBaseMultiSelectSnapinItem::ScOnPaste(CBaseSnapin * pSnapin, CBaseSnapinItem * pitemTarget, LPDATAOBJECT lpDataObjectList, LPDATAOBJECT * ppDataObjectPasted, IConsole * ipConsole)
  1469. {
  1470. // Declarations
  1471. SC sc = S_OK;
  1472. INT nIterator = 0;
  1473. BOOL fAtLeastOnePaste = FALSE;
  1474. // Data validation
  1475. ASSERT(pSnapin);
  1476. ASSERT(pitemTarget);
  1477. ASSERT(lpDataObjectList);
  1478. ASSERT(ipConsole);
  1479. // other parameters can not be ASSERTed
  1480. // Allocate an array of booleans to indicate the correctly pasted items
  1481. ASSERT(PivSelectedItems()->size() > 0);
  1482. m_pfPastedWithCut = new BOOL[PivSelectedItems()->size()];
  1483. if (!m_pfPastedWithCut)
  1484. goto MemoryError;
  1485. for (nIterator=0; nIterator < PivSelectedItems()->size(); nIterator++)
  1486. m_pfPastedWithCut[nIterator] = FALSE;
  1487. // Iterate through all the objects and verify that they can be pasted
  1488. for (nIterator=0; nIterator < PivSelectedItems()->size(); nIterator++)
  1489. {
  1490. // Local declarations
  1491. DWORD dwCanCopyCut = 0;
  1492. BOOL fPasted = FALSE;
  1493. // Ask the item to copy the underlying object
  1494. sc = pitemTarget->ScOnPaste((*PivSelectedItems())[nIterator], ppDataObjectPasted ? TRUE : FALSE, &fPasted);
  1495. if (sc)
  1496. goto Error;
  1497. if (fPasted)
  1498. {
  1499. // Remember we pasted at least one item
  1500. fAtLeastOnePaste = TRUE;
  1501. }
  1502. // If this was a cut, we need to return to MMC the items that were pasted
  1503. // (do not delete the dropped item if we are just adding it to a policy)
  1504. if (fPasted && ppDataObjectPasted && !pitemTarget->FIsPolicy())
  1505. {
  1506. // Remember the items which should receive a cut notification
  1507. m_pfPastedWithCut[nIterator] = TRUE;
  1508. }
  1509. }
  1510. // Indicate to MMC the pasted item
  1511. if (ppDataObjectPasted)
  1512. {
  1513. *ppDataObjectPasted = this;
  1514. AddRef(); // reuse ourselves as the multiselect data object which indicates the pasted items
  1515. }
  1516. // Refresh
  1517. if (fAtLeastOnePaste)
  1518. {
  1519. sc = ipConsole->UpdateAllViews(static_cast<IDataObject *>(pitemTarget), 0, ONVIEWCHANGE_REFRESHCHILDREN);
  1520. if (sc)
  1521. goto Error;
  1522. }
  1523. Cleanup:
  1524. return sc;
  1525. MemoryError:
  1526. sc = E_OUTOFMEMORY;
  1527. goto Error;
  1528. Error:
  1529. TraceError(_T("CBaseMultiSelectSnapinItem::ScOnPaste()"), sc);
  1530. goto Cleanup;
  1531. }
  1532. /* CBaseMultiSelectSnapinItem::ScOnCutOrMove
  1533. *
  1534. * PURPOSE: We are a multiselect snapin item which points to an array of booleans indicating which snapin items need a cut notification.
  1535. * We must forward a cut notification to these items.
  1536. *
  1537. * PARAMETERS:
  1538. * CBaseSnapin * psnapin Pointer to the snapin.
  1539. * LPDATAOBJECT lpDataObjectList Pointer to the multiselect snapin item.
  1540. * IConsoleNameSpace * ipConsoleNameSpace Pointer to the namespace console interface.
  1541. * IConsole * ipConsole Pointer to the console interface.
  1542. *
  1543. * RETURNS:
  1544. * SC Execution code
  1545. */
  1546. SC
  1547. CBaseMultiSelectSnapinItem::ScOnCutOrMove(CBaseSnapin * pSnapin, LPDATAOBJECT lpDataObjectList, IConsoleNameSpace * ipConsoleNameSpace, IConsole * ipConsole)
  1548. {
  1549. // Declarations
  1550. SC sc = S_OK;
  1551. INT nIterator = 0;
  1552. // Data validation
  1553. ASSERT(pSnapin);
  1554. ASSERT(lpDataObjectList);
  1555. ASSERT(ipConsoleNameSpace);
  1556. ASSERT(ipConsole);
  1557. // Iterate through the items and find those which need a cut notification
  1558. for (nIterator=0; nIterator < PivSelectedItems()->size(); nIterator++) // start at index 1
  1559. {
  1560. // Get the next item
  1561. ASSERT((*PivSelectedItems())[nIterator]);
  1562. ASSERT(m_pfPastedWithCut);
  1563. // Check if the item needs a cut notification
  1564. if (m_pfPastedWithCut[nIterator])
  1565. {
  1566. // Call ScOnCutOrMove for each snapin item - pass pitem as an lpDataObjectList parameter
  1567. sc = pSnapin->ScOnCutOrMove((*PivSelectedItems())[nIterator], ipConsoleNameSpace, ipConsole);
  1568. if (sc)
  1569. goto Error;
  1570. }
  1571. }
  1572. Cleanup:
  1573. return sc;
  1574. Error:
  1575. TraceError(_T("CBaseMultiSelectSnapinItem::ScOnCutOrMove()"), sc);
  1576. goto Cleanup;
  1577. }
  1578. /* CBaseMultiSelectSnapinItem::ScOnDelete
  1579. *
  1580. * PURPOSE: Forward a delete notification to selected items.
  1581. *
  1582. * PARAMETERS:
  1583. * CComponent * pComponent Pointer to the component.
  1584. * LPDATAOBJECT lpDataObject Pointer to the multiselect snapin item.
  1585. * RETURNS:
  1586. * SC Execution code
  1587. */
  1588. SC
  1589. CBaseMultiSelectSnapinItem::ScOnDelete(CComponent * pComponent, LPDATAOBJECT lpDataObject)
  1590. {
  1591. // Declarations
  1592. SC sc = S_OK;
  1593. INT nIterator = 0;
  1594. // Data validation
  1595. ASSERT(pComponent);
  1596. ASSERT(lpDataObject);
  1597. // Iterate through the items and find those which need a cut notification
  1598. for (nIterator=0; nIterator < PivSelectedItems()->size(); nIterator++) // start at index 1
  1599. {
  1600. // Get the next item
  1601. ASSERT((*PivSelectedItems())[nIterator]);
  1602. // Call ScOnDelete for each snapin item - pass pitem as an lpDataObject parameter
  1603. sc = pComponent->ScOnDelete((*PivSelectedItems())[nIterator]);
  1604. if (sc)
  1605. goto Error;
  1606. }
  1607. Cleanup:
  1608. return sc;
  1609. Error:
  1610. TraceError(_T("CBaseMultiSelectSnapinItem::ScOnDelete()"), sc);
  1611. goto Cleanup;
  1612. }
  1613. /* CBaseMultiSelectSnapinItem::ScExtractMultiSelectObjectFromCompositeMultiSelectObject
  1614. *
  1615. * PURPOSE: On some notifications, MMC gives us a composite object made of multiselect object from different snapins.
  1616. * This method's goal is to extract a multiselect object from the composite object.
  1617. *
  1618. * PARAMETERS:
  1619. * CBaseSnapin * psnapin Snapin (used to determine which multiselect data object is the right one in the composite multiselect data object).
  1620. * LPDATAOBJECT pDataObjectComposite Composite data object.
  1621. * CBaseMultiSelectSnapinItem ** ppBaseMultiSelectSnapinItem Determined multiselect data object.
  1622. *
  1623. * RETURNS:
  1624. * SC Execution code
  1625. */
  1626. SC
  1627. CBaseMultiSelectSnapinItem::ScExtractMultiSelectObjectFromCompositeMultiSelectObject(CBaseSnapin * psnapin, LPDATAOBJECT pDataObjectComposite, CBaseMultiSelectSnapinItem ** ppBaseMultiSelectSnapinItem)
  1628. {
  1629. // Declarations
  1630. SC sc = S_OK;
  1631. STGMEDIUM stgmedium = {TYMED_HGLOBAL, NULL};
  1632. FORMATETC formatetc = {(CLIPFORMAT)s_cfMultiSelectSnapins, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1633. SMMCDataObjects * pSMMCDataObjects = NULL;
  1634. CBaseMultiSelectSnapinItem * pBaseMultiSelectSnapinItem = NULL;
  1635. INT nIterator = 0;
  1636. // Data validation
  1637. ASSERT(pDataObjectComposite);
  1638. ASSERT(ppBaseMultiSelectSnapinItem);
  1639. ASSERT(!*ppBaseMultiSelectSnapinItem);
  1640. ASSERT(psnapin);
  1641. // Retrieve data
  1642. sc = pDataObjectComposite->GetData(&formatetc, &stgmedium);
  1643. if (sc)
  1644. goto Error;
  1645. // Lock memory and cast
  1646. pSMMCDataObjects = (SMMCDataObjects *)(::GlobalLock(stgmedium.hGlobal));
  1647. ASSERT(pSMMCDataObjects);
  1648. // What we get here is a composite object made of multiselection sets of snapin items from the same snapin
  1649. // We have to locate the multiselection set for our snapin
  1650. ASSERT(pSMMCDataObjects->count > 0);
  1651. for (nIterator=0; nIterator < pSMMCDataObjects->count; nIterator++)
  1652. {
  1653. // Local declarations
  1654. CLSID clsid;
  1655. // Get the class id for the dataobject
  1656. ASSERT(pSMMCDataObjects->lpDataObject[nIterator]);
  1657. sc = ScGetClassID(pSMMCDataObjects->lpDataObject[nIterator], &clsid);
  1658. if (sc)
  1659. {
  1660. // Ignore the error, probably this node does not belong to us
  1661. sc = S_OK;
  1662. }
  1663. else if (::IsEqualCLSID(clsid, *(psnapin->PclsidSnapin())))
  1664. {
  1665. pBaseMultiSelectSnapinItem = dynamic_cast<CBaseMultiSelectSnapinItem *>(pSMMCDataObjects->lpDataObject[nIterator]);
  1666. ASSERT(pBaseMultiSelectSnapinItem);
  1667. break;
  1668. }
  1669. }
  1670. // Assign the result
  1671. ASSERT(pBaseMultiSelectSnapinItem);
  1672. ASSERT(*(psnapin->PclsidSnapin()) == *(pBaseMultiSelectSnapinItem->PclsidSnapin()));
  1673. *ppBaseMultiSelectSnapinItem = pBaseMultiSelectSnapinItem;
  1674. Cleanup:
  1675. // Cleanup allocated resources
  1676. if (pSMMCDataObjects)
  1677. ::GlobalUnlock(stgmedium.hGlobal);
  1678. if (stgmedium.hGlobal)
  1679. ::GlobalFree(stgmedium.hGlobal);
  1680. return sc;
  1681. Error:
  1682. TraceError(_T("CBaseMultiSelectSnapinItem::ScExtractMultiSelectObjectFromCompositeMultiSelectObject()"), sc);
  1683. goto Cleanup;
  1684. }
  1685. /* CBaseMultiSelectSnapinItem::ScIsPastableDataObject
  1686. *
  1687. * PURPOSE: Determine, using the multiselect object, if a paste operation is acceptable.
  1688. *
  1689. * PARAMETERS:
  1690. * CBaseSnapin * psnapin Pointer to the snapin.
  1691. * CBaseSnapinItem * pitemTarget Target item for the paste.
  1692. * LPDATAOBJECT lpDataObjectList Pointer to the multiselect snapin item.
  1693. * BOOL * pfPastable Must be set to TRUE if the paste operation is acceptable.
  1694. *
  1695. * RETURNS:
  1696. * SC Execution code
  1697. */
  1698. SC
  1699. CBaseMultiSelectSnapinItem::ScIsPastableDataObject(CBaseSnapin * pSnapin, CBaseSnapinItem * pitemTarget, LPDATAOBJECT lpDataObjectList, BOOL * pfPastable)
  1700. {
  1701. // Declarations
  1702. SC sc = S_OK;
  1703. INT nIterator = 0;
  1704. // Data validation
  1705. ASSERT(pSnapin);
  1706. ASSERT(pitemTarget);
  1707. ASSERT(lpDataObjectList);
  1708. ASSERT(pfPastable);
  1709. // Go through each snapin items for the multiselect snapin items
  1710. for (nIterator=0; nIterator < PivSelectedItems()->size(); nIterator++)
  1711. {
  1712. // Check if we can paste - if any item can not be pasted, then cancel out
  1713. sc = pSnapin->ScIsPastableDataObject(pitemTarget, (*(PivSelectedItems()))[nIterator], pfPastable);
  1714. if (sc)
  1715. goto Error;
  1716. if (!*pfPastable)
  1717. {
  1718. sc = S_FALSE;
  1719. goto Cleanup;
  1720. }
  1721. }
  1722. Cleanup:
  1723. return sc;
  1724. Error:
  1725. *pfPastable = FALSE;
  1726. TraceError(_T("CBaseMultiSelectSnapinItem::ScIsPastableDataObject()"), sc);
  1727. goto Cleanup;
  1728. }
  1729. /* CBaseMultiSelectSnapinItem::MergeMenuItemsVectors
  1730. *
  1731. * PURPOSE: Merges menu item vectors in a smart way.
  1732. * If a menu item in the merge is not found in the list to add, then remove this item from the merge (one snapin item does not support the operation).
  1733. * If a menu item in the merge is found in the list to add, logically combine the flags.
  1734. *
  1735. * PARAMETERS:
  1736. * CSnapinContextMenuItemVectorWrapper * pcmivwForMerge Vector of menu items to merge - will contain the result of the merge
  1737. * CSnapinContextMenuItemVectorWrapper * pcmivwToAdd Vector of menu items to merge - specify what to add here
  1738. */
  1739. void
  1740. CBaseMultiSelectSnapinItem::MergeMenuItems(CSnapinContextMenuItemVectorWrapper * pcmivwForMerge, CSnapinContextMenuItemVectorWrapper * pcmivwToAdd)
  1741. {
  1742. // Declarations
  1743. INT nIteratorToAdd = 0;
  1744. INT nIteratorForMerge = 0;
  1745. // Data validation
  1746. ASSERT(pcmivwForMerge);
  1747. ASSERT(pcmivwToAdd);
  1748. // Iterate through the merge
  1749. for (nIteratorForMerge=0; nIteratorForMerge < pcmivwForMerge->cmiv.size(); nIteratorForMerge++)
  1750. {
  1751. // Local declarations
  1752. BOOL fFound = FALSE; // if we are not able to find, then we must remove them menu item
  1753. // See if we can find in the add a menu item with the same command id and the same insertion point
  1754. for (nIteratorToAdd=0; nIteratorToAdd < pcmivwToAdd->cmiv.size(); nIteratorToAdd++)
  1755. {
  1756. if (((pcmivwToAdd->cmiv)[nIteratorToAdd]->cm.lCommandID == (pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.lCommandID) &&
  1757. ((pcmivwToAdd->cmiv)[nIteratorToAdd]->cm.lInsertionPointID == (pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.lInsertionPointID))
  1758. {
  1759. // Set the new default
  1760. fFound = TRUE;
  1761. // Combine the flags in merge
  1762. (pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.fFlags = (pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.fFlags | (pcmivwToAdd->cmiv)[nIteratorToAdd]->cm.fFlags;
  1763. (pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.fSpecialFlags = (pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.fSpecialFlags | (pcmivwToAdd->cmiv)[nIteratorToAdd]->cm.fSpecialFlags;
  1764. // Handle flag combining exceptions: MF_ENABLED and MF_GRAYED -> MF_GRAYED
  1765. if ((pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.fFlags & (MF_ENABLED | MF_GRAYED))
  1766. (pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.fFlags = (pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.fFlags & ~MF_ENABLED;
  1767. // Handle flag combining exceptions: MF_MENUBARBREAK and MF_MENUBREAK -> MF_MENUBREAK
  1768. if ((pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.fFlags & (MF_MENUBARBREAK | MF_MENUBREAK))
  1769. (pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.fFlags = (pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.fFlags & ~MF_MENUBARBREAK;
  1770. // Handle flag combining exceptions: MF_CHECKED and MF_UNCHECKED -> MF_UNCHECKED
  1771. if ((pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.fFlags & (MF_CHECKED | MF_UNCHECKED))
  1772. (pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.fFlags = (pcmivwForMerge->cmiv)[nIteratorForMerge]->cm.fFlags & ~MF_CHECKED;
  1773. // Stop now
  1774. break;
  1775. }
  1776. }
  1777. // If we were not able to find a menu item from merge in add, we have to remove this menu item because at least one snapin item does not advertise it
  1778. if (!fFound)
  1779. {
  1780. // Delete the pointed context menu item
  1781. if (pcmivwForMerge->cmiv[nIteratorForMerge])
  1782. {
  1783. delete pcmivwForMerge->cmiv[nIteratorForMerge];
  1784. pcmivwForMerge->cmiv[nIteratorForMerge] = NULL;
  1785. }
  1786. pcmivwForMerge->cmiv.erase(&(pcmivwForMerge->cmiv[nIteratorForMerge]));
  1787. nIteratorForMerge--;
  1788. }
  1789. }
  1790. }
  1791. /* CBaseMultiSelectSnapinItem::ScGetMultiSelectDataObject
  1792. *
  1793. * PURPOSE: Determines if an object is a multiselect data object and casts it.
  1794. *
  1795. * PARAMETERS:
  1796. * LPDATAOBJECT lpDataObject Received data object to cast
  1797. * CBaseMultiSelectSnapinItem ** ppMultiSelectSnapinItem Pointer to multiselect pointer - set to NULL we can not convert.
  1798. *
  1799. * RETURNS SC Execution code.
  1800. */
  1801. SC
  1802. CBaseMultiSelectSnapinItem::ScGetMultiSelectDataObject(LPDATAOBJECT lpDataObject, CBaseMultiSelectSnapinItem ** ppMultiSelectSnapinItem)
  1803. {
  1804. // Declarations
  1805. SC sc = S_OK;
  1806. CLSID clsid;
  1807. // Data validation
  1808. ASSERT(lpDataObject);
  1809. ASSERT(ppMultiSelectSnapinItem);
  1810. ASSERT(!*ppMultiSelectSnapinItem);
  1811. // Use the clipboard format to identify the object type
  1812. sc = CBaseDataObject::ScGetNodeType(lpDataObject, &clsid);
  1813. if (sc == SC(DV_E_FORMATETC) )
  1814. {
  1815. SC scNoTrace = sc;
  1816. sc.Clear();
  1817. return scNoTrace;
  1818. }
  1819. if (sc)
  1820. goto Error;
  1821. // If the node type is nodetypeBaseMultiSelect then we know we are a multiselect data object
  1822. if (::IsEqualCLSID(clsid, *(nodetypeBaseMultiSelect.PclsidNodeType())))
  1823. {
  1824. ASSERT(dynamic_cast<CBaseSnapinItem *>(lpDataObject));
  1825. *ppMultiSelectSnapinItem = dynamic_cast<CBaseMultiSelectSnapinItem *>(lpDataObject);
  1826. }
  1827. else
  1828. *ppMultiSelectSnapinItem = NULL;
  1829. Cleanup:
  1830. return sc;
  1831. Error:
  1832. *ppMultiSelectSnapinItem = NULL;
  1833. TraceError(_T("CBaseMultiSelectSnapinItem::ScGetMultiSelectDataObject()"), sc);
  1834. goto Cleanup;
  1835. }
  1836. /* CBaseMultiSelectSnapinItem::ScExtractMultiSelectDataObject
  1837. *
  1838. * PURPOSE: Determines if an object is a composite data object and extracts the correct multiselect snapin item from it.
  1839. *
  1840. * PARAMETERS:
  1841. * CBaseSnapin * psnapin Snapin (used to determine which multiselect data object is the right one in the composite multiselect data object).
  1842. * LPDATAOBJECT lpDataObject Received data object to cast
  1843. * CBaseMultiSelectSnapinItem ** ppMultiSelectSnapinItem Pointer to multiselect pointer - set to NULL we can not convert.
  1844. *
  1845. * RETURNS SC Execution code.
  1846. */
  1847. SC
  1848. CBaseMultiSelectSnapinItem::ScExtractMultiSelectDataObject(CBaseSnapin * psnapin, LPDATAOBJECT lpDataObject, CBaseMultiSelectSnapinItem ** ppMultiSelectSnapinItem)
  1849. {
  1850. // Declarations
  1851. SC sc = S_OK;
  1852. STGMEDIUM stgmedium = {TYMED_HGLOBAL, NULL};
  1853. FORMATETC formatetc = {(CLIPFORMAT)s_cfCompositeDataObject, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1854. BOOL * pfCompositeDataObject = NULL;
  1855. // Data validation
  1856. ASSERT(lpDataObject);
  1857. ASSERT(psnapin);
  1858. ASSERT(ppMultiSelectSnapinItem);
  1859. ASSERT(!*ppMultiSelectSnapinItem);
  1860. // Retrieve data
  1861. sc = lpDataObject->GetData(&formatetc, &stgmedium);
  1862. if (sc)
  1863. {
  1864. sc = S_OK; // ignore the error, consider that we are not a composite data object
  1865. goto Cleanup;
  1866. }
  1867. // Lock memory and cast
  1868. pfCompositeDataObject = (BOOL *)(::GlobalLock(stgmedium.hGlobal));
  1869. ASSERT(pfCompositeDataObject);
  1870. // If the object is a composite data object then extract the correct multiselect snapin item
  1871. if (*pfCompositeDataObject)
  1872. {
  1873. sc = ScExtractMultiSelectObjectFromCompositeMultiSelectObject(psnapin, lpDataObject, ppMultiSelectSnapinItem);
  1874. if (sc)
  1875. goto Error;
  1876. }
  1877. Cleanup:
  1878. // Cleanup allocated resources
  1879. if (pfCompositeDataObject)
  1880. ::GlobalUnlock(stgmedium.hGlobal);
  1881. if (stgmedium.hGlobal)
  1882. ::GlobalFree(stgmedium.hGlobal);
  1883. return sc;
  1884. Error:
  1885. *ppMultiSelectSnapinItem = NULL;
  1886. TraceError(_T("CBaseMultiSelectSnapinItem::ScExtractMultiSelectDataObject()"), sc);
  1887. goto Cleanup;
  1888. }