#include "precomp.hxx" #pragma hdrstop #include #include "contextmenu.h" // Context Menu Forwarding base class, desinged to delegate // to a real IContextMenu, and provide inheriting class // an easy way to override minor bits of functionality // CContextMenuForwarder::CContextMenuForwarder(IUnknown* punk) : _cRef(1) { _punk = punk; _punk->AddRef(); _punk->QueryInterface(IID_PPV_ARG(IObjectWithSite, &_pows)); _punk->QueryInterface(IID_PPV_ARG(IContextMenu, &_pcm)); _punk->QueryInterface(IID_PPV_ARG(IContextMenu2, &_pcm2)); _punk->QueryInterface(IID_PPV_ARG(IContextMenu3, &_pcm3)); } CContextMenuForwarder::~CContextMenuForwarder() { if (_pows) _pows->Release(); if (_pcm) _pcm->Release(); if (_pcm2) _pcm2->Release(); if (_pcm3) _pcm3->Release(); _punk->Release(); } STDMETHODIMP CContextMenuForwarder::QueryInterface(REFIID riid, void **ppv) { HRESULT hr = _punk->QueryInterface(riid, ppv); if (SUCCEEDED(hr)) { IUnknown* punkTmp = (IUnknown*)(*ppv); static const QITAB qit[] = { QITABENT(CContextMenuForwarder, IObjectWithSite), // IID_IObjectWithSite QITABENT(CContextMenuForwarder, IContextMenu3), // IID_IContextMenu3 QITABENTMULTI(CContextMenuForwarder, IContextMenu2, IContextMenu3), // IID_IContextMenu2 QITABENTMULTI(CContextMenuForwarder, IContextMenu, IContextMenu3), // IID_IContextMenu { 0 }, }; HRESULT hrTmp = QISearch(this, qit, riid, ppv); if (SUCCEEDED(hrTmp)) { punkTmp->Release(); } else { RIPMSG(FALSE, "CContextMenuForwarder asked for an interface it doesn't support"); *ppv = NULL; hr = E_NOINTERFACE; } } return hr; } STDMETHODIMP_(ULONG) CContextMenuForwarder::AddRef() { return InterlockedIncrement(&_cRef); } STDMETHODIMP_(ULONG) CContextMenuForwarder::Release() { ASSERT( 0 != _cRef ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; } // Forward everything to the given context menu, // but remove menu items with the canonical verbs // given in the semicolon-separated list of canonical verbs // class CContextMenuWithoutVerbs : CContextMenuForwarder { public: STDMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags); protected: CContextMenuWithoutVerbs(IUnknown* punk, LPCWSTR pszVerbList); friend HRESULT Create_ContextMenuWithoutVerbs(IUnknown* punk, LPCWSTR pszVerbList, REFIID riid, void **ppv); private: LPCWSTR _pszVerbList; }; CContextMenuWithoutVerbs::CContextMenuWithoutVerbs(IUnknown* punk, LPCWSTR pszVerbList) : CContextMenuForwarder(punk) { _pszVerbList = pszVerbList; // no reference - this should be a pointer to the code segment } HRESULT Create_ContextMenuWithoutVerbs(IUnknown* punk, LPCWSTR pszVerbList, REFIID riid, void **ppv) { HRESULT hr = E_OUTOFMEMORY; *ppv = NULL; if (pszVerbList) { CContextMenuWithoutVerbs* p = new CContextMenuWithoutVerbs(punk, pszVerbList); if (p) { hr = p->QueryInterface(riid, ppv); p->Release(); } } return hr; } HRESULT CContextMenuWithoutVerbs::QueryContextMenu(HMENU hmenu, UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags) { HRESULT hr = CContextMenuForwarder::QueryContextMenu(hmenu,indexMenu,idCmdFirst,idCmdLast,uFlags); if (SUCCEEDED(hr)) { LPCWSTR pszVerb = _pszVerbList; while (*pszVerb) { WCHAR szVerb[64]; LPCWSTR pszNext = StrChrW(pszVerb, L';'); if (pszNext) { size_t cch = (size_t)(pszNext - pszVerb) + 1; ASSERT(0 < cch && cch < ARRAYSIZE(szVerb)); // we should be large enough for all the canonical verbs we use StrCpyNW(szVerb, pszVerb, min(cch, ARRAYSIZE(szVerb))); pszVerb = pszNext + 1; } else { size_t cch = lstrlenW(pszVerb) + 1; ASSERT(0 < cch && cch < ARRAYSIZE(szVerb)); // we should be large enough for all the canonical verbs we use StrCpyNW(szVerb, pszVerb, min(cch, ARRAYSIZE(szVerb))); pszVerb += cch - 1; // point at NULL } ContextMenu_DeleteCommandByName(_pcm, hmenu, idCmdFirst, szVerb); } } return hr; } // Forward everything to the given context menu, // but disable popup menus // class CContextMenuWithoutPopups : CContextMenuForwarder { public: STDMETHODIMP QueryContextMenu(HMENU hmenu, UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags); protected: CContextMenuWithoutPopups(IUnknown* punk) : CContextMenuForwarder(punk) {} friend HRESULT Create_ContextMenuWithoutPopups(IUnknown* punk, REFIID riid, void **ppv); }; HRESULT Create_ContextMenuWithoutPopups(IUnknown* punk, REFIID riid, void **ppv) { HRESULT hr = E_OUTOFMEMORY; *ppv = NULL; CContextMenuWithoutPopups* p = new CContextMenuWithoutPopups(punk); if (p) { hr = p->QueryInterface(riid, ppv); p->Release(); } return hr; } HRESULT CContextMenuWithoutPopups::QueryContextMenu(HMENU hmenu, UINT indexMenu,UINT idCmdFirst,UINT idCmdLast,UINT uFlags) { HRESULT hr = CContextMenuForwarder::QueryContextMenu(hmenu,indexMenu,idCmdFirst,idCmdLast,uFlags); if (SUCCEEDED(hr)) { MENUITEMINFO mii; // Disable any submenus that were just added mii.cbSize = sizeof(mii); idCmdLast = idCmdFirst + ShortFromResult(hr); for (UINT i = idCmdFirst; i < idCmdLast; i++) { mii.fMask = MIIM_STATE | MIIM_SUBMENU; if (GetMenuItemInfo(hmenu, i, FALSE, &mii) && mii.hSubMenu && (mii.fState & (MFS_DISABLED | MFS_GRAYED)) != (MFS_DISABLED | MFS_GRAYED)) { mii.fMask = MIIM_STATE; mii.fState |= MFS_DISABLED | MFS_GRAYED; SetMenuItemInfo(hmenu, i, FALSE, &mii); } } } return hr; }