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.

576 lines
15 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1999 - 1999
  6. //
  7. // File: menuitem.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. /////////////////////////////////////////////////////////////////////////////
  11. // MenuItem.cpp : CMenuItem class implementation.
  12. #include "stdafx.h"
  13. #include "MenuItem.h"
  14. #include "..\inc\stddbg.h" // ASSERT_OBJECTPTR
  15. #include "util.h"
  16. #ifdef _DEBUG
  17. #undef THIS_FILE
  18. static char THIS_FILE[] = __FILE__;
  19. #endif
  20. DEBUG_DECLARE_INSTANCE_COUNTER(CMenuItem);
  21. //############################################################################
  22. //############################################################################
  23. //
  24. // Traces
  25. //
  26. //############################################################################
  27. //############################################################################
  28. #ifdef DBG
  29. CTraceTag tagMenuItem(TEXT("Menu Items"), TEXT("Menu Item Path"));
  30. #endif
  31. //############################################################################
  32. //############################################################################
  33. //
  34. // Implementation of class CMMCMenuItem
  35. //
  36. //############################################################################
  37. //############################################################################
  38. /*+-------------------------------------------------------------------------*
  39. * class CMMCMenuItem
  40. *
  41. *
  42. * PURPOSE: Encapsulates a single CMenuItem, and exposes the MenuItem interface.
  43. *
  44. *+-------------------------------------------------------------------------*/
  45. class CMMCMenuItem:
  46. public CMMCIDispatchImpl<MenuItem>,
  47. public CTiedComObject<CMenuItem>
  48. {
  49. typedef CMMCMenuItem ThisClass;
  50. typedef CMenuItem CMyTiedObject;
  51. public:
  52. BEGIN_MMC_COM_MAP(ThisClass)
  53. END_MMC_COM_MAP()
  54. // give a public access to IsTied();
  55. bool IsTied() { return CTiedComObject<CMenuItem>::IsTied(); }
  56. // MenuItem interface methods
  57. public:
  58. MMC_METHOD0(Execute);
  59. MMC_METHOD1(get_DisplayName, PBSTR /*pbstrName*/);
  60. MMC_METHOD1(get_LanguageIndependentName, PBSTR /*LanguageIndependentName*/);
  61. MMC_METHOD1(get_Path, PBSTR /*pbstrPath*/);
  62. MMC_METHOD1(get_LanguageIndependentPath, PBSTR /*LanguageIndependentPath*/);
  63. MMC_METHOD1(get_Enabled, PBOOL /*pBool*/);
  64. };
  65. //############################################################################
  66. //############################################################################
  67. //
  68. // Implementation of class CMenuItem
  69. //
  70. //############################################################################
  71. //############################################################################
  72. CMenuItem::CMenuItem( LPCTSTR lpszName,
  73. LPCTSTR lpszStatusBarText,
  74. LPCTSTR lpszLanguageIndependentName,
  75. LPCTSTR lpszPath,
  76. LPCTSTR lpszLanguageIndependentPath,
  77. long nCommandID,
  78. long nMenuItemID,
  79. long nFlags,
  80. MENU_OWNER_ID ownerID,
  81. IExtendContextMenu * pExtendContextMenu,
  82. IDataObject * pDataObject,
  83. DWORD fSpecialFlags,
  84. bool bPassCommandBackToSnapin /*= false*/) :
  85. m_strName(lpszName),
  86. m_strStatusBarText(lpszStatusBarText),
  87. m_strPath(lpszPath),
  88. m_strLanguageIndependentName(lpszLanguageIndependentName),
  89. m_strLanguageIndependentPath(lpszLanguageIndependentPath),
  90. m_nCommandID(nCommandID),
  91. m_nMenuItemID(nMenuItemID),
  92. m_nFlags(nFlags),
  93. m_OwnerID(ownerID),
  94. m_fSpecialFlags(fSpecialFlags),
  95. m_PopupMenuHandle(NULL),
  96. m_SubMenu(), // default c-tor
  97. m_spExtendContextMenu(pExtendContextMenu),
  98. m_pDataObject(pDataObject), //AddRef'ed in the c-tor body
  99. m_bEnabled(true),
  100. m_spMenuItem(), // default c-tor
  101. m_bPassCommandBackToSnapin(bPassCommandBackToSnapin)
  102. {
  103. // Caller must check range on ID and State
  104. // NULL is a special dataobject
  105. if (! IS_SPECIAL_DATAOBJECT(m_pDataObject))
  106. m_pDataObject->AddRef();
  107. DEBUG_INCREMENT_INSTANCE_COUNTER(CMenuItem);
  108. }
  109. CMenuItem::~CMenuItem()
  110. {
  111. POSITION pos = m_SubMenu.GetHeadPosition();
  112. while(pos)
  113. {
  114. CMenuItem* pItem = m_SubMenu.GetNext(pos);
  115. ASSERT( pItem != NULL );
  116. delete pItem;
  117. }
  118. m_SubMenu.RemoveAll();
  119. m_spExtendContextMenu = NULL;
  120. if (! IS_SPECIAL_DATAOBJECT(m_pDataObject))
  121. m_pDataObject->Release();
  122. m_spMenuItem = NULL;
  123. DEBUG_DECREMENT_INSTANCE_COUNTER(CMenuItem);
  124. }
  125. void CMenuItem::AssertValid()
  126. {
  127. ASSERT(this != NULL);
  128. if (m_nCommandID == -1 ||
  129. m_nMenuItemID == OWNERID_INVALID ||
  130. m_nFlags == -1
  131. )
  132. {
  133. ASSERT( FALSE );
  134. }
  135. }
  136. /*+-------------------------------------------------------------------------*
  137. *
  138. * CMenuItem::ScGetMenuItem
  139. *
  140. * PURPOSE: Creates an returns a tied MenuItem COM object.
  141. *
  142. * PARAMETERS:
  143. * PPMENUITEM ppMenuItem :
  144. *
  145. * RETURNS:
  146. * SC
  147. *
  148. *+-------------------------------------------------------------------------*/
  149. SC
  150. CMenuItem::ScGetMenuItem(PPMENUITEM ppMenuItem)
  151. {
  152. DECLARE_SC(sc, TEXT("CMenuItem::ScGetMenuItem"));
  153. sc = ScCheckPointers(ppMenuItem);
  154. if(sc)
  155. return sc;
  156. // initialize out parameter
  157. *ppMenuItem = NULL;
  158. // create a CMMCMenuItem if needed.
  159. sc = CTiedComObjectCreator<CMMCMenuItem>::ScCreateAndConnect(*this, m_spMenuItem);
  160. if(sc)
  161. return sc;
  162. if(m_spMenuItem == NULL)
  163. {
  164. sc = E_UNEXPECTED;
  165. return sc;
  166. }
  167. // addref the pointer for the client.
  168. m_spMenuItem->AddRef();
  169. *ppMenuItem = m_spMenuItem;
  170. return sc;
  171. }
  172. //+-------------------------------------------------------------------
  173. //
  174. // class: CManageActCtx
  175. //
  176. // Purpose: To deactivate UI theme context (if set) and restore
  177. // the context automatically.
  178. //
  179. // Usage: 1. Call Activate to set the activation context to V5
  180. // common controls. This is needed before calling into snapins
  181. // so that snapin created windows are not themed accidentally.
  182. //
  183. // The snapin can theme its windows by calling appropriate
  184. // fusion apis while calling create-window.
  185. //
  186. // 2. Call Deactivate to restore the activation context.
  187. // This is needed after calling into snapins, so that
  188. // if we called from themed context then it is restored.
  189. //
  190. // Explanation:
  191. // When MMC calls into the snapin if the last winproc which
  192. // received a window message is themed and will result in a
  193. // call to snapin then we will call the snapin in themed
  194. // context. If snapin creates & displays any UI then it will
  195. // be themed. This function is to de-activate the theming
  196. // before calling the snapin.
  197. //
  198. //
  199. //--------------------------------------------------------------------
  200. class CManageActCtx
  201. {
  202. public:
  203. CManageActCtx() : m_ulpCookie(0) { }
  204. ~CManageActCtx()
  205. {
  206. if (m_ulpCookie != 0)
  207. MmcDownlevelDeactivateActCtx(0, m_ulpCookie);
  208. }
  209. BOOL Activate(HANDLE hActCtx)
  210. {
  211. if (m_ulpCookie != 0)
  212. {
  213. ULONG_PTR ulpTemp = m_ulpCookie;
  214. m_ulpCookie = 0;
  215. MmcDownlevelDeactivateActCtx(0, ulpTemp);
  216. }
  217. return MmcDownlevelActivateActCtx(hActCtx, &m_ulpCookie);
  218. }
  219. VOID Deactivate()
  220. {
  221. ULONG_PTR ulpTemp = m_ulpCookie;
  222. if (ulpTemp != 0)
  223. {
  224. m_ulpCookie = 0;
  225. MmcDownlevelDeactivateActCtx(0, ulpTemp);
  226. }
  227. }
  228. private:
  229. ULONG_PTR m_ulpCookie;
  230. };
  231. /*+-------------------------------------------------------------------------*
  232. *
  233. * CMenuItem::ScExecute
  234. *
  235. * PURPOSE: Executes the menu item.
  236. *
  237. * RETURNS:
  238. * SC
  239. *
  240. *+-------------------------------------------------------------------------*/
  241. SC
  242. CMenuItem::ScExecute()
  243. {
  244. DECLARE_SC(sc, TEXT("CMenuItem::ScExecute"));
  245. Trace(tagMenuItem, TEXT("\"%s\""), m_strPath);
  246. // check whether the item is disabled.
  247. BOOL bEnabled = FALSE;
  248. sc = Scget_Enabled(&bEnabled);
  249. if (sc)
  250. return sc;
  251. if (!bEnabled)
  252. return sc = E_FAIL;
  253. // if the command is to be passed to snapin - nothing can be done here
  254. if ( m_bPassCommandBackToSnapin )
  255. return sc;
  256. sc = ScCheckPointers(m_spExtendContextMenu.GetInterfacePtr(), E_UNEXPECTED);
  257. if(sc)
  258. return sc;
  259. MenuItemPtr spMenuItem;
  260. sc = ScGetMenuItem( &spMenuItem );
  261. if (sc)
  262. return sc;
  263. // Deactivate if theming (fusion or V6 common-control) context before calling snapins.
  264. CManageActCtx mac;
  265. if (! mac.Activate(NULL) )
  266. return (sc = E_FAIL);
  267. try
  268. {
  269. sc = m_spExtendContextMenu->Command(GetCommandID(), m_pDataObject);
  270. }
  271. catch(...)
  272. {
  273. // Do nothing.
  274. }
  275. mac.Deactivate();
  276. if (sc)
  277. return sc;
  278. // get the pointer for com event emitting
  279. CConsoleEventDispatcher *pConsoleEventDispatcher = NULL;
  280. sc = CConsoleEventDispatcherProvider::ScGetConsoleEventDispatcher( pConsoleEventDispatcher );
  281. if(sc)
  282. {
  283. sc.TraceAndClear(); // event does not affect item execution itself
  284. return sc;
  285. }
  286. // fire event about successful execution (do not rely on 'this' to be valid)
  287. if (pConsoleEventDispatcher != NULL)
  288. {
  289. // check if com object still points to a valid object
  290. CMMCMenuItem *pMMCMenuItem = dynamic_cast<CMMCMenuItem *>( spMenuItem.GetInterfacePtr() );
  291. // check the pointer
  292. sc = ScCheckPointers( pMMCMenuItem, E_UNEXPECTED );
  293. if (sc)
  294. {
  295. spMenuItem = NULL; // invalid anyway - do not pass to the script
  296. sc.TraceAndClear(); // does not affect the result
  297. }
  298. else if ( !pMMCMenuItem->IsTied() ) // validate menu item
  299. {
  300. spMenuItem = NULL; // gone away - change to NULL instead of passing invalid object
  301. }
  302. // fire it!
  303. sc = pConsoleEventDispatcher->ScOnContextMenuExecuted( spMenuItem );
  304. if (sc)
  305. sc.TraceAndClear(); // does not affect the result
  306. }
  307. else
  308. {
  309. // needs to be set prior to using
  310. (sc = E_UNEXPECTED).TraceAndClear();
  311. }
  312. return sc;
  313. }
  314. /*+-------------------------------------------------------------------------*
  315. *
  316. * CMenuItem::Scget_DisplayName
  317. *
  318. * PURPOSE: Returns the display name of the menu item, which includes acclerators.
  319. * Eg '&Properties ALT+ENTER'
  320. *
  321. * PARAMETERS:
  322. * PBSTR pbstrName :
  323. *
  324. * RETURNS:
  325. * SC
  326. *
  327. *+-------------------------------------------------------------------------*/
  328. SC
  329. CMenuItem::Scget_DisplayName(PBSTR pbstrName)
  330. {
  331. DECLARE_SC(sc, TEXT("CMenuItem::Scget_DisplayName"));
  332. sc = ScCheckPointers(pbstrName);
  333. if(sc)
  334. return sc;
  335. CComBSTR bstrName = GetMenuItemName();
  336. // give the
  337. *pbstrName = bstrName.Detach();
  338. return sc;
  339. }
  340. /*+-------------------------------------------------------------------------*
  341. *
  342. * CMenuItem::Scget_LanguageIndependentName
  343. *
  344. * PURPOSE: Returns the language-independent name of the menu item. If there is no
  345. * language independent name, returns the display name without accelerators.
  346. *
  347. * PARAMETERS:
  348. * PBSTR LanguageIndependentName :
  349. *
  350. * RETURNS:
  351. * SC
  352. *
  353. *+-------------------------------------------------------------------------*/
  354. SC
  355. CMenuItem::Scget_LanguageIndependentName(PBSTR LanguageIndependentName)
  356. {
  357. DECLARE_SC(sc, TEXT("CMenuItem::Scget_LanguageIndependentName"));
  358. sc = ScCheckPointers(LanguageIndependentName);
  359. if(sc)
  360. return sc;
  361. // initialize the out parameter
  362. *LanguageIndependentName = NULL;
  363. CComBSTR bstrLanguageIndependentName = GetLanguageIndependentName();
  364. // set the output param
  365. *LanguageIndependentName = bstrLanguageIndependentName.Detach();
  366. return sc;
  367. }
  368. /*+-------------------------------------------------------------------------*
  369. *
  370. * CMenuItem::Scget_Path
  371. *
  372. * PURPOSE: Returns the path of the menu item starting from the root. Does not include
  373. * accelerators. Eg View->Large
  374. *
  375. * PARAMETERS:
  376. * PBSTR pbstrPath :
  377. *
  378. * RETURNS:
  379. * SC
  380. *
  381. *+-------------------------------------------------------------------------*/
  382. SC
  383. CMenuItem::Scget_Path(PBSTR pbstrPath)
  384. {
  385. DECLARE_SC(sc, TEXT("CMenuItem::Scget_Path"));
  386. sc = ScCheckPointers(pbstrPath);
  387. if(sc)
  388. return sc.ToHr();
  389. CComBSTR bstrPath = (LPCTSTR)m_strPath;
  390. // give the
  391. *pbstrPath = bstrPath.Detach();
  392. return sc.ToHr();
  393. }
  394. /*+-------------------------------------------------------------------------*
  395. *
  396. * CMenuItem::Scget_LanguageIndependentPath
  397. *
  398. * PURPOSE: Returns the language independent path of the menu item starting from the root.
  399. * Eg _VIEW->_LARGE
  400. *
  401. * PARAMETERS:
  402. * PBSTR LanguageIndependentPath :
  403. *
  404. * RETURNS:
  405. * SC
  406. *
  407. *+-------------------------------------------------------------------------*/
  408. SC
  409. CMenuItem::Scget_LanguageIndependentPath(PBSTR LanguageIndependentPath)
  410. {
  411. DECLARE_SC(sc, TEXT("CMenuItem::Scget_LanguageIndependentPath"));
  412. sc = ScCheckPointers(LanguageIndependentPath);
  413. if(sc)
  414. return sc;
  415. // initialize the out parameter
  416. *LanguageIndependentPath = NULL;
  417. CComBSTR bstrLanguageIndependentPath = (LPCTSTR)GetLanguageIndependentPath();
  418. // set the output param
  419. *LanguageIndependentPath = bstrLanguageIndependentPath.Detach();
  420. return sc;
  421. }
  422. /*+-------------------------------------------------------------------------*
  423. *
  424. * CMenuItem::Scget_Enabled
  425. *
  426. * PURPOSE: Returns whether the menu item is enabled.
  427. *
  428. * PARAMETERS:
  429. * PBOOL pBool :
  430. *
  431. * RETURNS:
  432. * HRESULT
  433. *
  434. *+-------------------------------------------------------------------------*/
  435. SC
  436. CMenuItem::Scget_Enabled(PBOOL pBool)
  437. {
  438. DECLARE_SC(sc, TEXT("CMenuItem::Scget_Enabled"));
  439. sc = ScCheckPointers(pBool);
  440. if(sc)
  441. return sc.ToHr();
  442. // the item is enabled only if it was never disabled via the Disable object model
  443. // method and it is not grayed out or disabled via the MF_ flags.
  444. *pBool = m_bEnabled &&
  445. ((m_nFlags & MF_DISABLED) == 0) &&
  446. ((m_nFlags & MF_GRAYED) == 0);
  447. return sc.ToHr();
  448. }
  449. /***************************************************************************\
  450. *
  451. * METHOD: CMenuItem::ScFindMenuItemByPath
  452. *
  453. * PURPOSE: finds the menu item by matching the path
  454. *
  455. * PARAMETERS:
  456. * LPCTSTR lpstrPath [in] manu item path
  457. *
  458. * RETURNS:
  459. * CMenuItem* - found item (NULL == not found)
  460. *
  461. \***************************************************************************/
  462. CMenuItem*
  463. CMenuItem::FindItemByPath( LPCTSTR lpstrPath )
  464. {
  465. // first check if this item does not meet requirements
  466. if ( 0 == m_strLanguageIndependentPath.Compare(lpstrPath)
  467. || 0 == m_strPath.Compare(lpstrPath) )
  468. return this;
  469. // recurse into subitems
  470. POSITION pos = GetMenuItemSubmenu().GetHeadPosition();
  471. while(pos)
  472. {
  473. CMenuItem* pItem = GetMenuItemSubmenu().GetNext(pos);
  474. if (!pItem)
  475. {
  476. ASSERT(FALSE);
  477. return NULL;
  478. }
  479. CMenuItem* pItemFound = pItem->FindItemByPath( lpstrPath );
  480. if (pItemFound)
  481. return pItemFound;
  482. }
  483. // not found
  484. return NULL;
  485. }