base
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
// ShellContextMenu.cpp: implementation of the CShellContextMenu class.
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2000-2001 by Paolo Messina
|
||||
// (http://www.geocities.com/ppescher - ppescher@yahoo.com)
|
||||
//
|
||||
// The contents of this file are subject to the Artistic License (the "License").
|
||||
// You may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at:
|
||||
// http://www.opensource.org/licenses/artistic-license.html
|
||||
//
|
||||
// If you find this code useful, credits would be nice!
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ShellContextMenu.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
BOOL CShellContextMenu::InvokeCommand(UINT nCmdID)
|
||||
{
|
||||
if (!IsValid() || !IsCommandInRange(nCmdID))
|
||||
return FALSE;
|
||||
|
||||
CMINVOKECOMMANDINFO cmi;
|
||||
ZeroMemory(&cmi, sizeof(CMINVOKECOMMANDINFO));
|
||||
cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
|
||||
cmi.hwnd = m_pOwner->GetSafeHwnd();
|
||||
cmi.lpVerb = MAKEINTRESOURCE(nCmdID - m_nCmdFirstID);
|
||||
cmi.nShow = SW_SHOWNORMAL;
|
||||
|
||||
return (NOERROR == m_pCtxMenu->InvokeCommand(&cmi));
|
||||
}
|
||||
|
||||
BOOL CShellContextMenu::FillMenu(CMenu *pMenu, UINT nStartIndex, UINT nCmdFirstID, UINT nCmdLastID, UINT nFlags)
|
||||
{
|
||||
if (!IsValid())
|
||||
return FALSE;
|
||||
|
||||
m_nCmdFirstID = nCmdFirstID;
|
||||
m_nCmdLastID = nCmdLastID;
|
||||
|
||||
UINT nDefID = pMenu->GetDefaultItem(GMDI_USEDISABLED, TRUE);
|
||||
|
||||
HRESULT hr = m_pCtxMenu->QueryContextMenu(pMenu->GetSafeHmenu(),
|
||||
nStartIndex, m_nCmdFirstID, m_nCmdLastID, nFlags);
|
||||
|
||||
if (nFlags & CMF_NODEFAULT)
|
||||
pMenu->SetDefaultItem(nDefID, TRUE);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
m_nCmdLastID = m_nCmdFirstID = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
m_nCmdLastID = m_nCmdFirstID + HRESULT_CODE(hr) - 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL CShellContextMenu::HandleMenuMessage(UINT message, WPARAM wParam, LPARAM lParam, LRESULT *pLResult)
|
||||
{
|
||||
if (!IsValid())
|
||||
return FALSE;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_MENUSELECT:
|
||||
{
|
||||
// look for a parent frame, to update its status bar
|
||||
if (m_pOwner == NULL)
|
||||
return FALSE;
|
||||
CFrameWnd* pFrame = m_pOwner->GetTopLevelFrame();
|
||||
if (pFrame == NULL)
|
||||
return FALSE;
|
||||
|
||||
// provide status bar text
|
||||
*pLResult = 0;
|
||||
CString sStatusText;
|
||||
|
||||
UINT uItem = (UINT) LOWORD(wParam);
|
||||
UINT fuFlags = (UINT) HIWORD(wParam);
|
||||
|
||||
if (fuFlags == 0xFFFF) // menu was closed
|
||||
return FALSE;
|
||||
|
||||
// get the first item of submenu, if popup item
|
||||
if (fuFlags & MF_POPUP)
|
||||
uItem = ::GetMenuItemID(::GetSubMenu((HMENU)lParam, uItem), 0);
|
||||
|
||||
// check if it's a valid item
|
||||
if (!(fuFlags & MF_SEPARATOR)
|
||||
&& (uItem == 0 || !IsCommandInRange(uItem)))
|
||||
return FALSE;
|
||||
|
||||
// get description
|
||||
if (!(fuFlags & MF_SEPARATOR))
|
||||
GetCommandDescription(uItem, sStatusText);
|
||||
|
||||
// update status text, even if empty
|
||||
pFrame->SetMessageText(sStatusText);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_INITMENUPOPUP: // initialize sub-menus
|
||||
case WM_MEASUREITEM: // handle owner-draw items
|
||||
case WM_DRAWITEM:
|
||||
{
|
||||
// prepare result in case we handle the message
|
||||
// (if we don't, it will be discarded)
|
||||
*pLResult = TRUE;
|
||||
if (message == WM_INITMENUPOPUP)
|
||||
*pLResult = 0;
|
||||
|
||||
// check if it's a menu message
|
||||
if (message == WM_MEASUREITEM
|
||||
&& ((LPMEASUREITEMSTRUCT)lParam)->CtlType != ODT_MENU)
|
||||
return FALSE;
|
||||
if (message == WM_DRAWITEM
|
||||
&& ((LPDRAWITEMSTRUCT)lParam)->CtlType != ODT_MENU)
|
||||
return FALSE;
|
||||
|
||||
// these messages need interface version 2
|
||||
SContextMenu2Ptr pCtxMenu2(m_pCtxMenu);
|
||||
if (!pCtxMenu2.IsValid())
|
||||
return FALSE;
|
||||
|
||||
return (NOERROR == pCtxMenu2->HandleMenuMsg(message, wParam, lParam));
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CShellContextMenu::GetCommandDescription(UINT nCmdID, CString& rText)
|
||||
{
|
||||
if (!IsValid() || !IsCommandInRange(nCmdID))
|
||||
return FALSE;
|
||||
|
||||
// make a buffer large enough to hold either a Unicode or Ansi
|
||||
// string and initialize it to zeroes, because some shell
|
||||
// extensions return success even when they don't copy anything
|
||||
// to the buffer. Conversion is achieved by a CString object.
|
||||
WCHAR szHelpText[MAX_PATH];
|
||||
ZeroMemory(szHelpText, sizeof(WCHAR)*MAX_PATH);
|
||||
|
||||
// try with Unicode first (it seems Explorer does so)
|
||||
HRESULT hr = m_pCtxMenu->GetCommandString(nCmdID - m_nCmdFirstID,
|
||||
GCS_HELPTEXTW, NULL, (LPSTR)szHelpText, MAX_PATH);
|
||||
if (*(LPWSTR)szHelpText != 0) // buffer was used
|
||||
rText = (LPWSTR)szHelpText;
|
||||
else
|
||||
{
|
||||
// otherwise try with Ansi
|
||||
hr = m_pCtxMenu->GetCommandString(nCmdID - m_nCmdFirstID,
|
||||
GCS_HELPTEXTA, NULL, (LPSTR)szHelpText, MAX_PATH);
|
||||
if (*(LPSTR)szHelpText != 0) // buffer was used
|
||||
rText = (LPSTR)szHelpText;
|
||||
}
|
||||
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
BOOL CShellContextMenu::Create(IShellFolder *pParentFolder, LPCITEMIDLIST pidl)
|
||||
{
|
||||
m_pCtxMenu = SContextMenuPtr(pParentFolder, pidl);
|
||||
return m_pCtxMenu.IsValid();
|
||||
}
|
||||
|
||||
// a NULL pointer to unsubclass
|
||||
void CShellContextMenu::SetOwner(CWnd *pOwner)
|
||||
{
|
||||
if (m_pOwner != NULL || pOwner == NULL)
|
||||
UnsubclassOwner();
|
||||
|
||||
m_pOwner = pOwner;
|
||||
if (m_pOwner != NULL)
|
||||
SubclassOwner();
|
||||
}
|
||||
|
||||
const LPCTSTR SH_CTXMENU_OBJ = _T("ShellContextMenu");
|
||||
|
||||
void CShellContextMenu::SubclassOwner()
|
||||
{
|
||||
ASSERT(::IsWindow(m_pOwner->GetSafeHwnd()));
|
||||
|
||||
m_oldWndProc = (WNDPROC)::GetWindowLong(*m_pOwner, GWL_WNDPROC);
|
||||
::SetProp(*m_pOwner, SH_CTXMENU_OBJ, (HANDLE)this);
|
||||
::SetWindowLong(*m_pOwner, GWL_WNDPROC, (LONG)WindowProc);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK CShellContextMenu::WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
CShellContextMenu *pThis =
|
||||
(CShellContextMenu*)::GetProp(hwnd, SH_CTXMENU_OBJ);
|
||||
|
||||
LRESULT lResult;
|
||||
if (pThis->HandleMenuMessage(message, wParam, lParam, &lResult))
|
||||
return lResult; // success, no default processing
|
||||
|
||||
if (message == WM_DESTROY)
|
||||
pThis->UnsubclassOwner();
|
||||
|
||||
return ::CallWindowProc(pThis->m_oldWndProc, hwnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
void CShellContextMenu::UnsubclassOwner()
|
||||
{
|
||||
ASSERT(::IsWindow(m_pOwner->GetSafeHwnd()));
|
||||
|
||||
::RemoveProp(*m_pOwner, SH_CTXMENU_OBJ);
|
||||
::SetWindowLong(*m_pOwner, GWL_WNDPROC, (LONG)m_oldWndProc);
|
||||
m_pOwner = NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user