MFC 右键系统菜单
来源:互联网 发布:淘宝上的笛子怎么样 编辑:程序博客网 时间:2024/06/08 18:30
MFC 右键系统菜单
CShellContextMenu类的使用
xxx.h文件
// ShellContextMenu.h: Schnittstelle die Klasse CShellContextMenu.////////////////////////////////////////////////////////////////////////#if !defined(AFX_SHELLCONTEXTMENU_H__A358AACF_7C7C_410D_AD29_67310B2DDC22__INCLUDED_)#define AFX_SHELLCONTEXTMENU_H__A358AACF_7C7C_410D_AD29_67310B2DDC22__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000/////////////////////////////////////////////////////////////////////// class to show shell contextmenu of files/folders/shell objects// developed by R. Engels 2003/////////////////////////////////////////////////////////////////////class CShellContextMenu {public: CMenu * GetMenu (); void SetObjects (IShellFolder * psfFolder, LPITEMIDLIST pidlItem); void SetObjects (IShellFolder * psfFolder, LPITEMIDLIST * pidlArray, int nItemCount); void SetObjects (LPITEMIDLIST pidl); void SetObjects (CString strObject); void SetObjects (CStringArray &strArray); UINT ShowContextMenu (CWnd* pWnd, CPoint pt); CShellContextMenu(); virtual ~CShellContextMenu();private: int nItems; BOOL bDelete; CMenu * m_Menu; IShellFolder * m_psfFolder; LPITEMIDLIST * m_pidlArray; void InvokeCommand (LPCONTEXTMENU pContextMenu, UINT idCommand); BOOL GetContextMenu (void ** ppContextMenu, int & iMenuType); HRESULT SHBindToParentEx (LPCITEMIDLIST pidl, REFIID riid, VOID **ppv, LPCITEMIDLIST *ppidlLast); static LRESULT CALLBACK HookWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); void FreePIDLArray (LPITEMIDLIST * pidlArray); LPITEMIDLIST CopyPIDL (LPCITEMIDLIST pidl, int cb = -1); UINT GetPIDLSize (LPCITEMIDLIST pidl); LPBYTE GetPIDLPos (LPCITEMIDLIST pidl, int nPos); int GetPIDLCount (LPCITEMIDLIST pidl);};#endif // !defined(AFX_SHELLCONTEXTMENU_H__A358AACF_7C7C_410D_AD29_67310B2DDC22__INCLUDED_)
.cpp文件
// ShellContextMenu.cpp: Implementierung der Klasse CShellContextMenu.////////////////////////////////////////////////////////////////////////#include "stdafx.h"#include "ShellContextMenu.h"#ifdef _DEBUG#undef THIS_FILEstatic char THIS_FILE[]=__FILE__;#define new DEBUG_NEW#endif//////////////////////////////////////////////////////////////////////// Konstruktion/Destruktion//////////////////////////////////////////////////////////////////////#define MIN_ID 1#define MAX_ID 10000IContextMenu2 * g_IContext2 = NULL;IContextMenu3 * g_IContext3 = NULL;CShellContextMenu::CShellContextMenu(){ m_psfFolder = NULL; m_pidlArray = NULL; m_Menu = NULL;}CShellContextMenu::~CShellContextMenu(){ // free all allocated datas if (m_psfFolder && bDelete) m_psfFolder->Release (); m_psfFolder = NULL; FreePIDLArray (m_pidlArray); m_pidlArray = NULL; if (m_Menu) delete m_Menu;}// this functions determines which version of IContextMenu is avaibale for those objects (always the highest one)// and returns that interfaceBOOL CShellContextMenu::GetContextMenu (void ** ppContextMenu, int & iMenuType){ *ppContextMenu = NULL; LPCONTEXTMENU icm1 = NULL; // first we retrieve the normal IContextMenu interface (every object should have it) m_psfFolder->GetUIObjectOf (NULL, nItems, (LPCITEMIDLIST *)m_pidlArray, IID_IContextMenu, NULL, (void**) &icm1); if (icm1) { // since we got an IContextMenu interface we can now obtain the higher version interfaces via that /* if (icm1->QueryInterface (IID_IContextMenu3, ppContextMenu) == NOERROR) iMenuType = 3; else if (icm1->QueryInterface (IID_IContextMenu2, ppContextMenu) == NOERROR) iMenuType = 2; if (*ppContextMenu) icm1->Release(); // we can now release version 1 interface, cause we got a higher one else */ { iMenuType = 1; *ppContextMenu = icm1; // since no higher versions were found } // redirect ppContextMenu to version 1 interface } else return (FALSE); // something went wrong return (TRUE); // success}LRESULT CALLBACK CShellContextMenu::HookWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){ switch (message) { case WM_MENUCHAR: // only supported by IContextMenu3 if (g_IContext3) { LRESULT lResult = 0; g_IContext3->HandleMenuMsg2 (message, wParam, lParam, &lResult); return (lResult); } break; case WM_DRAWITEM: case WM_MEASUREITEM: if (wParam) break; // if wParam != 0 then the message is not menu-related case WM_INITMENUPOPUP: if (g_IContext2) g_IContext2->HandleMenuMsg (message, wParam, lParam); else // version 3 g_IContext3->HandleMenuMsg (message, wParam, lParam); return (message == WM_INITMENUPOPUP ? 0 : TRUE); // inform caller that we handled WM_INITPOPUPMENU by ourself break; default: break; } // call original WndProc of window to prevent undefined bevhaviour of window return ::CallWindowProc ((WNDPROC) GetProp ( hWnd, TEXT ("OldWndProc")), hWnd, message, wParam, lParam);}UINT CShellContextMenu::ShowContextMenu(CWnd *pWnd, CPoint pt){ int iMenuType = 0; // to know which version of IContextMenu is supported LPCONTEXTMENU pContextMenu; // common pointer to IContextMenu and higher version interface if (!GetContextMenu ((void**) &pContextMenu, iMenuType)) return (0); // something went wrong if (!m_Menu) { delete m_Menu; m_Menu = NULL; m_Menu = new CMenu; m_Menu->CreatePopupMenu(); } // lets fill the our popupmenu pContextMenu->QueryContextMenu (m_Menu->m_hMenu, m_Menu->GetMenuItemCount(), MIN_ID, MAX_ID, CMF_NORMAL | CMF_EXPLORE); // subclass window to handle menurelated messages in CShellContextMenu WNDPROC OldWndProc; if (iMenuType > 1) // only subclass if its version 2 or 3 { OldWndProc = (WNDPROC) SetWindowLong (pWnd->m_hWnd, GWL_WNDPROC, (DWORD) HookWndProc); if (iMenuType == 2) g_IContext2 = (LPCONTEXTMENU2) pContextMenu; else // version 3 g_IContext3 = (LPCONTEXTMENU3) pContextMenu; } else OldWndProc = NULL; UINT idCommand = m_Menu->TrackPopupMenu ( TPM_RETURNCMD | TPM_LEFTALIGN | TPM_NOANIMATION | TPM_VCENTERALIGN, pt.x, pt.y, pWnd); if (OldWndProc) // unsubclass SetWindowLong (pWnd->m_hWnd, GWL_WNDPROC, (DWORD) OldWndProc); if (idCommand >= MIN_ID && idCommand <= MAX_ID) // see if returned idCommand belongs to shell menu entries { InvokeCommand (pContextMenu, idCommand - MIN_ID); // execute related command idCommand = 0; }else idCommand = -1; pContextMenu->Release(); g_IContext2 = NULL; g_IContext3 = NULL; return (idCommand);}void CShellContextMenu::InvokeCommand (LPCONTEXTMENU pContextMenu, UINT idCommand){ CMINVOKECOMMANDINFO cmi = {0}; cmi.cbSize = sizeof (CMINVOKECOMMANDINFO); cmi.lpVerb = (LPSTR) MAKEINTRESOURCE (idCommand); cmi.nShow = SW_SHOWNORMAL; pContextMenu->InvokeCommand (&cmi);}void CShellContextMenu::SetObjects(CString strObject){ // only one object is passed CStringArray strArray; strArray.Add (strObject); // create a CStringArray with one element SetObjects (strArray); // and pass it to SetObjects (CStringArray &strArray) // for further processing}void CShellContextMenu::SetObjects(CStringArray &strArray){ // free all allocated datas if (m_psfFolder && bDelete) m_psfFolder->Release (); m_psfFolder = NULL; FreePIDLArray (m_pidlArray); m_pidlArray = NULL; // get IShellFolder interface of Desktop (root of shell namespace) IShellFolder * psfDesktop = NULL; SHGetDesktopFolder (&psfDesktop); // needed to obtain full qualified pidl // ParseDisplayName creates a PIDL from a file system path relative to the IShellFolder interface // but since we use the Desktop as our interface and the Desktop is the namespace root // that means that it's a fully qualified PIDL, which is what we need LPITEMIDLIST pidl = NULL;#ifndef _UNICODE OLECHAR * olePath = NULL; olePath = (OLECHAR *) calloc (strArray.GetAt (0).GetLength () + 1, sizeof (OLECHAR)); ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strArray.GetAt(0), -1, olePath, strArray.GetAt(0).GetLength() + 1); psfDesktop->ParseDisplayName (NULL, 0, olePath, NULL, &pidl, NULL); free (olePath);#else psfDesktop->ParseDisplayName (NULL, 0, strArray.GetAt (0).GetBuffer (0), NULL, &pidl, NULL);#endif // now we need the parent IShellFolder interface of pidl, and the relative PIDL to that interface LPITEMIDLIST pidlItem = NULL; // relative pidl SHBindToParentEx (pidl, IID_IShellFolder, (void **) &m_psfFolder, NULL); free (pidlItem); // get interface to IMalloc (need to free the PIDLs allocated by the shell functions) LPMALLOC lpMalloc = NULL; SHGetMalloc (&lpMalloc); lpMalloc->Free (pidl); // now we have the IShellFolder interface to the parent folder specified in the first element in strArray // since we assume that all objects are in the same folder (as it's stated in the MSDN) // we now have the IShellFolder interface to every objects parent folder IShellFolder * psfFolder = NULL; nItems = strArray.GetSize (); for (int i = 0; i < nItems; i++) {#ifndef _UNICODE olePath = (OLECHAR *) calloc (strArray.GetAt (i).GetLength () + 1, sizeof (OLECHAR)); ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, strArray.GetAt(i), -1, olePath, strArray.GetAt(i).GetLength() + 1); psfDesktop->ParseDisplayName (NULL, 0, olePath, NULL, &pidl, NULL); free (olePath);#else psfDesktop->ParseDisplayName (NULL, 0, strArray.GetAt (i).GetBuffer (0), NULL, &pidl, NULL);#endif m_pidlArray = (LPITEMIDLIST *) realloc (m_pidlArray, (i + 1) * sizeof (LPITEMIDLIST)); // get relative pidl via SHBindToParent SHBindToParentEx (pidl, IID_IShellFolder, (void **) &psfFolder, (LPCITEMIDLIST *) &pidlItem); m_pidlArray[i] = CopyPIDL (pidlItem); // copy relative pidl to pidlArray free (pidlItem); lpMalloc->Free (pidl); // free pidl allocated by ParseDisplayName psfFolder->Release (); } lpMalloc->Release (); psfDesktop->Release (); bDelete = TRUE; // indicates that m_psfFolder should be deleted by CShellContextMenu}// only one full qualified PIDL has been passedvoid CShellContextMenu::SetObjects(LPITEMIDLIST pidl){ // free all allocated datas if (m_psfFolder && bDelete) m_psfFolder->Release (); m_psfFolder = NULL; FreePIDLArray (m_pidlArray); m_pidlArray = NULL; // full qualified PIDL is passed so we need // its parent IShellFolder interface and its relative PIDL to that LPITEMIDLIST pidlItem = NULL; SHBindToParent ((LPCITEMIDLIST) pidl, IID_IShellFolder, (void **) &m_psfFolder, (LPCITEMIDLIST *) &pidlItem); m_pidlArray = (LPITEMIDLIST *) malloc (sizeof (LPITEMIDLIST)); // allocate ony for one elemnt m_pidlArray[0] = CopyPIDL (pidlItem); // now free pidlItem via IMalloc interface (but not m_psfFolder, that we need later LPMALLOC lpMalloc = NULL; SHGetMalloc (&lpMalloc); lpMalloc->Free (pidlItem); lpMalloc->Release(); nItems = 1; bDelete = TRUE; // indicates that m_psfFolder should be deleted by CShellContextMenu}// IShellFolder interface with a relative pidl has been passedvoid CShellContextMenu::SetObjects(IShellFolder *psfFolder, LPITEMIDLIST pidlItem){ // free all allocated datas if (m_psfFolder && bDelete) m_psfFolder->Release (); m_psfFolder = NULL; FreePIDLArray (m_pidlArray); m_pidlArray = NULL; m_psfFolder = psfFolder; m_pidlArray = (LPITEMIDLIST *) malloc (sizeof (LPITEMIDLIST)); m_pidlArray[0] = CopyPIDL (pidlItem); nItems = 1; bDelete = FALSE; // indicates wheter m_psfFolder should be deleted by CShellContextMenu}void CShellContextMenu::SetObjects(IShellFolder * psfFolder, LPITEMIDLIST *pidlArray, int nItemCount){ // free all allocated datas if (m_psfFolder && bDelete) m_psfFolder->Release (); m_psfFolder = NULL; FreePIDLArray (m_pidlArray); m_pidlArray = NULL; m_psfFolder = psfFolder; m_pidlArray = (LPITEMIDLIST *) malloc (nItemCount * sizeof (LPITEMIDLIST)); for (int i = 0; i < nItemCount; i++) m_pidlArray[i] = CopyPIDL (pidlArray[i]); nItems = nItemCount; bDelete = FALSE; // indicates wheter m_psfFolder should be deleted by CShellContextMenu}void CShellContextMenu::FreePIDLArray(LPITEMIDLIST *pidlArray){ if (!pidlArray) return; int iSize = _msize (pidlArray) / sizeof (LPITEMIDLIST); for (int i = 0; i < iSize; i++) free (pidlArray[i]); free (pidlArray);}LPITEMIDLIST CShellContextMenu::CopyPIDL (LPCITEMIDLIST pidl, int cb){ if (cb == -1) cb = GetPIDLSize (pidl); // Calculate size of list. LPITEMIDLIST pidlRet = (LPITEMIDLIST) calloc (cb + sizeof (USHORT), sizeof (BYTE)); if (pidlRet) CopyMemory(pidlRet, pidl, cb); return (pidlRet);}UINT CShellContextMenu::GetPIDLSize (LPCITEMIDLIST pidl){ if (!pidl) return 0; int nSize = 0; LPITEMIDLIST pidlTemp = (LPITEMIDLIST) pidl; while (pidlTemp->mkid.cb) { nSize += pidlTemp->mkid.cb; pidlTemp = (LPITEMIDLIST) (((LPBYTE) pidlTemp) + pidlTemp->mkid.cb); } return nSize;}CMenu * CShellContextMenu::GetMenu(){ if (!m_Menu) { m_Menu = new CMenu; m_Menu->CreatePopupMenu(); // create the popupmenu (its empty) } return (m_Menu);}// this is workaround function for the Shell API Function SHBindToParent// SHBindToParent is not available under Win95/98HRESULT CShellContextMenu::SHBindToParentEx (LPCITEMIDLIST pidl, REFIID riid, VOID **ppv, LPCITEMIDLIST *ppidlLast){ HRESULT hr = 0; if (!pidl || !ppv) return E_POINTER; int nCount = GetPIDLCount (pidl); if (nCount == 0) // desktop pidl of invalid pidl return E_POINTER; IShellFolder * psfDesktop = NULL; SHGetDesktopFolder (&psfDesktop); if (nCount == 1) // desktop pidl { if ((hr = psfDesktop->QueryInterface(riid, ppv)) == S_OK) { if (ppidlLast) *ppidlLast = CopyPIDL (pidl); } psfDesktop->Release (); return hr; } LPBYTE pRel = GetPIDLPos (pidl, nCount - 1); LPITEMIDLIST pidlParent = NULL; pidlParent = CopyPIDL (pidl, pRel - (LPBYTE) pidl); IShellFolder * psfFolder = NULL; if ((hr = psfDesktop->BindToObject (pidlParent, NULL, __uuidof (psfFolder), (void **) &psfFolder)) != S_OK) { free (pidlParent); psfDesktop->Release (); return hr; } if ((hr = psfFolder->QueryInterface (riid, ppv)) == S_OK) { if (ppidlLast) *ppidlLast = CopyPIDL ((LPCITEMIDLIST) pRel); } free (pidlParent); psfFolder->Release (); psfDesktop->Release (); return hr;}LPBYTE CShellContextMenu::GetPIDLPos (LPCITEMIDLIST pidl, int nPos){ if (!pidl) return 0; int nCount = 0; BYTE * pCur = (BYTE *) pidl; while (((LPCITEMIDLIST) pCur)->mkid.cb) { if (nCount == nPos) return pCur; nCount++; pCur += ((LPCITEMIDLIST) pCur)->mkid.cb; // + sizeof(pidl->mkid.cb); } if (nCount == nPos) return pCur; return NULL;}int CShellContextMenu::GetPIDLCount (LPCITEMIDLIST pidl){ if (!pidl) return 0; int nCount = 0; BYTE* pCur = (BYTE *) pidl; while (((LPCITEMIDLIST) pCur)->mkid.cb) { nCount++; pCur += ((LPCITEMIDLIST) pCur)->mkid.cb; } return nCount;}
简单使用 main.cpp
CString filepath="D:\\1.txt";CShellContextMenu* shellMenu = new CShellContextMenu(); shellMenu->SetObjects(filepath); //设置菜单弹出坐标DWORD dwPos = GetMessagePos();CPoint point( LOWORD(dwPos), HIWORD(dwPos) );UINT cmd=shellMenu->ShowContextMenu(this, point);delete shellMenu;shellMenu=NULL;
运行效果:
demo下载地址:
http://download.csdn.net/download/hilary929265053/9995259
阅读全文
0 0
- MFC 右键系统菜单
- MFC右键菜单
- MFC添加右键菜单
- MFC添加右键菜单
- MFC添加右键菜单
- MFC 右键菜单
- MFC添加右键菜单
- MFC右键菜单
- MFC 添加右键菜单
- MFC 右键菜单呼出
- MFC添加右键菜单
- MFC右键弹出菜单
- MFC添加右键菜单
- MFC 右键弹出菜单
- MFC右键菜单
- MFC 右键自定义菜单
- MFC-右键弹出菜单
- MFC右键弹出菜单
- 搜索树的建立,高度的获得,最大值的获得
- 实用小技巧
- Qt注意事项(2)
- Java学习笔记(17)-- 值传递与引用传递
- 欢迎使用CSDN-markdown编辑器
- MFC 右键系统菜单
- 关于循环删除集合中的元素
- Android Fragment销毁问题
- maven安装和eclipse集成
- 如何成为架构师系列:以数据为核心的架构(二)
- ---线上版本----php5.2.17---mysql5.55----nginx1.12.1编译安装
- “米录”讨论总结(四)
- 求出0~999之间的所有“水仙花数”并输出
- Http常见的请求参数