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.

1978 lines
62 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: cmenu.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. // cmenu.cpp : Implementation of IContextMenuProvider and DLL registration.
  11. #include "stdafx.h"
  12. #include "oncmenu.h"
  13. #include "menuitem.h"
  14. #include "constatbar.h"
  15. #include "regutil.h"
  16. #include "moreutil.h"
  17. #include "multisel.h"
  18. #include "cmenuinfo.h"
  19. #include "conview.h"
  20. #include "scopndcb.h"
  21. #ifdef _DEBUG
  22. #undef THIS_FILE
  23. static char THIS_FILE[] = __FILE__;
  24. #endif
  25. /*+-------------------------------------------------------------------------*
  26. * class CNativeExtendContextMenu
  27. *
  28. *
  29. * PURPOSE: implements IExtendContextMenu by forwarding calls to CContextMenu
  30. * but does not affect lifetime of CContextMenu
  31. *
  32. *+-------------------------------------------------------------------------*/
  33. class CNativeExtendContextMenu :
  34. public CTiedComObject<CContextMenu>,
  35. public CComObjectRoot,
  36. public IExtendContextMenu // this is used so that menu items can be executed uniformly.
  37. {
  38. protected:
  39. typedef CNativeExtendContextMenu ThisClass;
  40. typedef CContextMenu CMyTiedObject;
  41. public:
  42. // com entry points
  43. BEGIN_COM_MAP(ThisClass)
  44. COM_INTERFACE_ENTRY(IExtendContextMenu)
  45. END_COM_MAP()
  46. DECLARE_NOT_AGGREGATABLE(ThisClass)
  47. // IExtendContexMenu methods
  48. MMC_METHOD3( AddMenuItems, LPDATAOBJECT, LPCONTEXTMENUCALLBACK, long * );
  49. MMC_METHOD2( Command, long, LPDATAOBJECT );
  50. };
  51. //############################################################################
  52. //############################################################################
  53. //
  54. // Implementation of methods on CNodeInitObject that
  55. // forward to CContextMenu
  56. //
  57. //############################################################################
  58. //############################################################################
  59. CContextMenu *
  60. CNodeInitObject::GetContextMenu()
  61. {
  62. DECLARE_SC(sc, TEXT("CNodeInitObject::GetContextMenu"));
  63. if(m_spContextMenu == NULL)
  64. {
  65. // check internal pointers
  66. sc = ScCheckPointers(m_spScopeTree, E_UNEXPECTED);
  67. if (sc)
  68. return NULL;
  69. // get scopetree and call back pointers
  70. CScopeTree* const pScopeTree =
  71. dynamic_cast<CScopeTree*>(m_spScopeTree.GetInterfacePtr());
  72. // if the menu is created by component data, it does not have the node.
  73. // in that case menu is created by passing NULL pointers to some parameters.
  74. // Menu should never need those pointers in the mentioned case
  75. CNodeCallback* pNodeCallback = NULL;
  76. if ( m_pNode != NULL )
  77. {
  78. // check other required pointers
  79. sc = ScCheckPointers(m_pNode->GetViewData(), E_UNEXPECTED);
  80. if (sc)
  81. return NULL;
  82. pNodeCallback =
  83. dynamic_cast<CNodeCallback *>(m_pNode->GetViewData()->GetNodeCallback());
  84. }
  85. // create context menu
  86. CContextMenu *pContextMenu = NULL;
  87. sc = CContextMenu::ScCreateContextMenuForScopeNode(m_pNode, pNodeCallback, pScopeTree,
  88. &m_spContextMenu, pContextMenu);
  89. if (sc)
  90. return NULL;
  91. sc = ScCheckPointers(pContextMenu, E_UNEXPECTED);
  92. if (sc)
  93. return NULL;
  94. return pContextMenu;
  95. }
  96. return dynamic_cast<CContextMenu *>(m_spContextMenu.GetInterfacePtr());
  97. }
  98. STDMETHODIMP
  99. CNodeInitObject::AddItem(CONTEXTMENUITEM * pItem)
  100. {
  101. DECLARE_SC(sc, TEXT("CNodeInitObject::AddItem"));
  102. CContextMenu *pContextMenu = GetContextMenu();
  103. sc = ScCheckPointers(pContextMenu, E_UNEXPECTED);
  104. if(sc)
  105. return sc.ToHr();
  106. sc = pContextMenu->ScAddItem(pItem, true/*bPassCommandBackToSnapin*/);
  107. return sc.ToHr();
  108. }
  109. STDMETHODIMP
  110. CNodeInitObject::EmptyMenuList ()
  111. {
  112. DECLARE_SC(sc, TEXT("CNodeInitObject::EmptyMenuList"));
  113. if (m_spContextMenu == NULL)
  114. return S_OK;
  115. CContextMenu *pContextMenu = GetContextMenu();
  116. sc = ScCheckPointers(pContextMenu, E_UNEXPECTED);
  117. if(sc)
  118. return sc.ToHr();
  119. sc = pContextMenu->EmptyMenuList();
  120. return sc.ToHr();
  121. }
  122. STDMETHODIMP
  123. CNodeInitObject::AddThirdPartyExtensionItems(IDataObject* piDataObject )
  124. {
  125. DECLARE_SC(sc, TEXT("CNodeInitObject::AddThirdPartyExtensionItems"));
  126. CContextMenu *pContextMenu = GetContextMenu();
  127. sc = ScCheckPointers(pContextMenu, E_UNEXPECTED);
  128. if(sc)
  129. return sc.ToHr();
  130. sc = pContextMenu->AddThirdPartyExtensionItems(piDataObject);
  131. return sc.ToHr();
  132. }
  133. STDMETHODIMP
  134. CNodeInitObject::AddPrimaryExtensionItems(IUnknown* piCallback, IDataObject* piDataObject )
  135. {
  136. DECLARE_SC(sc, TEXT("CNodeInitObject::AddPrimaryExtensionItems"));
  137. CContextMenu *pContextMenu = GetContextMenu();
  138. sc = ScCheckPointers(pContextMenu, E_UNEXPECTED);
  139. if(sc)
  140. return sc.ToHr();
  141. sc = pContextMenu->AddPrimaryExtensionItems(piCallback, piDataObject);
  142. return sc.ToHr();
  143. }
  144. STDMETHODIMP
  145. CNodeInitObject::ShowContextMenu(HWND hwndParent, LONG xPos, LONG yPos, LONG* plSelected)
  146. {
  147. DECLARE_SC(sc, TEXT("CNodeInitObject::ShowContextMenu"));
  148. CContextMenu *pContextMenu = GetContextMenu();
  149. sc = ScCheckPointers(pContextMenu, E_UNEXPECTED);
  150. if(sc)
  151. return sc.ToHr();
  152. pContextMenu->SetStatusBar(GetStatusBar()); // wire up the status bar.
  153. sc = pContextMenu->ShowContextMenu(hwndParent, xPos, yPos, plSelected);
  154. return sc.ToHr();
  155. }
  156. //############################################################################
  157. //############################################################################
  158. //
  159. // Implementation of CCommandSink
  160. //
  161. //############################################################################
  162. //############################################################################
  163. /*+-------------------------------------------------------------------------*
  164. * class CCommandSink
  165. *
  166. *
  167. * PURPOSE:
  168. *
  169. *+-------------------------------------------------------------------------*/
  170. class CCommandSink : public CWindowImpl<CCommandSink>
  171. {
  172. // Construction
  173. public:
  174. CCommandSink( CContextMenu& nodemgr, WTL::CMenu& menu, CConsoleStatusBar * pStatusbar);
  175. virtual ~CCommandSink();
  176. BOOL Init();
  177. LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
  178. BEGIN_MSG_MAP(CCommandSink)
  179. MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
  180. END_MSG_MAP()
  181. private:
  182. CContextMenu& m_nodemgr;
  183. const WTL::CMenu& m_menu;
  184. CConsoleStatusBar * m_pStatusBar;
  185. };
  186. CCommandSink::CCommandSink( CContextMenu& nodemgr, WTL::CMenu& menu, CConsoleStatusBar * pStatusbar)
  187. : m_nodemgr( nodemgr ),
  188. m_menu( menu ),
  189. m_pStatusBar(pStatusbar)
  190. {
  191. }
  192. CCommandSink::~CCommandSink()
  193. {
  194. }
  195. BOOL CCommandSink::Init()
  196. {
  197. RECT rcPos = {0,0,0,0};
  198. Create(NULL, rcPos, _T("ACFx:CxtMenuSink"), WS_POPUP);
  199. return TRUE;
  200. }
  201. LRESULT CCommandSink::OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  202. {
  203. UINT nItemID = (UINT) LOWORD(wParam); // menu item or submenu index
  204. UINT nFlags = (UINT) HIWORD(wParam); // menu flags
  205. HMENU hSysMenu = (HMENU) lParam; // handle of menu clicked
  206. TRACE(_T("CCommandSink::OnMenuSelect: nItemID=%d, nFlags=0x%X, hSysMenu=0x%X\n"), nItemID, nFlags, hSysMenu);
  207. if ( 0xFFFF == nFlags && NULL == hSysMenu )
  208. {
  209. /*
  210. * The system has closed the menu so
  211. * clear the status bar text, if there's any there.
  212. */
  213. if (m_pStatusBar != NULL)
  214. m_pStatusBar->ScSetStatusText (NULL);
  215. return 0; // as per Win32 ProgRef
  216. }
  217. if ( 0 == nItemID && !(nFlags & MF_POPUP) )
  218. return 0; // no item selected
  219. CMenuItem* pmenuitem = NULL;
  220. if (nFlags & MF_POPUP)
  221. {
  222. if ( hSysMenu == m_menu.m_hMenu )
  223. {
  224. // We assume menu's cannot be longer than 256 chars
  225. TCHAR szMenu[256];
  226. MENUITEMINFO menuItemInfo;
  227. menuItemInfo.cbSize = sizeof(MENUITEMINFO);
  228. menuItemInfo.fMask = MIIM_TYPE;
  229. menuItemInfo.fType = MFT_STRING;
  230. menuItemInfo.cch = 256;
  231. menuItemInfo.dwTypeData = szMenu;
  232. ::GetMenuItemInfo(hSysMenu, nItemID, TRUE, &menuItemInfo);
  233. ASSERT(256 >= (menuItemInfo.cch+1));
  234. pmenuitem = m_nodemgr.FindNthItemInSubmenu( NULL, nItemID, szMenu );
  235. }
  236. else
  237. pmenuitem = m_nodemgr.FindNthItemInSubmenu( hSysMenu, nItemID, NULL );
  238. }
  239. else
  240. pmenuitem = m_nodemgr.FindMenuItem( nItemID );
  241. if ( NULL == pmenuitem )
  242. {
  243. ASSERT( FALSE );
  244. return 0;
  245. }
  246. if(m_pStatusBar)
  247. m_pStatusBar->ScSetStatusText( pmenuitem->GetMenuItemStatusBarText() );
  248. return 0;
  249. }
  250. //############################################################################
  251. //############################################################################
  252. //
  253. // CContextMenu methods - continued from oncmenu.cpp
  254. // These methods were originally in this file and I dont want to move
  255. // them and break history - vivekj
  256. //
  257. //############################################################################
  258. //############################################################################
  259. //+-------------------------------------------------------------------
  260. //
  261. // Member: CContextMenu::EmptyMenuList
  262. //
  263. // Synopsis: Clear the context menu.
  264. //
  265. // Arguments:
  266. //
  267. // Returns: HRESULT
  268. //
  269. //--------------------------------------------------------------------
  270. STDMETHODIMP CContextMenu::EmptyMenuList ()
  271. {
  272. DECLARE_SC(sc, _T("IContextMenuProvider::EmptyMenuList"));
  273. START_CRITSEC_BOTH
  274. delete m_pmenuitemRoot;
  275. m_pmenuitemRoot = NULL;
  276. m_nNextMenuItemID = MENUITEM_BASE_ID;
  277. ReleaseSnapinList();
  278. m_fAddedThirdPartyExtensions = FALSE;
  279. m_MaxPrimaryOwnerID = OWNERID_PRIMARY_MIN;
  280. m_MaxThirdPartyOwnerID = OWNERID_THIRD_PARTY_MIN;
  281. m_CurrentExtensionOwnerID = OWNERID_NATIVE;
  282. m_fPrimaryInsertionFlags = 0;
  283. m_fThirdPartyInsertionFlags = 0;
  284. END_CRITSEC_BOTH
  285. return sc.ToHr();
  286. }
  287. /*+-------------------------------------------------------------------------*
  288. *
  289. * CContextMenu::RemoveAccelerators
  290. *
  291. * PURPOSE: Removes the accelerators from a context menu item name
  292. *
  293. * PARAMETERS:
  294. * CStr & str :
  295. *
  296. * RETURNS:
  297. * void
  298. *
  299. *+-------------------------------------------------------------------------*/
  300. void
  301. RemoveAccelerators(tstring &str)
  302. {
  303. // in some locales , the accelerators appear at the end eg: Start (&s). Therefore, remove anything after (&
  304. int i = str.find(TEXT( "(&" ));
  305. if (i != tstring::npos)
  306. str.erase (i); // remove the waste left over after and including the string "(&"
  307. tstring::iterator itToTrim = std::remove (str.begin(), str.end(), _T('&'));
  308. // remove the waste left over after removing accelerator markers
  309. str.erase (itToTrim, str.end());
  310. }
  311. //+-------------------------------------------------------------------
  312. //
  313. // Member: CContextMenu::AddItem
  314. //
  315. // Synopsis: Add a menu item to context menu.
  316. //
  317. // Arguments: CONTEXTMENUITEM*
  318. //
  319. // Returns: HRESULT
  320. //
  321. //--------------------------------------------------------------------
  322. STDMETHODIMP CContextMenu::AddItem( CONTEXTMENUITEM* pItem )
  323. {
  324. DECLARE_SC(sc, _T("IContextMenuCallback::AddItem"));
  325. return ( sc = ScAddItem( pItem ) ).ToHr();
  326. }
  327. //+-------------------------------------------------------------------
  328. //
  329. // Member: CContextMenu::ScAddItem
  330. //
  331. // Synopsis: Add a menu item to context menu.
  332. //
  333. // Arguments: CONTEXTMENUITEM*
  334. //
  335. // Returns: SC
  336. //
  337. //--------------------------------------------------------------------
  338. SC CContextMenu::ScAddItem( CONTEXTMENUITEM* pItem, bool bPassCommandBackToSnapin /*= false*/ )
  339. {
  340. DECLARE_SC(sc, _T("IContextMenuCallback::ScAddItem"));
  341. if (NULL == pItem)
  342. {
  343. sc = E_INVALIDARG;
  344. TraceSnapinError(_T("NULL CONTEXTMENUITEM ptr"), sc);
  345. return sc;
  346. }
  347. // added a non-langugage independent context menu item. Cook up a language independent ID.
  348. // get the menu text and strip out accelerator markers
  349. tstring strLanguageIndependentName;
  350. if(pItem->strName)
  351. {
  352. USES_CONVERSION;
  353. strLanguageIndependentName = OLE2CT(pItem->strName);
  354. RemoveAccelerators(strLanguageIndependentName);
  355. }
  356. #ifdef DBG
  357. TRACE(_T("CContextMenu::AddItem name \"%ls\" statusbartext \"%ls\" commandID %ld submenuID %ld flags %ld special %ld\n"),
  358. SAFEDBGBSTR(pItem->strName),
  359. SAFEDBGBSTR(pItem->strStatusBarText),
  360. pItem->lCommandID,
  361. pItem->lInsertionPointID,
  362. pItem->fFlags,
  363. pItem->fSpecialFlags);
  364. #endif
  365. // leaves critsec claim for DoAddMenuItem
  366. USES_CONVERSION;
  367. sc = DoAddMenuItem( OLE2CT(pItem->strName),
  368. OLE2CT(pItem->strStatusBarText),
  369. strLanguageIndependentName.data(),
  370. pItem->lCommandID,
  371. pItem->lInsertionPointID,
  372. pItem->fFlags,
  373. pItem->fSpecialFlags,
  374. m_CurrentExtensionOwnerID,
  375. NULL,
  376. bPassCommandBackToSnapin );
  377. return sc;
  378. }
  379. //+-------------------------------------------------------------------
  380. //
  381. // Member: CContextMenu::AddItem
  382. //
  383. // Synopsis: Add a menu item to context menu.
  384. //
  385. // Arguments: CONTEXTMENUITEM2* - includes a language independent name
  386. //
  387. // Returns: HRESULT
  388. //
  389. //--------------------------------------------------------------------
  390. STDMETHODIMP CContextMenu::AddItem( CONTEXTMENUITEM2* pItem )
  391. {
  392. DECLARE_SC(sc, _T("IContextMenuCallback::AddItem"));
  393. if (NULL == pItem)
  394. {
  395. sc = E_INVALIDARG;
  396. TraceSnapinError(_T("NULL CONTEXTMENUITEM ptr"), sc);
  397. return sc.ToHr();
  398. }
  399. // No language-independent-id ?
  400. if ( (pItem->strLanguageIndependentName == NULL) ||
  401. (wcscmp(pItem->strLanguageIndependentName, L"") == 0) )
  402. {
  403. // and it is neither a separator nor insertion point.
  404. if ( !(MF_SEPARATOR & pItem->fFlags) &&
  405. !(CCM_SPECIAL_INSERTION_POINT & pItem->fSpecialFlags) )
  406. {
  407. sc = E_INVALIDARG;
  408. TraceSnapinError(_T("NULL language-indexpendent-id passed"), sc);
  409. return sc.ToHr();
  410. }
  411. }
  412. #ifdef DBG
  413. TRACE(_T("CContextMenu::AddItem name \"%ls\" statusbartext \"%ls\" languageIndependentName \"%ls\" commandID %ld submenuID %ld flags %ld special %ld\n"),
  414. SAFEDBGBSTR(pItem->strName),
  415. SAFEDBGBSTR(pItem->strStatusBarText),
  416. SAFEDBGBSTR(pItem->strLanguageIndependentName),
  417. pItem->lCommandID,
  418. pItem->lInsertionPointID,
  419. pItem->fFlags,
  420. pItem->fSpecialFlags
  421. );
  422. #endif
  423. // leaves critsec claim for DoAddMenuItem
  424. USES_CONVERSION;
  425. sc = DoAddMenuItem( OLE2CT(pItem->strName),
  426. OLE2CT(pItem->strStatusBarText),
  427. OLE2CT(pItem->strLanguageIndependentName),
  428. pItem->lCommandID,
  429. pItem->lInsertionPointID,
  430. pItem->fFlags,
  431. pItem->fSpecialFlags,
  432. m_CurrentExtensionOwnerID );
  433. return sc.ToHr();
  434. }
  435. //+-------------------------------------------------------------------
  436. //
  437. // Member: CContextMenu::AddPrimaryExtensionItems
  438. //
  439. // Synopsis: Ask primary snapin to add menu items.
  440. //
  441. // Arguments: [piExtension]
  442. // [piDataobject]
  443. //
  444. // Note: claims critsec
  445. //
  446. // Returns: HRESULT
  447. //
  448. //--------------------------------------------------------------------
  449. STDMETHODIMP CContextMenu::AddPrimaryExtensionItems (
  450. IUnknown* piExtension,
  451. IDataObject* piDataObject )
  452. {
  453. DECLARE_SC(sc, _T("IContextMenuProvider::AddPrimaryExtensionItems"));
  454. if (NULL == piExtension)
  455. {
  456. sc = E_INVALIDARG;
  457. TraceSnapinError(_T("NULL IUnknown ptr"), sc);
  458. return sc.ToHr();
  459. }
  460. if (NULL == piDataObject)
  461. {
  462. sc = E_INVALIDARG;
  463. TraceSnapinError(_T("NULL IDataObject ptr"), sc);
  464. return sc.ToHr();
  465. }
  466. // control reentrant access to this
  467. if (!m_fAddingPrimaryExtensionItems)
  468. {
  469. m_fAddingPrimaryExtensionItems = true;
  470. //HRESULT hr = ExtractObjectTypeCStr( piDataObject, &m_strObjectGUID );
  471. //ASSERT( SUCCEEDED(hr) );
  472. START_CRITSEC_SNAPIN;
  473. sc = ScAddSnapinToList_IUnknown( piExtension, piDataObject, m_MaxPrimaryOwnerID++ );
  474. END_CRITSEC_SNAPIN;
  475. m_fAddingPrimaryExtensionItems = false;
  476. // Clear view menu allowed flag
  477. // A second call may be made to AddPrimaryExtensionItems to handle the other item
  478. // types only, so the view items must be disabled after the first call.
  479. m_fPrimaryInsertionFlags &= ~CCM_INSERTIONALLOWED_VIEW;
  480. if (sc)
  481. return sc.ToHr();
  482. }
  483. return sc.ToHr();
  484. }
  485. //+-------------------------------------------------------------------
  486. //
  487. // Member: CContextMenu::AddThirdPartyExtensionItems
  488. //
  489. // Synopsis: Ask extensions to add comtext menu items.
  490. //
  491. // Arguments: IDataObject*
  492. //
  493. // Note: claims critsec, potentially for a considerable period of time
  494. //
  495. // Returns: HRESULT
  496. //
  497. //--------------------------------------------------------------------
  498. STDMETHODIMP CContextMenu::AddThirdPartyExtensionItems (
  499. IDataObject* piDataObject )
  500. {
  501. DECLARE_SC(sc, _T("IContextMenuProvider::AddThirdPartyExtensionItems"));
  502. if (NULL == piDataObject)
  503. {
  504. sc = E_INVALIDARG;
  505. TraceSnapinError(_T("NULL piDataObject"), sc);
  506. return sc.ToHr();
  507. }
  508. START_CRITSEC_SNAPIN;
  509. // Extensions may only be added once, otherwise return S_FALSE
  510. if (m_fAddedThirdPartyExtensions == TRUE)
  511. {
  512. sc = S_FALSE;
  513. TraceNodeMgrLegacy(_T("CContextMenu::AddThirdPartyExtensionItems>> Menu already extended"), sc);
  514. return sc.ToHr();
  515. }
  516. m_fAddedThirdPartyExtensions = TRUE;
  517. do // not a loop
  518. {
  519. CExtensionsIterator it;
  520. sc = it.ScInitialize(piDataObject, g_szContextMenu);
  521. if (sc)
  522. {
  523. sc = S_FALSE;
  524. break;
  525. }
  526. BOOL fProblem = FALSE;
  527. for (; it.IsEnd() == FALSE; it.Advance())
  528. {
  529. sc = ScAddSnapinToList_GUID(it.GetCLSID(), piDataObject,
  530. m_MaxThirdPartyOwnerID++);
  531. if (sc)
  532. fProblem = TRUE; // Continue even on error.
  533. }
  534. if (fProblem == TRUE)
  535. sc = S_FALSE;
  536. } while (0);
  537. END_CRITSEC_SNAPIN;
  538. return sc.ToHr();
  539. }
  540. // claims critsec, potentially for a considerable period of time
  541. STDMETHODIMP CContextMenu::AddMultiSelectExtensionItems (
  542. LONG_PTR lMultiSelection)
  543. {
  544. if (lMultiSelection == 0)
  545. return E_INVALIDARG;
  546. CMultiSelection* pMS = reinterpret_cast<CMultiSelection*>(lMultiSelection);
  547. ASSERT(pMS != NULL);
  548. TRACE_METHOD(CContextMenu,AddThirdPartyExtensionItems);
  549. TRACE(_T("CContextMenu::AddThirdPartyExtensionItems"));
  550. START_CRITSEC_SNAPIN;
  551. // Extensions may only be added once, otherwise return S_FALSE
  552. if (m_fAddedThirdPartyExtensions == TRUE)
  553. {
  554. TRACE(_T("CContextMenu::AddThirdPartyExtensionItems>> Menu already extended"));
  555. return S_FALSE;
  556. }
  557. m_fAddedThirdPartyExtensions = TRUE;
  558. do // not a loop
  559. {
  560. CList<CLSID, CLSID&> snapinClsidList;
  561. HRESULT hr = pMS->GetExtensionSnapins(g_szContextMenu, snapinClsidList);
  562. BREAK_ON_FAIL(hr);
  563. POSITION pos = snapinClsidList.GetHeadPosition();
  564. if (pos == NULL)
  565. break;
  566. CLSID clsid;
  567. IDataObjectPtr spDataObject;
  568. hr = pMS->GetMultiSelDataObject(&spDataObject);
  569. ASSERT(SUCCEEDED(hr));
  570. BREAK_ON_FAIL(hr);
  571. BOOL fProblem = FALSE;
  572. while (pos)
  573. {
  574. clsid = snapinClsidList.GetNext(pos);
  575. hr = ScAddSnapinToList_GUID(clsid, spDataObject,
  576. m_MaxThirdPartyOwnerID++).ToHr();
  577. CHECK_HRESULT(hr);
  578. if (FAILED(hr))
  579. fProblem = TRUE; // Continue even on error.
  580. }
  581. if (fProblem == TRUE)
  582. hr = S_FALSE;
  583. } while (0);
  584. END_CRITSEC_SNAPIN;
  585. return S_OK;
  586. }
  587. // Worker function, called recursively by FindMenuItem
  588. // critsec should already be claimed
  589. // If fFindSubmenu, then nMenuItemID is actually an HMENU
  590. CMenuItem* FindWorker( MenuItemList& list, LONG_PTR nMenuItemID, BOOL fFindSubmenu )
  591. {
  592. POSITION pos = list.GetHeadPosition();
  593. while(pos)
  594. {
  595. CMenuItem* pItem = list.GetNext(pos);
  596. if ( !fFindSubmenu && pItem->GetMenuItemID() == nMenuItemID )
  597. {
  598. // Found a match
  599. return pItem;
  600. } else
  601. if ( pItem->HasChildList() )
  602. {
  603. if ( fFindSubmenu &&
  604. pItem->GetPopupMenuHandle() == (HMENU)nMenuItemID &&
  605. !pItem->IsSpecialInsertionPoint() ) // "insertion point" is not real menu
  606. return pItem;
  607. pItem = FindWorker( pItem->GetMenuItemSubmenu(), nMenuItemID, fFindSubmenu );
  608. if (NULL != pItem)
  609. return pItem;
  610. }
  611. }
  612. return NULL;
  613. }
  614. MenuItemList* CContextMenu::GetMenuItemList()
  615. {
  616. if (NULL == m_pmenuitemRoot)
  617. m_pmenuitemRoot = new CRootMenuItem;
  618. if (m_pmenuitemRoot == NULL)
  619. {
  620. return NULL;
  621. }
  622. return &m_pmenuitemRoot->GetMenuItemSubmenu();
  623. }
  624. // critsec should already be claimed
  625. CMenuItem* CContextMenu::FindMenuItem( LONG_PTR nMenuItemID, BOOL fFindSubmenu )
  626. {
  627. DECLARE_SC(sc, TEXT("CContextMenu::FindMenuItem"));
  628. if (0 == nMenuItemID || CCM_INSERTIONPOINTID_ROOT_MENU == nMenuItemID)
  629. return m_pmenuitemRoot;
  630. else
  631. {
  632. MenuItemList* plist = GetMenuItemList();
  633. sc = ScCheckPointers( plist );
  634. if (sc)
  635. return NULL;
  636. return FindWorker( *plist, nMenuItemID, fFindSubmenu );
  637. }
  638. }
  639. /*+-------------------------------------------------------------------------*
  640. *
  641. * ReverseFindWorker
  642. *
  643. * PURPOSE: Worker function, called recursively by ReverseFindMenuItem
  644. * critsec should already be claimed
  645. *
  646. * PARAMETERS:
  647. * MenuItemList& list :
  648. * long nCommandID :
  649. * MENU_OWNER_ID ownerID :
  650. * CStr & strPath :
  651. *
  652. * RETURNS:
  653. * CMenuItem*
  654. *
  655. *+-------------------------------------------------------------------------*/
  656. CMenuItem*
  657. ReverseFindWorker( MenuItemList& list, long nCommandID, MENU_OWNER_ID ownerID, CStr &strPath, CStr &strLanguageIndependentPath )
  658. {
  659. POSITION pos = list.GetHeadPosition();
  660. while(pos)
  661. {
  662. CMenuItem* pItem = list.GetNext(pos);
  663. if ( pItem->GetCommandID() == nCommandID
  664. && ( (pItem->GetMenuItemOwner() == ownerID)
  665. || IsSharedInsertionPointID(nCommandID)
  666. )
  667. )
  668. {
  669. // Found a match - add it to the path and return
  670. strPath = pItem->GetPath();
  671. strLanguageIndependentPath = pItem->GetLanguageIndependentPath();
  672. return pItem;
  673. }
  674. else if ( pItem->HasChildList() )
  675. {
  676. pItem = ReverseFindWorker( pItem->GetMenuItemSubmenu(), nCommandID, ownerID, strPath, strLanguageIndependentPath );
  677. if (NULL != pItem)
  678. {
  679. return pItem;
  680. }
  681. }
  682. }
  683. return NULL;
  684. }
  685. /*+-------------------------------------------------------------------------*
  686. *
  687. * CContextMenu::ReverseFindMenuItem
  688. *
  689. * PURPOSE: Searches for the specified menu item. Also builds up the
  690. * path to the menu item in strPath.
  691. *
  692. * NOTE: critsec should already be claimed
  693. *
  694. * PARAMETERS:
  695. * long nCommandID :
  696. * MENU_OWNER_ID ownerID :
  697. * CStr & strPath :
  698. *
  699. * RETURNS:
  700. * CMenuItem*
  701. *
  702. *+-------------------------------------------------------------------------*/
  703. CMenuItem*
  704. CContextMenu::ReverseFindMenuItem( long nCommandID, MENU_OWNER_ID ownerID, CStr &strPath, CStr &strLanguageIndependentPath)
  705. {
  706. DECLARE_SC(sc, TEXT("CContextMenu::ReverseFindMenuItem"));
  707. strPath = TEXT(""); // initialize
  708. if (CCM_INSERTIONPOINTID_ROOT_MENU == nCommandID)
  709. return m_pmenuitemRoot;
  710. else
  711. {
  712. MenuItemList* plist = GetMenuItemList();
  713. sc = ScCheckPointers( plist );
  714. if (sc)
  715. return NULL;
  716. return ReverseFindWorker( *plist, nCommandID, ownerID, strPath, strLanguageIndependentPath);
  717. }
  718. }
  719. //
  720. // Find Nth item in specified menu/submenu
  721. //
  722. CMenuItem* CContextMenu::FindNthItemInSubmenu( HMENU hmenuParent, UINT iPosition, LPTSTR lpszMenuName )
  723. {
  724. // locate menu/submenu
  725. MenuItemList* plist = GetMenuItemList();
  726. if ( NULL != hmenuParent )
  727. {
  728. CMenuItem* pParent = FindMenuItem( (LONG_PTR)hmenuParent, TRUE );
  729. if ( NULL == pParent )
  730. {
  731. ASSERT( FALSE );
  732. return NULL;
  733. }
  734. plist = &pParent->GetMenuItemSubmenu();
  735. }
  736. if ( NULL == plist )
  737. {
  738. ASSERT( FALSE );
  739. return NULL;
  740. }
  741. // find the Nth item
  742. POSITION pos = plist->GetHeadPosition();
  743. if (NULL != lpszMenuName)
  744. {
  745. while(pos)
  746. {
  747. CMenuItem* pItem = plist->GetNext(pos);
  748. if (! _tcscmp(lpszMenuName, pItem->GetMenuItemName() ))
  749. {
  750. // Found the match
  751. return pItem;
  752. }
  753. }
  754. }
  755. else
  756. {
  757. while(pos)
  758. {
  759. CMenuItem* pItem = plist->GetNext(pos);
  760. if ( 0 == iPosition-- )
  761. {
  762. // Found a match
  763. return pItem;
  764. }
  765. }
  766. }
  767. ASSERT( FALSE );
  768. return NULL;
  769. }
  770. // claims critsec
  771. STDMETHODIMP CContextMenu::DoAddMenuItem(LPCTSTR lpszName,
  772. LPCTSTR lpszStatusBarText,
  773. LPCTSTR lpszLanguageIndependentName,
  774. LONG lCommandID,
  775. LONG lInsertionPointID,
  776. LONG fFlags,
  777. LONG fSpecialFlags,
  778. MENU_OWNER_ID ownerID,
  779. CMenuItem** ppMenuItem /* = NULL */,
  780. bool bPassCommandBackToSnapin /*= false*/ )
  781. {
  782. DECLARE_SC(sc, TEXT("CContextMenu::DoAddMenuItem"));
  783. // init out param
  784. if (ppMenuItem)
  785. *ppMenuItem = NULL;
  786. // Save test flag now because special flags are modified below
  787. BOOL bTestOnly = fSpecialFlags & CCM_SPECIAL_TESTONLY;
  788. if ( OWNERID_INVALID == ownerID )
  789. {
  790. TRACE(_T("CContextMenu::DoAddMenuItem(): invalid ownerid"));
  791. ASSERT(FALSE);
  792. return E_INVALIDARG;
  793. }
  794. if ( (CCM_SPECIAL_SEPARATOR & fSpecialFlags)?0:1
  795. + ((CCM_SPECIAL_SUBMENU|CCM_SPECIAL_DEFAULT_ITEM) & fSpecialFlags)?0:1
  796. + (CCM_SPECIAL_INSERTION_POINT & fSpecialFlags)?0:1
  797. > 1 )
  798. {
  799. TRACE(_T("CContextMenu::DoAddMenuItem(): invalid combination of special flags"));
  800. ASSERT(FALSE);
  801. return E_INVALIDARG;
  802. }
  803. if (CCM_SPECIAL_SEPARATOR & fSpecialFlags)
  804. {
  805. lpszName = NULL;
  806. lpszStatusBarText = NULL;
  807. lCommandID = 0;
  808. fFlags = MF_SEPARATOR | MF_GRAYED | MF_DISABLED;
  809. }
  810. if ( CCM_SPECIAL_INSERTION_POINT & fSpecialFlags )
  811. {
  812. fFlags = NULL; // be sure to clear MF_POPUP
  813. fSpecialFlags = CCM_SPECIAL_INSERTION_POINT;
  814. }
  815. if ( (CCM_SPECIAL_SUBMENU & fSpecialFlags) && !(MF_POPUP & fFlags) )
  816. {
  817. TRACE(_T("CContextMenu::DoAddMenuItem(): CCM_SPECIAL_SUBMENU requires MF_POPUP"));
  818. ASSERT(FALSE);
  819. return E_INVALIDARG;
  820. }
  821. if ( (MF_OWNERDRAW|MF_BITMAP) & fFlags )
  822. {
  823. TRACE(_T("CContextMenu::DoAddMenuItem(): MF_OWNERDRAW and MF_BITMAP are invalid"));
  824. ASSERT(FALSE);
  825. return E_INVALIDARG;
  826. }
  827. else if ( !(MF_SEPARATOR & fFlags) &&
  828. !(CCM_SPECIAL_INSERTION_POINT & fSpecialFlags) &&
  829. NULL == lpszName )
  830. {
  831. TRACE(_T("CContextMenu::DoAddMenuItem(): invalid menuitem text\n"));
  832. ASSERT(FALSE);
  833. return E_INVALIDARG;
  834. }
  835. // note that NULL==lpszStatusBarText is permitted
  836. START_CRITSEC_MENU;
  837. //
  838. // An insertion point of 0 is interpreted the same as CCM_INSERTIONPOINTID_ROOT_MENU
  839. //
  840. if (0 == lInsertionPointID)
  841. lInsertionPointID = CCM_INSERTIONPOINTID_ROOT_MENU;
  842. //
  843. // Check that the insertion point ID specified is legal for this customer
  844. //
  845. do // false loop
  846. {
  847. if ( !IsSpecialInsertionPointID(lInsertionPointID) )
  848. break;
  849. if ( IsReservedInsertionPointID(lInsertionPointID) )
  850. {
  851. TRACE(_T("CContextMenu::DoAddMenuItem(): using reserved insertion point ID\n"));
  852. return E_INVALIDARG;
  853. }
  854. if ( !IsSharedInsertionPointID(lInsertionPointID) )
  855. break;
  856. if ( !IsAddPrimaryInsertionPointID(lInsertionPointID) )
  857. {
  858. if ( IsPrimaryOwnerID(ownerID) )
  859. {
  860. TRACE(_T("CContextMenu::DoAddMenuItem(): not addprimary insertion point ID\n"));
  861. return E_INVALIDARG;
  862. }
  863. }
  864. if ( !IsAdd3rdPartyInsertionPointID(lInsertionPointID) )
  865. {
  866. if ( IsThirdPartyOwnerID(ownerID) )
  867. {
  868. TRACE(_T("CContextMenu::DoAddMenuItem(): not add3rdpartyinsertion point ID\n"));
  869. return E_INVALIDARG;
  870. }
  871. }
  872. } while (FALSE); // false loop
  873. //
  874. // Check that the command ID specified is legal for this customer
  875. //
  876. if ( (MF_POPUP & fFlags) || (CCM_SPECIAL_INSERTION_POINT & fSpecialFlags) )
  877. {
  878. do // false loop
  879. {
  880. if ( !IsSpecialInsertionPointID(lCommandID) )
  881. break;
  882. if ( IsReservedInsertionPointID(lCommandID) )
  883. {
  884. TRACE(_T("CContextMenu::DoAddMenuItem(): adding reserved insertion point ID\n"));
  885. ASSERT(FALSE);
  886. return E_INVALIDARG;
  887. }
  888. if ( !IsSharedInsertionPointID(lCommandID) )
  889. break;
  890. if ( IsThirdPartyOwnerID(ownerID) )
  891. {
  892. TRACE(_T("CContextMenu::DoAddMenuItem(): 3rdparty cannot add shared insertion point"));
  893. ASSERT(FALSE);
  894. return E_INVALIDARG;
  895. }
  896. else if ( IsPrimaryOwnerID(ownerID) )
  897. {
  898. if ( !IsCreatePrimaryInsertionPointID(lCommandID) )
  899. {
  900. TRACE(_T("CContextMenu::DoAddMenuItem(): only system for new !PRIMARYCREATE submenu"));
  901. ASSERT(FALSE);
  902. return E_INVALIDARG;
  903. }
  904. }
  905. else if ( IsSystemOwnerID(ownerID) )
  906. {
  907. if ( IsCreatePrimaryInsertionPointID(lCommandID) )
  908. {
  909. TRACE(_T("CContextMenu::DoAddMenuItem(): only primary extension for new PRIMARYCREATE submenu"));
  910. ASSERT(FALSE);
  911. return E_INVALIDARG;
  912. }
  913. }
  914. } while (FALSE); // false loop
  915. }
  916. else if ( !(CCM_SPECIAL_SEPARATOR & fSpecialFlags) )
  917. {
  918. if ( IsReservedCommandID(lCommandID) )
  919. {
  920. TRACE(_T("CContextMenu::DoAddMenuItem(): no new RESERVED menu items"));
  921. ASSERT(FALSE);
  922. return E_INVALIDARG;
  923. }
  924. }
  925. if (NULL == m_pmenuitemRoot)
  926. m_pmenuitemRoot = new CRootMenuItem;
  927. CStr strPath, strLanguageIndependentPath; // this builds up the path of the menu item.
  928. CMenuItem* pParent = ReverseFindMenuItem( lInsertionPointID, ownerID, strPath, strLanguageIndependentPath);
  929. if (NULL == pParent)
  930. {
  931. TRACE(_T("CContextMenu::DoAddMenuItem(): submenu with command ID %ld owner %ld does not exist"), lInsertionPointID, ownerID );
  932. ASSERT(FALSE);
  933. return E_INVALIDARG;
  934. }
  935. MenuItemList& rMenuList = pParent->GetMenuItemSubmenu();
  936. // If this is only a test add, return with success now
  937. if (bTestOnly)
  938. return S_OK;
  939. // get the data object and IExtendContextMenu pointer to set in the item.
  940. IExtendContextMenuPtr spExtendContextMenu;
  941. IDataObject* pDataObject = NULL; // This is used JUST to hold on to the object until Command completes.
  942. // locate the IExtendContextMenu of the snapin.
  943. {
  944. // The selected item was added by an extension
  945. SnapinStruct* psnapin = FindSnapin( ownerID );
  946. if(psnapin != NULL)
  947. {
  948. pDataObject = psnapin->m_pIDataObject;
  949. spExtendContextMenu = psnapin->pIExtendContextMenu;
  950. }
  951. else
  952. {
  953. CTiedComObjectCreator<CNativeExtendContextMenu>::
  954. ScCreateAndConnect(*this, spExtendContextMenu);
  955. // built in items are handled by CContextMenu itself.
  956. }
  957. }
  958. // compute the language independent and language dependent paths for the context menu item.
  959. CStr strLanguageIndependentName = lpszLanguageIndependentName;
  960. tstring tstrName = lpszName ? lpszName : TEXT("");
  961. RemoveAccelerators(tstrName);
  962. CStr strName;
  963. strName = tstrName.data(); // got to standardise on either tstring or CStr
  964. // add a "->" separator to the path if needed
  965. if(!strPath.IsEmpty() && !strName.IsEmpty())
  966. strPath += _T("->");
  967. strPath += strName;
  968. // add a "->" separator to the language independent path if needed
  969. if(!strLanguageIndependentPath.IsEmpty() && !strLanguageIndependentName.IsEmpty())
  970. strLanguageIndependentPath += _T("->");
  971. strLanguageIndependentPath += strLanguageIndependentName;
  972. CMenuItem* pItem = new CMenuItem(
  973. lpszName,
  974. lpszStatusBarText,
  975. lpszLanguageIndependentName,
  976. (LPCTSTR)strPath,
  977. (LPCTSTR)strLanguageIndependentPath,
  978. lCommandID,
  979. m_nNextMenuItemID++,
  980. fFlags,
  981. ownerID,
  982. spExtendContextMenu,
  983. pDataObject,
  984. fSpecialFlags,
  985. bPassCommandBackToSnapin);
  986. ASSERT( pItem );
  987. if (pItem == NULL)
  988. return E_OUTOFMEMORY;
  989. rMenuList.AddTail(pItem);
  990. // If this is a system defined insertion point, update the insertion flags
  991. if (IsSharedInsertionPointID(lCommandID) && !IsCreatePrimaryInsertionPointID(lCommandID))
  992. {
  993. long fFlag = ( 1L << (lCommandID & CCM_INSERTIONPOINTID_MASK_FLAGINDEX));
  994. if (IsAddPrimaryInsertionPointID(lCommandID))
  995. m_fPrimaryInsertionFlags |= fFlag;
  996. if (IsAdd3rdPartyInsertionPointID(lCommandID))
  997. m_fThirdPartyInsertionFlags |= fFlag;
  998. }
  999. // return the item if required
  1000. if (ppMenuItem)
  1001. *ppMenuItem = pItem;
  1002. END_CRITSEC_MENU;
  1003. return S_OK;
  1004. }
  1005. // APP HACK. Workarounding dependency on older FP where they were QI'ing for IConsole from
  1006. // IContextMenuCallback, which was working in MMC 1.2, but cannot work in mmc 2.0
  1007. // See bug 200621 (Windows bugs (ntbug9) 11/15/2000)
  1008. #define WORKAROUND_FOR_FP_REQUIRED
  1009. #if defined (WORKAROUND_FOR_FP_REQUIRED)
  1010. /***************************************************************************\
  1011. *
  1012. * CLASS: CWorkaroundWrapperForFrontPageMenu
  1013. *
  1014. * PURPOSE: Used from subclassed MMC's IExtendContextMenu interface for FrontPage.
  1015. * Contains (in com sense) IContextMenuCallback2 and IContextMenuCallback by forwarding
  1016. * them to original interface, but in addition supports QI for IConsole.
  1017. * This is a requirement for older FrontPage to work
  1018. *
  1019. \***************************************************************************/
  1020. class CWorkaroundWrapperForFrontPageMenu :
  1021. public IContextMenuCallback,
  1022. public IContextMenuCallback2,
  1023. public IConsole2, // workaround for bug 200621. This is a dummy implementation of IConsole2
  1024. public CComObjectRoot
  1025. {
  1026. friend class CWorkaroundMMCWrapperForFrontPageMenu;
  1027. // pointer to context menu object
  1028. IContextMenuCallbackPtr m_spIContextMenuCallback;
  1029. IContextMenuCallback2Ptr m_spIContextMenuCallback2;
  1030. public:
  1031. typedef CWorkaroundWrapperForFrontPageMenu ThisClass;
  1032. // com entry points
  1033. BEGIN_COM_MAP(ThisClass)
  1034. COM_INTERFACE_ENTRY(IContextMenuCallback) // the IContextMenuProvider and IContextMenu
  1035. COM_INTERFACE_ENTRY(IContextMenuCallback2)
  1036. COM_INTERFACE_ENTRY(IConsole)
  1037. COM_INTERFACE_ENTRY(IConsole2)
  1038. END_COM_MAP()
  1039. // just forward...
  1040. STDMETHOD(AddItem) ( CONTEXTMENUITEM* pItem )
  1041. {
  1042. if ( m_spIContextMenuCallback == NULL )
  1043. return E_UNEXPECTED;
  1044. return m_spIContextMenuCallback->AddItem( pItem );
  1045. }
  1046. // just forward...
  1047. STDMETHOD(AddItem) ( CONTEXTMENUITEM2* pItem )
  1048. {
  1049. if ( m_spIContextMenuCallback2 == NULL )
  1050. return E_UNEXPECTED;
  1051. return m_spIContextMenuCallback2->AddItem( pItem );
  1052. }
  1053. // IConsole2 methods - DUMMY - workaround for bug 200621
  1054. STDMETHOD(SetHeader)( LPHEADERCTRL pHeader) {return E_NOTIMPL;}
  1055. STDMETHOD(SetToolbar)( LPTOOLBAR pToolbar) {return E_NOTIMPL;}
  1056. STDMETHOD(QueryResultView)( LPUNKNOWN* pUnknown) {return E_NOTIMPL;}
  1057. STDMETHOD(QueryScopeImageList)( LPIMAGELIST* ppImageList) {return E_NOTIMPL;}
  1058. STDMETHOD(QueryResultImageList)( LPIMAGELIST* ppImageList) {return E_NOTIMPL;}
  1059. STDMETHOD(UpdateAllViews)( LPDATAOBJECT lpDataObject,LPARAM data,LONG_PTR hint) {return E_NOTIMPL;}
  1060. STDMETHOD(MessageBox)( LPCWSTR lpszText, LPCWSTR lpszTitle,UINT fuStyle, int* piRetval) {return E_NOTIMPL;}
  1061. STDMETHOD(QueryConsoleVerb)( LPCONSOLEVERB * ppConsoleVerb) {return E_NOTIMPL;}
  1062. STDMETHOD(SelectScopeItem)( HSCOPEITEM hScopeItem) {return E_NOTIMPL;}
  1063. STDMETHOD(GetMainWindow)( HWND* phwnd)
  1064. {
  1065. if (!phwnd)
  1066. return E_INVALIDARG;
  1067. *phwnd = (CScopeTree::GetScopeTree() ? CScopeTree::GetScopeTree()->GetMainWindow() : NULL);
  1068. return S_OK;
  1069. }
  1070. STDMETHOD(NewWindow)( HSCOPEITEM hScopeItem, unsigned long lOptions) {return E_NOTIMPL;}
  1071. STDMETHOD(Expand)( HSCOPEITEM hItem, BOOL bExpand) {return E_NOTIMPL;}
  1072. STDMETHOD(IsTaskpadViewPreferred)() {return E_NOTIMPL;}
  1073. STDMETHOD(SetStatusText )( LPOLESTR pszStatusText) {return E_NOTIMPL;}
  1074. };
  1075. /***************************************************************************\
  1076. *
  1077. * CLASS: CWorkaroundMMCWrapperForFrontPageMenu
  1078. *
  1079. * PURPOSE: Subclasses MMC's IExtendContextMenu interface for FrontPage.
  1080. * Contains ( in com sense) IExtendContextMenu; Forwards calls to default MMC implementation,
  1081. * but for AddMenuItems gives itself as a callback interface.
  1082. * [ main purpose to have this object is to avoid changing main MMC functions ]
  1083. * [ to implement this workaround ]
  1084. *
  1085. \***************************************************************************/
  1086. class CWorkaroundMMCWrapperForFrontPageMenu :
  1087. public IExtendContextMenu,
  1088. public CComObjectRoot
  1089. {
  1090. // pointer to context menu object
  1091. IExtendContextMenuPtr m_spExtendContextMenu;
  1092. CNode *m_pNode;
  1093. public:
  1094. typedef CWorkaroundMMCWrapperForFrontPageMenu ThisClass;
  1095. // this method is null for all snapins, but FrontPage
  1096. // for FrontPage it wraps and replaces spIUnknown paramter
  1097. static SC ScSubclassFP(const CLSID& clsid,IUnknownPtr &spIUnknown)
  1098. {
  1099. DECLARE_SC(sc, TEXT("CWorkaroundMMCWrapperForFrontPageMenu::ScSubclassFP"));
  1100. static const CLSID CLSID_Fpsrvmmc = { 0xFF5903A8, 0x78D6, 0x11D1,
  1101. { 0x92, 0xF6, 0x00, 0x60, 0x97, 0xB0, 0x10, 0x56 } };
  1102. // only required intercept one clsid
  1103. if ( clsid != CLSID_Fpsrvmmc )
  1104. return sc;
  1105. // create self
  1106. typedef CComObject<CWorkaroundMMCWrapperForFrontPageMenu> ThisComObj_t;
  1107. ThisComObj_t *pObj = NULL;
  1108. sc = ThisComObj_t::CreateInstance(&pObj);
  1109. if (sc)
  1110. return sc;
  1111. // cast to avoid member access problems (workarounding compiler)
  1112. ThisClass *pThis = pObj;
  1113. sc = ScCheckPointers( pThis, E_UNEXPECTED );
  1114. if (sc)
  1115. return sc;
  1116. // maintain the lifetime in case of accident
  1117. IUnknownPtr spThis = pThis->GetUnknown();
  1118. // grab on snapin's interface
  1119. pThis->m_spExtendContextMenu = spIUnknown;
  1120. sc = ScCheckPointers( pThis->m_spExtendContextMenu, E_UNEXPECTED );
  1121. if (sc)
  1122. return sc;
  1123. // substitute the snapin (in-out parameter)
  1124. spIUnknown = spThis;
  1125. return sc;
  1126. }
  1127. // com entry points
  1128. BEGIN_COM_MAP(ThisClass)
  1129. COM_INTERFACE_ENTRY(IExtendContextMenu)
  1130. END_COM_MAP()
  1131. // AddMenuItems is the method this object exists for.
  1132. // If we got here, mmc is about to ask FrontPage to add its items to context menu.
  1133. // We'll wrap the callback interface given by MMC with the object implementing
  1134. // phony IConsole - this is required for older FP to work
  1135. STDMETHOD(AddMenuItems)( LPDATAOBJECT piDataObject, LPCONTEXTMENUCALLBACK piCallback, long * pInsertionAllowed )
  1136. {
  1137. DECLARE_SC(sc, TEXT("CWorkaroundMMCWrapperForFrontPageMenu::AddMenuItems"));
  1138. IContextMenuCallbackPtr spIContextMenuCallback = piCallback;
  1139. IContextMenuCallback2Ptr spIContextMenuCallback2 = piCallback;
  1140. if ( m_spExtendContextMenu == NULL || spIContextMenuCallback == NULL || spIContextMenuCallback2 == NULL )
  1141. return E_UNEXPECTED;
  1142. // create a wrapper for FP
  1143. typedef CComObject<CWorkaroundWrapperForFrontPageMenu> WrapperComObj_t;
  1144. WrapperComObj_t *pObj = NULL;
  1145. sc = WrapperComObj_t::CreateInstance(&pObj);
  1146. if (sc)
  1147. return sc.ToHr();
  1148. // cast to avoid member access problems (workarounding compiler)
  1149. CWorkaroundWrapperForFrontPageMenu *pWrapper = pObj;
  1150. sc = ScCheckPointers( pWrapper, E_UNEXPECTED );
  1151. if (sc)
  1152. return sc.ToHr();
  1153. // maintain the lifetime in case of accident
  1154. IUnknownPtr spWrapper = pWrapper->GetUnknown();
  1155. // grab on snapin's interface
  1156. pWrapper->m_spIContextMenuCallback = spIContextMenuCallback;
  1157. pWrapper->m_spIContextMenuCallback2 = spIContextMenuCallback2;
  1158. // call snapin on behave on mmc, but pass itself as callback
  1159. sc = m_spExtendContextMenu->AddMenuItems( piDataObject, pWrapper, pInsertionAllowed );
  1160. // fall thru even on error - need to release interfaces
  1161. // reset callback interfaces - not valid after the call anyway...
  1162. // this will let context menu go, and prevent FP from suicide (AV);
  1163. // Following this all calls to IContextMenuCallback would fail,
  1164. // but that's ok, since it is not legal to call them after AddMenuItems.
  1165. pWrapper->m_spIContextMenuCallback = NULL;
  1166. pWrapper->m_spIContextMenuCallback2 = NULL;
  1167. return sc.ToHr();
  1168. }
  1169. // simply forward....
  1170. STDMETHOD(Command)(long lCommandID, LPDATAOBJECT piDataObject)
  1171. {
  1172. ASSERT( m_spExtendContextMenu != NULL );
  1173. if ( m_spExtendContextMenu == NULL )
  1174. return E_UNEXPECTED;
  1175. return m_spExtendContextMenu->Command(lCommandID, piDataObject);
  1176. }
  1177. };
  1178. #endif // defined (WORKAROUND_FOR_FP_REQUIRED)
  1179. // critsec should already be claimed
  1180. SC CContextMenu::ScAddSnapinToList_GUID(
  1181. const CLSID& clsid,
  1182. IDataObject* piDataObject,
  1183. MENU_OWNER_ID ownerID )
  1184. {
  1185. DECLARE_SC(sc, TEXT("CContextMenu::ScAddSnapinToList_GUID"));
  1186. // cocreate extension
  1187. IUnknownPtr spIUnknown;
  1188. sc = ::CoCreateInstance(clsid, NULL, MMC_CLSCTX_INPROC,
  1189. IID_IUnknown, (LPVOID*)&spIUnknown);
  1190. if (sc)
  1191. return sc;
  1192. #if defined (WORKAROUND_FOR_FP_REQUIRED)
  1193. sc = CWorkaroundMMCWrapperForFrontPageMenu::ScSubclassFP(clsid, spIUnknown);
  1194. #endif // defined (WORKAROUND_FOR_FP_REQUIRED)
  1195. // get IExtendContextMenu interface
  1196. IExtendContextMenuPtr spIExtendContextMenu = spIUnknown;
  1197. sc = ScCheckPointers(spIExtendContextMenu, E_NOINTERFACE);
  1198. if (sc)
  1199. return sc;
  1200. // add menu items
  1201. sc = ScAddSnapinToList_IExtendContextMenu(spIExtendContextMenu,
  1202. piDataObject, ownerID );
  1203. if (sc)
  1204. return sc;
  1205. return sc;
  1206. }
  1207. // does not AddRef() or Release() interface pointer
  1208. // critsec should already be claimed
  1209. SC CContextMenu::ScAddSnapinToList_IUnknown(
  1210. IUnknown* piExtension,
  1211. IDataObject* piDataObject,
  1212. MENU_OWNER_ID ownerID )
  1213. {
  1214. DECLARE_SC(sc, TEXT("CContextMenu::AddSnapinToList_IUnknown"));
  1215. // parameter check
  1216. sc = ScCheckPointers(piExtension);
  1217. if (sc)
  1218. return sc;
  1219. IExtendContextMenuPtr spIExtendContextMenu = piExtension;
  1220. if (spIExtendContextMenu == NULL)
  1221. return sc; // snapin does not extend context menus
  1222. // add menu items
  1223. sc = ScAddSnapinToList_IExtendContextMenu( spIExtendContextMenu, piDataObject, ownerID );
  1224. if (sc)
  1225. return sc;
  1226. return sc;
  1227. }
  1228. // Interface pointer is Release()d when menu list is emptied
  1229. // critsec should already be claimed
  1230. SC CContextMenu::ScAddSnapinToList_IExtendContextMenu(
  1231. IExtendContextMenu* pIExtendContextMenu,
  1232. IDataObject* piDataObject,
  1233. MENU_OWNER_ID ownerID )
  1234. {
  1235. DECLARE_SC(sc, TEXT("CContextMenu::ScAddSnapinToList_IExtendContextMenu"));
  1236. // parameter check
  1237. sc = ScCheckPointers(pIExtendContextMenu);
  1238. if (sc)
  1239. return sc;
  1240. SnapinStruct* psnapstruct = new SnapinStruct( pIExtendContextMenu, piDataObject, ownerID );
  1241. sc = ScCheckPointers(psnapstruct, E_OUTOFMEMORY);
  1242. if (sc)
  1243. return sc;
  1244. m_SnapinList->AddTail(psnapstruct);
  1245. m_CurrentExtensionOwnerID = ownerID;
  1246. long fInsertionFlags = IsPrimaryOwnerID(ownerID) ? m_fPrimaryInsertionFlags : m_fThirdPartyInsertionFlags;
  1247. // if view items are requested, then allow only view items
  1248. // view item requests go to the IComponent. If other item types are allowed there
  1249. // will be a second pass through this code directed to the IComponentData.
  1250. long lTempFlags = fInsertionFlags;
  1251. if ( fInsertionFlags & CCM_INSERTIONALLOWED_VIEW )
  1252. lTempFlags = CCM_INSERTIONALLOWED_VIEW;
  1253. //catch all exceptions to show diagnostics to aid end-user in debugging
  1254. //exception is rethrown after diagnostics
  1255. try
  1256. {
  1257. sc = pIExtendContextMenu->AddMenuItems( piDataObject, this, &lTempFlags );
  1258. #ifdef DBG
  1259. if (sc)
  1260. TraceSnapinError(_T("IExtendContextMenu::AddMenuItems failed"), sc);
  1261. #endif
  1262. }
  1263. catch (...)
  1264. {
  1265. if (DOBJ_CUSTOMOCX == piDataObject)
  1266. {
  1267. ASSERT( FALSE && "IExtendContextMenu::AddMenuItem of IComponent is called with DOBJ_CUSTOMOCX; snapin potentially derefed this custom data object. Please handle special dataobjects in your snapin.");
  1268. }
  1269. else if (DOBJ_CUSTOMWEB == piDataObject)
  1270. {
  1271. ASSERT( FALSE && "IExtendContextMenu::AddMenuItem of IComponent is called with DOBJ_CUSTOMWEB; snapin potentially derefed this custom data object. Please handle special dataobjects in your snapin.");
  1272. }
  1273. else
  1274. {
  1275. ASSERT( FALSE && "IExtendContextMenu::AddMenuItem implemented by snapin has thrown an exception.");
  1276. }
  1277. throw;
  1278. }
  1279. m_CurrentExtensionOwnerID = OWNERID_NATIVE;
  1280. if (sc)
  1281. return sc;
  1282. // Primary snapin is allowed to clear extension snapin insertion flags
  1283. if ( IsPrimaryOwnerID(ownerID) )
  1284. m_fThirdPartyInsertionFlags &= fInsertionFlags;
  1285. return sc;
  1286. }
  1287. // All snapin interface pointers are Release()d
  1288. // critsec should already be claimed
  1289. void CContextMenu::ReleaseSnapinList()
  1290. {
  1291. ASSERT(m_SnapinList != NULL);
  1292. if (m_SnapinList != NULL && m_SnapinList->GetCount() != 0)
  1293. {
  1294. POSITION pos = m_SnapinList->GetHeadPosition();
  1295. while(pos)
  1296. {
  1297. SnapinStruct* pItem = (SnapinStruct*)m_SnapinList->GetNext(pos);
  1298. ASSERT_OBJECTPTR( pItem );
  1299. delete pItem;
  1300. }
  1301. m_SnapinList->RemoveAll();
  1302. }
  1303. }
  1304. // critsec should already be claimed
  1305. SnapinStruct* CContextMenu::FindSnapin( MENU_OWNER_ID ownerID )
  1306. {
  1307. ASSERT(m_SnapinList != NULL);
  1308. if (m_SnapinList != NULL && m_SnapinList->GetCount() != 0)
  1309. {
  1310. POSITION pos = m_SnapinList->GetHeadPosition();
  1311. while(pos)
  1312. {
  1313. SnapinStruct* pItem = (SnapinStruct*)m_SnapinList->GetNext(pos);
  1314. ASSERT( NULL != pItem );
  1315. if ( ownerID == pItem->m_OwnerID )
  1316. return pItem;
  1317. }
  1318. }
  1319. return NULL;
  1320. }
  1321. // Worker function, called recursively by ShowContextMenu
  1322. // critsec should already be claimed
  1323. HRESULT CollapseInsertionPoints( CMenuItem* pmenuitemParent )
  1324. {
  1325. ASSERT( NULL != pmenuitemParent && !pmenuitemParent->IsSpecialInsertionPoint() );
  1326. MenuItemList& rMenuList = pmenuitemParent->GetMenuItemSubmenu();
  1327. POSITION pos = rMenuList.GetHeadPosition();
  1328. while(pos)
  1329. {
  1330. POSITION posThisItem = pos;
  1331. CMenuItem* pItem = (rMenuList.GetNext(pos));
  1332. ASSERT( pItem != NULL );
  1333. if ( pItem->IsPopupMenu() )
  1334. {
  1335. ASSERT( !pItem->IsSpecialInsertionPoint() );
  1336. HRESULT hr = CollapseInsertionPoints( pItem );
  1337. if ( FAILED(hr) )
  1338. {
  1339. ASSERT( FALSE );
  1340. return hr;
  1341. }
  1342. continue;
  1343. }
  1344. if ( !pItem->IsSpecialInsertionPoint() )
  1345. continue;
  1346. // we found an insertion point, move its items into this list
  1347. MenuItemList& rInsertedList = pItem->GetMenuItemSubmenu();
  1348. POSITION posInsertAfterThis = posThisItem;
  1349. while ( !rInsertedList.IsEmpty() )
  1350. {
  1351. CMenuItem* pInsertedItem = rInsertedList.RemoveHead();
  1352. posInsertAfterThis = rMenuList.InsertAfter( posInsertAfterThis, pInsertedItem );
  1353. }
  1354. // delete the insertion point item
  1355. rMenuList.RemoveAt(posThisItem);
  1356. delete pItem;
  1357. // restart at head of list, in case of recursive insertion points
  1358. pos = rMenuList.GetHeadPosition();
  1359. }
  1360. return S_OK;
  1361. }
  1362. // Worker function, called recursively by ShowContextMenu
  1363. // critsec should already be claimed and CollapseInsertionPoints should have been called
  1364. HRESULT CollapseSpecialSeparators( CMenuItem* pmenuitemParent )
  1365. {
  1366. ASSERT( NULL != pmenuitemParent && !pmenuitemParent->IsSpecialInsertionPoint() );
  1367. MenuItemList& rMenuList = pmenuitemParent->GetMenuItemSubmenu();
  1368. CMenuItem* pItem = NULL;
  1369. BOOL fLastItemWasReal = FALSE;
  1370. POSITION pos = rMenuList.GetHeadPosition();
  1371. POSITION posThisItem = pos;
  1372. while(pos)
  1373. {
  1374. posThisItem = pos;
  1375. pItem = (rMenuList.GetNext(pos));
  1376. ASSERT( pItem != NULL );
  1377. ASSERT( !pItem->IsSpecialInsertionPoint() );
  1378. if ( pItem->IsPopupMenu() )
  1379. {
  1380. ASSERT( !pItem->IsSpecialSeparator() );
  1381. HRESULT hr = CollapseSpecialSeparators( pItem );
  1382. if ( FAILED(hr) )
  1383. {
  1384. ASSERT( FALSE );
  1385. return hr;
  1386. }
  1387. fLastItemWasReal = TRUE;
  1388. continue;
  1389. }
  1390. if ( !pItem->IsSpecialSeparator() )
  1391. {
  1392. fLastItemWasReal = TRUE;
  1393. continue;
  1394. }
  1395. if ( fLastItemWasReal )
  1396. {
  1397. fLastItemWasReal = FALSE;
  1398. continue;
  1399. }
  1400. // Found two consecutive special separators, or special seperator as first item
  1401. // delete the insertion point item
  1402. rMenuList.RemoveAt(posThisItem);
  1403. delete pItem;
  1404. }
  1405. if ( !fLastItemWasReal && !rMenuList.IsEmpty() )
  1406. {
  1407. // Found special separator as last item
  1408. delete rMenuList.RemoveTail();
  1409. }
  1410. return S_OK;
  1411. }
  1412. // Worker function, called recursively by ShowContextMenu
  1413. // critsec should already be claimed
  1414. HRESULT BuildContextMenu( WTL::CMenu& menu,
  1415. CMenuItem* pmenuitemParent )
  1416. {
  1417. MenuItemList& rMenuList = pmenuitemParent->GetMenuItemSubmenu();
  1418. int nCount = 0;
  1419. bool fInsertedItemSinceLastSeparator = false;
  1420. POSITION pos = rMenuList.GetHeadPosition();
  1421. while(pos)
  1422. {
  1423. CMenuItem* pItem = (rMenuList.GetNext(pos));
  1424. ASSERT( pItem != NULL );
  1425. ASSERT( !pItem->IsSpecialInsertionPoint() );
  1426. UINT_PTR nCommandID = pItem->GetMenuItemID();
  1427. long nFlags = pItem->GetMenuItemFlags();
  1428. /*
  1429. * special processing for submenus
  1430. */
  1431. if ( pItem->IsPopupMenu() )
  1432. {
  1433. // add items to a submenu
  1434. WTL::CMenu submenu;
  1435. VERIFY( submenu.CreatePopupMenu() );
  1436. HRESULT hr = BuildContextMenu( submenu, pItem );
  1437. if ( FAILED(hr) )
  1438. return hr;
  1439. HMENU hSubmenu = submenu.Detach();
  1440. ASSERT( NULL != hSubmenu );
  1441. nCommandID = (UINT_PTR)hSubmenu;
  1442. pItem->SetPopupMenuHandle( hSubmenu );
  1443. if ( pItem->IsSpecialSubmenu() )
  1444. {
  1445. MenuItemList& rChildMenuList = pItem->GetMenuItemSubmenu();
  1446. if ( rChildMenuList.IsEmpty() )
  1447. {
  1448. // Bug 151435: remove instead of disabling unused submenus
  1449. // pItem->SetMenuItemFlags(nFlags | (MF_GRAYED|MF_DISABLED));
  1450. ::DestroyMenu(hSubmenu);
  1451. continue;
  1452. }
  1453. }
  1454. fInsertedItemSinceLastSeparator = true;
  1455. }
  1456. /*
  1457. * special processing for separators
  1458. */
  1459. else if (nFlags & MF_SEPARATOR)
  1460. {
  1461. /*
  1462. * if we haven't inserted an item since the last separator,
  1463. * we don't want to insert this one or we'll have consecutive
  1464. * separators, or an unnecessary separator at the top of the menu
  1465. */
  1466. if (!fInsertedItemSinceLastSeparator)
  1467. continue;
  1468. /*
  1469. * if there aren't any more items after this separator,
  1470. * we don't want to insert this one or we'll have an
  1471. * unnecessary separator at the bottom of the menu
  1472. */
  1473. if (pos == NULL)
  1474. continue;
  1475. fInsertedItemSinceLastSeparator = false;
  1476. }
  1477. /*
  1478. * just a normal menu item
  1479. */
  1480. else
  1481. {
  1482. fInsertedItemSinceLastSeparator = true;
  1483. }
  1484. if (!menu.AppendMenu(nFlags, nCommandID, pItem->GetMenuItemName()))
  1485. {
  1486. #ifdef DBG
  1487. TRACE(_T("BuildContextMenu: AppendMenu(%ld, %ld, \"%s\") reports error\n"),
  1488. nFlags,
  1489. nCommandID,
  1490. SAFEDBGTCHAR(pItem->GetMenuItemName()) );
  1491. #endif
  1492. ASSERT( FALSE );
  1493. return E_UNEXPECTED;
  1494. }
  1495. if (pItem->IsSpecialItemDefault())
  1496. {
  1497. VERIFY( ::SetMenuDefaultItem(menu, nCount, TRUE) );
  1498. }
  1499. ++nCount;
  1500. }
  1501. return S_OK;
  1502. }
  1503. /*+-------------------------------------------------------------------------*
  1504. * CContextMenu::BuildContextMenu
  1505. *
  1506. * PURPOSE:
  1507. *
  1508. * PARAMETERS:
  1509. * WTL::CMenu & menu:
  1510. *
  1511. * RETURNS:
  1512. * HRESULT
  1513. /*+-------------------------------------------------------------------------*/
  1514. HRESULT
  1515. CContextMenu::BuildContextMenu(WTL::CMenu &menu)
  1516. {
  1517. HRESULT hr = S_OK;
  1518. hr = ::CollapseInsertionPoints( m_pmenuitemRoot );
  1519. if ( FAILED(hr) )
  1520. return hr;
  1521. hr = ::CollapseSpecialSeparators( m_pmenuitemRoot );
  1522. if ( FAILED(hr) )
  1523. return hr;
  1524. hr = ::BuildContextMenu( menu, m_pmenuitemRoot );
  1525. if ( FAILED(hr) )
  1526. return hr;
  1527. UINT iItems = menu.GetMenuItemCount();
  1528. if ((UINT)-1 == iItems)
  1529. {
  1530. TRACE(_T("CContextMenu::BuildContextMenu(): itemcount error"));
  1531. ASSERT( FALSE );
  1532. return E_UNEXPECTED;
  1533. }
  1534. else if (0 >= iItems)
  1535. {
  1536. TRACE(_T("CContextMenu::BuildContextMenu(): no items added"));
  1537. return S_OK;
  1538. }
  1539. return hr;
  1540. }
  1541. /*+-------------------------------------------------------------------------*
  1542. * CContextMenu::ShowContextMenu
  1543. *
  1544. * PURPOSE:
  1545. *
  1546. * PARAMETERS:
  1547. * WND hwndParent:
  1548. * LONG xPos:
  1549. * LONG yPos:
  1550. * LONG* plSelected:
  1551. *
  1552. * RETURNS:
  1553. * HRESULT
  1554. /*+-------------------------------------------------------------------------*/
  1555. STDMETHODIMP
  1556. CContextMenu::ShowContextMenu( HWND hwndParent, LONG xPos,
  1557. LONG yPos, LONG* plSelected)
  1558. {
  1559. return (ShowContextMenuEx (hwndParent, xPos, yPos, NULL/*prcExclude*/,
  1560. true/*bAllowDefaultMenuItem*/, plSelected));
  1561. }
  1562. STDMETHODIMP
  1563. CContextMenu::ShowContextMenuEx(HWND hwndParent, LONG xPos,
  1564. LONG yPos, LPCRECT prcExclude,
  1565. bool bAllowDefaultMenuItem, LONG* plSelected)
  1566. {
  1567. DECLARE_SC(sc, _T("IContextMenuProvider::ShowContextMenuEx"));
  1568. if (NULL == plSelected)
  1569. {
  1570. sc = E_INVALIDARG;
  1571. TraceSnapinError(_T("NULL selected ptr"), sc);
  1572. return sc.ToHr();
  1573. }
  1574. *plSelected = 0;
  1575. WTL::CMenu menu;
  1576. VERIFY( menu.CreatePopupMenu() );
  1577. START_CRITSEC_BOTH;
  1578. if (NULL == m_pmenuitemRoot)
  1579. return sc.ToHr();
  1580. sc = BuildContextMenu(menu); // build the context menu
  1581. if (sc)
  1582. return sc.ToHr();
  1583. CMenuItem* pItem = NULL;
  1584. LONG lSelected = 0;
  1585. CConsoleStatusBar *pStatusBar = GetStatusBar();
  1586. // At this point, pStatusBar should be non-NULL, either because
  1587. // 1) This function was called by CNodeInitObject, which calls SetStatusBar() first,
  1588. // or 2) by the object model, where m_pNode is always non-NULL.
  1589. ASSERT(pStatusBar);
  1590. // set up the menu command sink and hook up the status bar.
  1591. CCommandSink comsink( *this, menu, pStatusBar);
  1592. if ( !comsink.Init() )
  1593. {
  1594. sc = E_UNEXPECTED;
  1595. TraceNodeMgrLegacy(_T("CContextMenu::ShowContextMenuEx(): comsink error\n"), sc);
  1596. return sc.ToHr();
  1597. }
  1598. /*
  1599. * if we got an exclusion rectangle, set up a TPMPARAMS to specify it
  1600. */
  1601. TPMPARAMS* ptpm = NULL;
  1602. TPMPARAMS tpm;
  1603. if (prcExclude != NULL)
  1604. {
  1605. tpm.cbSize = sizeof(tpm);
  1606. tpm.rcExclude = *prcExclude;
  1607. ptpm = &tpm;
  1608. }
  1609. /*
  1610. * Bug 139708: menu bar popups shouldn't have default menu items. If
  1611. * we can't have one on this popup, remove any default item now.
  1612. */
  1613. if (!bAllowDefaultMenuItem)
  1614. SetMenuDefaultItem (menu, -1, false);
  1615. lSelected = menu.TrackPopupMenuEx(
  1616. TPM_RETURNCMD | TPM_NONOTIFY | TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_VERTICAL,
  1617. xPos,
  1618. yPos,
  1619. comsink.m_hWnd, // CODEWORK can we eliminate this?
  1620. ptpm );
  1621. comsink.DestroyWindow();
  1622. pItem = (0 == lSelected) ? NULL : FindMenuItem( lSelected );
  1623. if ( pItem != NULL )
  1624. {
  1625. // execute the menu item
  1626. sc = ExecuteMenuItem(pItem);
  1627. if(sc)
  1628. return sc.ToHr();
  1629. // in some cases we'll need to pass command to the sanpin
  1630. if ( pItem->NeedsToPassCommandBackToSnapin() )
  1631. *plSelected = pItem->GetCommandID();
  1632. }
  1633. else
  1634. ASSERT( 0 == lSelected ); // no items selected.
  1635. END_CRITSEC_BOTH;
  1636. return sc.ToHr();
  1637. }
  1638. HRESULT
  1639. CContextMenu::ExecuteMenuItem(CMenuItem *pItem)
  1640. {
  1641. DECLARE_SC(sc, TEXT("CContextMenu::ExecuteMenuItem"));
  1642. sc = ScCheckPointers(pItem);
  1643. if(sc)
  1644. return sc.ToHr();
  1645. // execute it;
  1646. sc = pItem->ScExecute();
  1647. if(sc)
  1648. return sc.ToHr();
  1649. return sc.ToHr();
  1650. }