mirror of https://github.com/tongzx/nt5src
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
576 lines
15 KiB
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (C) Microsoft Corporation, 1999 - 1999
|
|
//
|
|
// File: menuitem.cpp
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// MenuItem.cpp : CMenuItem class implementation.
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "MenuItem.h"
|
|
#include "..\inc\stddbg.h" // ASSERT_OBJECTPTR
|
|
#include "util.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
DEBUG_DECLARE_INSTANCE_COUNTER(CMenuItem);
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Traces
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
#ifdef DBG
|
|
CTraceTag tagMenuItem(TEXT("Menu Items"), TEXT("Menu Item Path"));
|
|
#endif
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Implementation of class CMMCMenuItem
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
/*+-------------------------------------------------------------------------*
|
|
* class CMMCMenuItem
|
|
*
|
|
*
|
|
* PURPOSE: Encapsulates a single CMenuItem, and exposes the MenuItem interface.
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
class CMMCMenuItem:
|
|
public CMMCIDispatchImpl<MenuItem>,
|
|
public CTiedComObject<CMenuItem>
|
|
{
|
|
typedef CMMCMenuItem ThisClass;
|
|
typedef CMenuItem CMyTiedObject;
|
|
|
|
public:
|
|
|
|
BEGIN_MMC_COM_MAP(ThisClass)
|
|
END_MMC_COM_MAP()
|
|
|
|
// give a public access to IsTied();
|
|
bool IsTied() { return CTiedComObject<CMenuItem>::IsTied(); }
|
|
|
|
// MenuItem interface methods
|
|
public:
|
|
MMC_METHOD0(Execute);
|
|
MMC_METHOD1(get_DisplayName, PBSTR /*pbstrName*/);
|
|
MMC_METHOD1(get_LanguageIndependentName, PBSTR /*LanguageIndependentName*/);
|
|
MMC_METHOD1(get_Path, PBSTR /*pbstrPath*/);
|
|
MMC_METHOD1(get_LanguageIndependentPath, PBSTR /*LanguageIndependentPath*/);
|
|
MMC_METHOD1(get_Enabled, PBOOL /*pBool*/);
|
|
};
|
|
|
|
|
|
//############################################################################
|
|
//############################################################################
|
|
//
|
|
// Implementation of class CMenuItem
|
|
//
|
|
//############################################################################
|
|
//############################################################################
|
|
|
|
CMenuItem::CMenuItem( LPCTSTR lpszName,
|
|
LPCTSTR lpszStatusBarText,
|
|
LPCTSTR lpszLanguageIndependentName,
|
|
LPCTSTR lpszPath,
|
|
LPCTSTR lpszLanguageIndependentPath,
|
|
long nCommandID,
|
|
long nMenuItemID,
|
|
long nFlags,
|
|
MENU_OWNER_ID ownerID,
|
|
IExtendContextMenu * pExtendContextMenu,
|
|
IDataObject * pDataObject,
|
|
DWORD fSpecialFlags,
|
|
bool bPassCommandBackToSnapin /*= false*/) :
|
|
|
|
m_strName(lpszName),
|
|
m_strStatusBarText(lpszStatusBarText),
|
|
m_strPath(lpszPath),
|
|
m_strLanguageIndependentName(lpszLanguageIndependentName),
|
|
m_strLanguageIndependentPath(lpszLanguageIndependentPath),
|
|
m_nCommandID(nCommandID),
|
|
m_nMenuItemID(nMenuItemID),
|
|
m_nFlags(nFlags),
|
|
m_OwnerID(ownerID),
|
|
m_fSpecialFlags(fSpecialFlags),
|
|
m_PopupMenuHandle(NULL),
|
|
m_SubMenu(), // default c-tor
|
|
m_spExtendContextMenu(pExtendContextMenu),
|
|
m_pDataObject(pDataObject), //AddRef'ed in the c-tor body
|
|
m_bEnabled(true),
|
|
m_spMenuItem(), // default c-tor
|
|
m_bPassCommandBackToSnapin(bPassCommandBackToSnapin)
|
|
{
|
|
// Caller must check range on ID and State
|
|
|
|
// NULL is a special dataobject
|
|
if (! IS_SPECIAL_DATAOBJECT(m_pDataObject))
|
|
m_pDataObject->AddRef();
|
|
|
|
DEBUG_INCREMENT_INSTANCE_COUNTER(CMenuItem);
|
|
}
|
|
|
|
CMenuItem::~CMenuItem()
|
|
{
|
|
POSITION pos = m_SubMenu.GetHeadPosition();
|
|
while(pos)
|
|
{
|
|
CMenuItem* pItem = m_SubMenu.GetNext(pos);
|
|
ASSERT( pItem != NULL );
|
|
delete pItem;
|
|
}
|
|
m_SubMenu.RemoveAll();
|
|
|
|
m_spExtendContextMenu = NULL;
|
|
|
|
if (! IS_SPECIAL_DATAOBJECT(m_pDataObject))
|
|
m_pDataObject->Release();
|
|
|
|
m_spMenuItem = NULL;
|
|
|
|
DEBUG_DECREMENT_INSTANCE_COUNTER(CMenuItem);
|
|
}
|
|
|
|
|
|
void CMenuItem::AssertValid()
|
|
{
|
|
ASSERT(this != NULL);
|
|
if (m_nCommandID == -1 ||
|
|
m_nMenuItemID == OWNERID_INVALID ||
|
|
m_nFlags == -1
|
|
)
|
|
{
|
|
ASSERT( FALSE );
|
|
}
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CMenuItem::ScGetMenuItem
|
|
*
|
|
* PURPOSE: Creates an returns a tied MenuItem COM object.
|
|
*
|
|
* PARAMETERS:
|
|
* PPMENUITEM ppMenuItem :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CMenuItem::ScGetMenuItem(PPMENUITEM ppMenuItem)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CMenuItem::ScGetMenuItem"));
|
|
|
|
sc = ScCheckPointers(ppMenuItem);
|
|
if(sc)
|
|
return sc;
|
|
|
|
// initialize out parameter
|
|
*ppMenuItem = NULL;
|
|
|
|
// create a CMMCMenuItem if needed.
|
|
sc = CTiedComObjectCreator<CMMCMenuItem>::ScCreateAndConnect(*this, m_spMenuItem);
|
|
if(sc)
|
|
return sc;
|
|
|
|
if(m_spMenuItem == NULL)
|
|
{
|
|
sc = E_UNEXPECTED;
|
|
return sc;
|
|
}
|
|
|
|
// addref the pointer for the client.
|
|
m_spMenuItem->AddRef();
|
|
*ppMenuItem = m_spMenuItem;
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// class: CManageActCtx
|
|
//
|
|
// Purpose: To deactivate UI theme context (if set) and restore
|
|
// the context automatically.
|
|
//
|
|
// Usage: 1. Call Activate to set the activation context to V5
|
|
// common controls. This is needed before calling into snapins
|
|
// so that snapin created windows are not themed accidentally.
|
|
//
|
|
// The snapin can theme its windows by calling appropriate
|
|
// fusion apis while calling create-window.
|
|
//
|
|
// 2. Call Deactivate to restore the activation context.
|
|
// This is needed after calling into snapins, so that
|
|
// if we called from themed context then it is restored.
|
|
//
|
|
// Explanation:
|
|
// When MMC calls into the snapin if the last winproc which
|
|
// received a window message is themed and will result in a
|
|
// call to snapin then we will call the snapin in themed
|
|
// context. If snapin creates & displays any UI then it will
|
|
// be themed. This function is to de-activate the theming
|
|
// before calling the snapin.
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------
|
|
class CManageActCtx
|
|
{
|
|
public:
|
|
CManageActCtx() : m_ulpCookie(0) { }
|
|
~CManageActCtx()
|
|
{
|
|
if (m_ulpCookie != 0)
|
|
MmcDownlevelDeactivateActCtx(0, m_ulpCookie);
|
|
}
|
|
|
|
BOOL Activate(HANDLE hActCtx)
|
|
{
|
|
if (m_ulpCookie != 0)
|
|
{
|
|
ULONG_PTR ulpTemp = m_ulpCookie;
|
|
m_ulpCookie = 0;
|
|
MmcDownlevelDeactivateActCtx(0, ulpTemp);
|
|
}
|
|
|
|
return MmcDownlevelActivateActCtx(hActCtx, &m_ulpCookie);
|
|
}
|
|
|
|
VOID Deactivate()
|
|
{
|
|
ULONG_PTR ulpTemp = m_ulpCookie;
|
|
|
|
if (ulpTemp != 0)
|
|
{
|
|
m_ulpCookie = 0;
|
|
MmcDownlevelDeactivateActCtx(0, ulpTemp);
|
|
}
|
|
}
|
|
|
|
private:
|
|
ULONG_PTR m_ulpCookie;
|
|
};
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CMenuItem::ScExecute
|
|
*
|
|
* PURPOSE: Executes the menu item.
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CMenuItem::ScExecute()
|
|
{
|
|
DECLARE_SC(sc, TEXT("CMenuItem::ScExecute"));
|
|
|
|
Trace(tagMenuItem, TEXT("\"%s\""), m_strPath);
|
|
|
|
// check whether the item is disabled.
|
|
BOOL bEnabled = FALSE;
|
|
sc = Scget_Enabled(&bEnabled);
|
|
if (sc)
|
|
return sc;
|
|
|
|
if (!bEnabled)
|
|
return sc = E_FAIL;
|
|
|
|
// if the command is to be passed to snapin - nothing can be done here
|
|
if ( m_bPassCommandBackToSnapin )
|
|
return sc;
|
|
|
|
sc = ScCheckPointers(m_spExtendContextMenu.GetInterfacePtr(), E_UNEXPECTED);
|
|
if(sc)
|
|
return sc;
|
|
|
|
MenuItemPtr spMenuItem;
|
|
sc = ScGetMenuItem( &spMenuItem );
|
|
if (sc)
|
|
return sc;
|
|
|
|
// Deactivate if theming (fusion or V6 common-control) context before calling snapins.
|
|
CManageActCtx mac;
|
|
if (! mac.Activate(NULL) )
|
|
return (sc = E_FAIL);
|
|
|
|
try
|
|
{
|
|
sc = m_spExtendContextMenu->Command(GetCommandID(), m_pDataObject);
|
|
}
|
|
catch(...)
|
|
{
|
|
// Do nothing.
|
|
}
|
|
|
|
mac.Deactivate();
|
|
|
|
if (sc)
|
|
return sc;
|
|
|
|
// get the pointer for com event emitting
|
|
CConsoleEventDispatcher *pConsoleEventDispatcher = NULL;
|
|
sc = CConsoleEventDispatcherProvider::ScGetConsoleEventDispatcher( pConsoleEventDispatcher );
|
|
if(sc)
|
|
{
|
|
sc.TraceAndClear(); // event does not affect item execution itself
|
|
return sc;
|
|
}
|
|
|
|
// fire event about successful execution (do not rely on 'this' to be valid)
|
|
if (pConsoleEventDispatcher != NULL)
|
|
{
|
|
// check if com object still points to a valid object
|
|
CMMCMenuItem *pMMCMenuItem = dynamic_cast<CMMCMenuItem *>( spMenuItem.GetInterfacePtr() );
|
|
|
|
// check the pointer
|
|
sc = ScCheckPointers( pMMCMenuItem, E_UNEXPECTED );
|
|
if (sc)
|
|
{
|
|
spMenuItem = NULL; // invalid anyway - do not pass to the script
|
|
sc.TraceAndClear(); // does not affect the result
|
|
}
|
|
else if ( !pMMCMenuItem->IsTied() ) // validate menu item
|
|
{
|
|
spMenuItem = NULL; // gone away - change to NULL instead of passing invalid object
|
|
}
|
|
|
|
// fire it!
|
|
sc = pConsoleEventDispatcher->ScOnContextMenuExecuted( spMenuItem );
|
|
if (sc)
|
|
sc.TraceAndClear(); // does not affect the result
|
|
}
|
|
else
|
|
{
|
|
// needs to be set prior to using
|
|
(sc = E_UNEXPECTED).TraceAndClear();
|
|
}
|
|
|
|
return sc;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CMenuItem::Scget_DisplayName
|
|
*
|
|
* PURPOSE: Returns the display name of the menu item, which includes acclerators.
|
|
* Eg '&Properties ALT+ENTER'
|
|
*
|
|
* PARAMETERS:
|
|
* PBSTR pbstrName :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CMenuItem::Scget_DisplayName(PBSTR pbstrName)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CMenuItem::Scget_DisplayName"));
|
|
|
|
sc = ScCheckPointers(pbstrName);
|
|
if(sc)
|
|
return sc;
|
|
|
|
CComBSTR bstrName = GetMenuItemName();
|
|
|
|
// give the
|
|
*pbstrName = bstrName.Detach();
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CMenuItem::Scget_LanguageIndependentName
|
|
*
|
|
* PURPOSE: Returns the language-independent name of the menu item. If there is no
|
|
* language independent name, returns the display name without accelerators.
|
|
*
|
|
* PARAMETERS:
|
|
* PBSTR LanguageIndependentName :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CMenuItem::Scget_LanguageIndependentName(PBSTR LanguageIndependentName)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CMenuItem::Scget_LanguageIndependentName"));
|
|
|
|
sc = ScCheckPointers(LanguageIndependentName);
|
|
if(sc)
|
|
return sc;
|
|
|
|
// initialize the out parameter
|
|
*LanguageIndependentName = NULL;
|
|
|
|
CComBSTR bstrLanguageIndependentName = GetLanguageIndependentName();
|
|
|
|
// set the output param
|
|
*LanguageIndependentName = bstrLanguageIndependentName.Detach();
|
|
|
|
return sc;
|
|
}
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CMenuItem::Scget_Path
|
|
*
|
|
* PURPOSE: Returns the path of the menu item starting from the root. Does not include
|
|
* accelerators. Eg View->Large
|
|
*
|
|
* PARAMETERS:
|
|
* PBSTR pbstrPath :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CMenuItem::Scget_Path(PBSTR pbstrPath)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CMenuItem::Scget_Path"));
|
|
|
|
sc = ScCheckPointers(pbstrPath);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
CComBSTR bstrPath = (LPCTSTR)m_strPath;
|
|
|
|
// give the
|
|
*pbstrPath = bstrPath.Detach();
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CMenuItem::Scget_LanguageIndependentPath
|
|
*
|
|
* PURPOSE: Returns the language independent path of the menu item starting from the root.
|
|
* Eg _VIEW->_LARGE
|
|
*
|
|
* PARAMETERS:
|
|
* PBSTR LanguageIndependentPath :
|
|
*
|
|
* RETURNS:
|
|
* SC
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CMenuItem::Scget_LanguageIndependentPath(PBSTR LanguageIndependentPath)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CMenuItem::Scget_LanguageIndependentPath"));
|
|
|
|
sc = ScCheckPointers(LanguageIndependentPath);
|
|
if(sc)
|
|
return sc;
|
|
|
|
// initialize the out parameter
|
|
*LanguageIndependentPath = NULL;
|
|
|
|
CComBSTR bstrLanguageIndependentPath = (LPCTSTR)GetLanguageIndependentPath();
|
|
|
|
// set the output param
|
|
*LanguageIndependentPath = bstrLanguageIndependentPath.Detach();
|
|
|
|
return sc;
|
|
}
|
|
|
|
|
|
/*+-------------------------------------------------------------------------*
|
|
*
|
|
* CMenuItem::Scget_Enabled
|
|
*
|
|
* PURPOSE: Returns whether the menu item is enabled.
|
|
*
|
|
* PARAMETERS:
|
|
* PBOOL pBool :
|
|
*
|
|
* RETURNS:
|
|
* HRESULT
|
|
*
|
|
*+-------------------------------------------------------------------------*/
|
|
SC
|
|
CMenuItem::Scget_Enabled(PBOOL pBool)
|
|
{
|
|
DECLARE_SC(sc, TEXT("CMenuItem::Scget_Enabled"));
|
|
|
|
sc = ScCheckPointers(pBool);
|
|
if(sc)
|
|
return sc.ToHr();
|
|
|
|
// the item is enabled only if it was never disabled via the Disable object model
|
|
// method and it is not grayed out or disabled via the MF_ flags.
|
|
*pBool = m_bEnabled &&
|
|
((m_nFlags & MF_DISABLED) == 0) &&
|
|
((m_nFlags & MF_GRAYED) == 0);
|
|
|
|
return sc.ToHr();
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* METHOD: CMenuItem::ScFindMenuItemByPath
|
|
*
|
|
* PURPOSE: finds the menu item by matching the path
|
|
*
|
|
* PARAMETERS:
|
|
* LPCTSTR lpstrPath [in] manu item path
|
|
*
|
|
* RETURNS:
|
|
* CMenuItem* - found item (NULL == not found)
|
|
*
|
|
\***************************************************************************/
|
|
CMenuItem*
|
|
CMenuItem::FindItemByPath( LPCTSTR lpstrPath )
|
|
{
|
|
// first check if this item does not meet requirements
|
|
if ( 0 == m_strLanguageIndependentPath.Compare(lpstrPath)
|
|
|| 0 == m_strPath.Compare(lpstrPath) )
|
|
return this;
|
|
|
|
// recurse into subitems
|
|
POSITION pos = GetMenuItemSubmenu().GetHeadPosition();
|
|
while(pos)
|
|
{
|
|
CMenuItem* pItem = GetMenuItemSubmenu().GetNext(pos);
|
|
if (!pItem)
|
|
{
|
|
ASSERT(FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
CMenuItem* pItemFound = pItem->FindItemByPath( lpstrPath );
|
|
if (pItemFound)
|
|
return pItemFound;
|
|
}
|
|
|
|
// not found
|
|
return NULL;
|
|
}
|
|
|
|
|