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.

569 lines
16 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. sc = m_spExtendContextMenu->Command(GetCommandID(), m_pDataObject);
  268. mac.Deactivate();
  269. if (sc)
  270. return sc;
  271. // get the pointer for com event emitting
  272. CConsoleEventDispatcher *pConsoleEventDispatcher = NULL;
  273. sc = CConsoleEventDispatcherProvider::ScGetConsoleEventDispatcher( pConsoleEventDispatcher );
  274. if(sc)
  275. {
  276. sc.TraceAndClear(); // event does not affect item execution itself
  277. return sc;
  278. }
  279. // fire event about successful execution (do not rely on 'this' to be valid)
  280. if (pConsoleEventDispatcher != NULL)
  281. {
  282. // check if com object still points to a valid object
  283. CMMCMenuItem *pMMCMenuItem = dynamic_cast<CMMCMenuItem *>( spMenuItem.GetInterfacePtr() );
  284. // check the pointer
  285. sc = ScCheckPointers( pMMCMenuItem, E_UNEXPECTED );
  286. if (sc)
  287. {
  288. spMenuItem = NULL; // invalid anyway - do not pass to the script
  289. sc.TraceAndClear(); // does not affect the result
  290. }
  291. else if ( !pMMCMenuItem->IsTied() ) // validate menu item
  292. {
  293. spMenuItem = NULL; // gone away - change to NULL instead of passing invalid object
  294. }
  295. // fire it!
  296. sc = pConsoleEventDispatcher->ScOnContextMenuExecuted( spMenuItem );
  297. if (sc)
  298. sc.TraceAndClear(); // does not affect the result
  299. }
  300. else
  301. {
  302. // needs to be set prior to using
  303. (sc = E_UNEXPECTED).TraceAndClear();
  304. }
  305. return sc;
  306. }
  307. /*+-------------------------------------------------------------------------*
  308. *
  309. * CMenuItem::Scget_DisplayName
  310. *
  311. * PURPOSE: Returns the display name of the menu item, which includes acclerators.
  312. * Eg '&Properties ALT+ENTER'
  313. *
  314. * PARAMETERS:
  315. * PBSTR pbstrName :
  316. *
  317. * RETURNS:
  318. * SC
  319. *
  320. *+-------------------------------------------------------------------------*/
  321. SC
  322. CMenuItem::Scget_DisplayName(PBSTR pbstrName)
  323. {
  324. DECLARE_SC(sc, TEXT("CMenuItem::Scget_DisplayName"));
  325. sc = ScCheckPointers(pbstrName);
  326. if(sc)
  327. return sc;
  328. CComBSTR bstrName = GetMenuItemName();
  329. // give the
  330. *pbstrName = bstrName.Detach();
  331. return sc;
  332. }
  333. /*+-------------------------------------------------------------------------*
  334. *
  335. * CMenuItem::Scget_LanguageIndependentName
  336. *
  337. * PURPOSE: Returns the language-independent name of the menu item. If there is no
  338. * language independent name, returns the display name without accelerators.
  339. *
  340. * PARAMETERS:
  341. * PBSTR LanguageIndependentName :
  342. *
  343. * RETURNS:
  344. * SC
  345. *
  346. *+-------------------------------------------------------------------------*/
  347. SC
  348. CMenuItem::Scget_LanguageIndependentName(PBSTR LanguageIndependentName)
  349. {
  350. DECLARE_SC(sc, TEXT("CMenuItem::Scget_LanguageIndependentName"));
  351. sc = ScCheckPointers(LanguageIndependentName);
  352. if(sc)
  353. return sc;
  354. // initialize the out parameter
  355. *LanguageIndependentName = NULL;
  356. CComBSTR bstrLanguageIndependentName = GetLanguageIndependentName();
  357. // set the output param
  358. *LanguageIndependentName = bstrLanguageIndependentName.Detach();
  359. return sc;
  360. }
  361. /*+-------------------------------------------------------------------------*
  362. *
  363. * CMenuItem::Scget_Path
  364. *
  365. * PURPOSE: Returns the path of the menu item starting from the root. Does not include
  366. * accelerators. Eg View->Large
  367. *
  368. * PARAMETERS:
  369. * PBSTR pbstrPath :
  370. *
  371. * RETURNS:
  372. * SC
  373. *
  374. *+-------------------------------------------------------------------------*/
  375. SC
  376. CMenuItem::Scget_Path(PBSTR pbstrPath)
  377. {
  378. DECLARE_SC(sc, TEXT("CMenuItem::Scget_Path"));
  379. sc = ScCheckPointers(pbstrPath);
  380. if(sc)
  381. return sc.ToHr();
  382. CComBSTR bstrPath = (LPCTSTR)m_strPath;
  383. // give the
  384. *pbstrPath = bstrPath.Detach();
  385. return sc.ToHr();
  386. }
  387. /*+-------------------------------------------------------------------------*
  388. *
  389. * CMenuItem::Scget_LanguageIndependentPath
  390. *
  391. * PURPOSE: Returns the language independent path of the menu item starting from the root.
  392. * Eg _VIEW->_LARGE
  393. *
  394. * PARAMETERS:
  395. * PBSTR LanguageIndependentPath :
  396. *
  397. * RETURNS:
  398. * SC
  399. *
  400. *+-------------------------------------------------------------------------*/
  401. SC
  402. CMenuItem::Scget_LanguageIndependentPath(PBSTR LanguageIndependentPath)
  403. {
  404. DECLARE_SC(sc, TEXT("CMenuItem::Scget_LanguageIndependentPath"));
  405. sc = ScCheckPointers(LanguageIndependentPath);
  406. if(sc)
  407. return sc;
  408. // initialize the out parameter
  409. *LanguageIndependentPath = NULL;
  410. CComBSTR bstrLanguageIndependentPath = (LPCTSTR)GetLanguageIndependentPath();
  411. // set the output param
  412. *LanguageIndependentPath = bstrLanguageIndependentPath.Detach();
  413. return sc;
  414. }
  415. /*+-------------------------------------------------------------------------*
  416. *
  417. * CMenuItem::Scget_Enabled
  418. *
  419. * PURPOSE: Returns whether the menu item is enabled.
  420. *
  421. * PARAMETERS:
  422. * PBOOL pBool :
  423. *
  424. * RETURNS:
  425. * HRESULT
  426. *
  427. *+-------------------------------------------------------------------------*/
  428. SC
  429. CMenuItem::Scget_Enabled(PBOOL pBool)
  430. {
  431. DECLARE_SC(sc, TEXT("CMenuItem::Scget_Enabled"));
  432. sc = ScCheckPointers(pBool);
  433. if(sc)
  434. return sc.ToHr();
  435. // the item is enabled only if it was never disabled via the Disable object model
  436. // method and it is not grayed out or disabled via the MF_ flags.
  437. *pBool = m_bEnabled &&
  438. ((m_nFlags & MF_DISABLED) == 0) &&
  439. ((m_nFlags & MF_GRAYED) == 0);
  440. return sc.ToHr();
  441. }
  442. /***************************************************************************\
  443. *
  444. * METHOD: CMenuItem::ScFindMenuItemByPath
  445. *
  446. * PURPOSE: finds the menu item by matching the path
  447. *
  448. * PARAMETERS:
  449. * LPCTSTR lpstrPath [in] manu item path
  450. *
  451. * RETURNS:
  452. * CMenuItem* - found item (NULL == not found)
  453. *
  454. \***************************************************************************/
  455. CMenuItem*
  456. CMenuItem::FindItemByPath( LPCTSTR lpstrPath )
  457. {
  458. // first check if this item does not meet requirements
  459. if ( 0 == m_strLanguageIndependentPath.Compare(lpstrPath)
  460. || 0 == m_strPath.Compare(lpstrPath) )
  461. return this;
  462. // recurse into subitems
  463. POSITION pos = GetMenuItemSubmenu().GetHeadPosition();
  464. while(pos)
  465. {
  466. CMenuItem* pItem = GetMenuItemSubmenu().GetNext(pos);
  467. if (!pItem)
  468. {
  469. ASSERT(FALSE);
  470. return NULL;
  471. }
  472. CMenuItem* pItemFound = pItem->FindItemByPath( lpstrPath );
  473. if (pItemFound)
  474. return pItemFound;
  475. }
  476. // not found
  477. return NULL;
  478. }