首页 > 代码库 > Creating Context Menu / 创建上下文菜单项 / Win32, VC++, Windows, DLL, ATL, COM
Creating Context Menu / 创建上下文菜单项 / Win32, VC++, Windows, DLL, ATL, COM
创建上下文菜单项
1、新建一个ATL Project。
2、建议将Project Property中Linker – General - “Register Output” 设为no,C/C++ - “Code Generation” - “Runtime Library” 设为 /MTd。
3、在Solution Explorer中右键Add Class,选择ATL Simple Object。并在弹出的对话框中为该Class命名。
4、添加完成后建议Build一下Project,MIDL compiler将根据 .idl文件生成IIDs and CLSIDs。
5、(可选)在Solution Explorer中右键Add Resource导入图标资源。
6、切换到新增Class的 .h文件中,使其继承接口IShellExtInit和IContextMenu。并在 .cpp文件中,参照MSDN给出实现。
1 // MyContextMenu.h : Declaration of the CMyContextMenu 2 3 #pragma once 4 #include "resource.h" // main symbols 5 6 7 8 #include "ContextMenuExample_i.h" 9 #include <Shlobj.h>10 11 12 13 #if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)14 #error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object‘s and allow use of it‘s single-threaded COM object implementations. The threading model in your rgs file was set to ‘Free‘ as that is the only threading model supported in non DCOM Windows CE platforms."15 #endif16 17 using namespace ATL;18 19 20 // CMyContextMenu21 22 class ATL_NO_VTABLE CMyContextMenu :23 public CComObjectRootEx<CComSingleThreadModel>,24 public CComCoClass<CMyContextMenu, &CLSID_MyContextMenu>,25 public IDispatchImpl<IMyContextMenu, &IID_IMyContextMenu, 26 &LIBID_ContextMenuExampleLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,27 public IShellExtInit,28 public IContextMenu29 {30 public:31 CMyContextMenu()32 {33 }34 35 DECLARE_REGISTRY_RESOURCEID(IDR_MYCONTEXTMENU)36 37 38 BEGIN_COM_MAP(CMyContextMenu)39 COM_INTERFACE_ENTRY(IMyContextMenu)40 COM_INTERFACE_ENTRY(IDispatch)41 COM_INTERFACE_ENTRY(IShellExtInit)42 COM_INTERFACE_ENTRY(IContextMenu)43 END_COM_MAP()44 45 46 47 DECLARE_PROTECT_FINAL_CONSTRUCT()48 49 HRESULT FinalConstruct();50 51 void FinalRelease();52 53 public:54 // IShellExtInit Method55 HRESULT STDMETHODCALLTYPE Initialize(56 _In_opt_ PCIDLIST_ABSOLUTE pidlFolder,57 _In_opt_ IDataObject *pdtobj,58 _In_opt_ HKEY hkeyProgID);59 60 // IContextMenu Method61 HRESULT STDMETHODCALLTYPE QueryContextMenu(62 _In_ HMENU hmenu, 63 _In_ UINT indexMenu, 64 _In_ UINT idCmdFirst,65 _In_ UINT idCmdLast,66 _In_ UINT uFlags);67 68 HRESULT STDMETHODCALLTYPE InvokeCommand(69 _In_ CMINVOKECOMMANDINFO *pici);70 71 HRESULT STDMETHODCALLTYPE GetCommandString(72 _In_ UINT_PTR idCmd,73 _In_ UINT uType,74 _Reserved_ UINT *pReserved,75 _Out_writes_bytes_((uType & GCS_UNICODE) ? (cchMax * sizeof(wchar_t)) : cchMax) _When_(!(uType & (GCS_VALIDATEA | GCS_VALIDATEW)), _Null_terminated_) CHAR *pszName,76 _In_ UINT cchMax);77 78 private:79 HBITMAP MenuIcon1;80 HBITMAP MenuIcon2;81 HBITMAP MenuIcon3;82 HBITMAP MenuIcon4;83 84 85 };86 87 OBJECT_ENTRY_AUTO(__uuidof(MyContextMenu), CMyContextMenu)
1 // MyContextMenu.cpp : Implementation of CMyContextMenu 2 3 #include "stdafx.h" 4 #include "MyContextMenu.h" 5 6 7 // CMyContextMenu 8 9 HRESULT CMyContextMenu::FinalConstruct() 10 { 11 HINSTANCE hInstance = _AtlBaseModule.GetModuleInstance(); 12 MenuIcon1 = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1)); 13 MenuIcon2 = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP2)); 14 MenuIcon3 = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP3)); 15 MenuIcon4 = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP4)); 16 17 return S_OK; 18 } 19 20 void CMyContextMenu::FinalRelease() 21 { 22 if (MenuIcon1 != NULL) 23 { 24 DeleteObject(MenuIcon1); 25 } 26 if (MenuIcon2 != NULL) 27 { 28 DeleteObject(MenuIcon2); 29 } 30 if (MenuIcon3 != NULL) 31 { 32 DeleteObject(MenuIcon3); 33 } 34 if (MenuIcon4 != NULL) 35 { 36 DeleteObject(MenuIcon4); 37 } 38 } 39 40 HRESULT CMyContextMenu::Initialize( 41 _In_opt_ PCIDLIST_ABSOLUTE pidlFolder, 42 _In_opt_ IDataObject *pdtobj, 43 _In_opt_ HKEY hkeyProgID) { 44 HRESULT hr; 45 UINT nFileCount; 46 47 FORMATETC fmt = 48 { 49 CF_HDROP, 50 NULL, 51 DVASPECT_CONTENT, 52 -1, 53 TYMED_HGLOBAL 54 }; 55 56 STGMEDIUM sm = 57 { 58 TYMED_HGLOBAL 59 }; 60 61 hr = pdtobj->GetData(&fmt, &sm); 62 63 if (FAILED(hr)) 64 { 65 return hr; 66 } 67 68 // query quantity of selected files 69 nFileCount = DragQueryFile((HDROP)sm.hGlobal, 0xFFFFFFFF, NULL, 0); 70 71 if (nFileCount == 1) // deal with only one file 72 { 73 // analyze selected file 74 75 } 76 else 77 { 78 hr = E_INVALIDARG; 79 } 80 81 ReleaseStgMedium(&sm); 82 83 return hr; 84 } 85 86 // IContextMenu Method 87 HRESULT CMyContextMenu::QueryContextMenu( 88 _In_ HMENU hmenu, 89 _In_ UINT indexMenu, 90 _In_ UINT idCmdFirst, 91 _In_ UINT idCmdLast, 92 _In_ UINT uFlags) { 93 94 UINT uCmdID = idCmdFirst; 95 LPCWSTR text1 = TEXT("新增层叠菜单项1"); 96 LPCWSTR text2 = TEXT("新增菜单项2"); 97 LPCWSTR text3 = TEXT("新增菜单项3"); 98 LPCWSTR text4 = TEXT("新增菜单项4"); 99 // do nothing when flag includes CMF_DEFAULTONLY.100 if (uFlags & CMF_DEFAULTONLY)101 {102 return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, 0);103 }104 InsertMenu(hmenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);105 indexMenu++;106 HMENU hSubMenu = CreateMenu();107 if (hSubMenu)108 {109 InsertMenu(hSubMenu, 0, MF_STRING | MF_BYPOSITION, uCmdID++, text2);110 SetMenuItemBitmaps(hSubMenu, 0, MF_BYPOSITION, MenuIcon2, MenuIcon2);111 InsertMenu(hSubMenu, 1, MF_STRING | MF_BYPOSITION, uCmdID++, text3);112 SetMenuItemBitmaps(hSubMenu, 1, MF_BYPOSITION, MenuIcon3, MenuIcon3);113 InsertMenu(hSubMenu, 2, MF_STRING | MF_BYPOSITION, uCmdID++, text4);114 SetMenuItemBitmaps(hSubMenu, 2, MF_BYPOSITION, MenuIcon4, MenuIcon4);115 // InsertMenu(hSubMenu, 3, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);//插入分隔线116 }117 InsertMenu(hmenu, indexMenu, MF_STRING | MF_POPUP | MF_BYPOSITION, (UINT_PTR)hSubMenu, text1);118 SetMenuItemBitmaps(hmenu, indexMenu, MF_BYPOSITION, MenuIcon1, MenuIcon1);119 indexMenu++;120 InsertMenu(hmenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);121 indexMenu++;122 123 // inform the explorer how many menu item we have added124 return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, uCmdID - idCmdFirst);125 }126 127 HRESULT CMyContextMenu::InvokeCommand(128 _In_ CMINVOKECOMMANDINFO *pici) {129 if (0 != HIWORD(pici->lpVerb))130 return E_INVALIDARG;131 // get index of added menu item132 switch (LOWORD(pici->lpVerb))133 {134 case 0:135 {136 // 执行新增菜单项2触发的操作137 STARTUPINFO si = { sizeof(si) };138 PROCESS_INFORMATION pi;139 TCHAR szCommandLine[] = TEXT("notepad");140 BOOL bCreateRet = CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);141 142 break;143 }144 case 1:145 {146 // 执行新增菜单项3触发的操作147 STARTUPINFO si = { sizeof(si) };148 PROCESS_INFORMATION pi;149 TCHAR szCommandLine[] = TEXT("write");150 BOOL bCreateRet = CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);151 152 break;153 }154 case 2:155 {156 // 执行新增菜单项4触发的操作157 STARTUPINFO si = { sizeof(si) };158 PROCESS_INFORMATION pi;159 TCHAR szCommandLine[] = TEXT("cmd");160 BOOL bCreateRet = CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);161 162 break;163 }164 default:165 {166 return E_INVALIDARG;167 break;168 }169 }170 return S_OK;171 }172 173 HRESULT CMyContextMenu::GetCommandString(174 _In_ UINT_PTR idCmd,175 _In_ UINT uType,176 _Reserved_ UINT *pReserved,177 _Out_writes_bytes_((uType & GCS_UNICODE) ? (cchMax * sizeof(wchar_t)) : cchMax) _When_(!(uType & (GCS_VALIDATEA | GCS_VALIDATEW)), _Null_terminated_) CHAR *pszName,178 _In_ UINT cchMax) {179 USES_CONVERSION;180 LPCTSTR szPrompt;181 // copy help info to cache when explorer ask182 if (uType & GCS_HELPTEXT)183 {184 switch (idCmd)185 {186 case 0:187 szPrompt = _T("新增菜单项2说明文字");188 break;189 case 1:190 szPrompt = _T("新增菜单项3说明文字");191 break;192 case 2:193 szPrompt = _T("新增菜单项4说明文字");194 break;195 default:196 //ATLASSERT(0); // should never get here197 return E_INVALIDARG;198 break;199 }200 if (uType & GCS_UNICODE)201 {202 lstrcpynW((LPWSTR)pszName, T2CW(szPrompt), cchMax);203 }204 else205 {206 lstrcpynA(pszName, T2CA(szPrompt), cchMax);207 }208 return S_OK;209 }210 return E_INVALIDARG;211 }
7、在 .rgs文件中添加注册表信息,确保各GUID与 .idl文件中的一致。
1 HKCR 2 { 3 NoRemove CLSID 4 { 5 ForceRemove {9C50C98F-E1FF-41CF-BD54-E9A3BBDDDEF8} = s ‘MyContextMenu Class‘ 6 { 7 ForceRemove Programmable 8 InprocServer32 = s ‘%MODULE%‘ 9 {10 val ThreadingModel = s ‘Apartment‘11 }12 TypeLib = s ‘{EB1C2F43-315D-4D8F-9A2A-70E67BE888E2}‘13 Version = s ‘1.0‘14 }15 }16 17 NoRemove *18 {19 NoRemove ShellEx20 {21 NoRemove ContextMenuHandlers22 {23 ForceRemove MyContextMenu = s ‘{9C50C98F-E1FF-41CF-BD54-E9A3BBDDDEF8}‘24 }25 }26 }27 }
8、Build Project 后打开cmd.exe,通过regsvr32命令注册或解注册生成的 .dll文件。
10、查看效果如下图所示。
——————————————————
本文为本人原创,如需转载请注明出处。
Creating Context Menu / 创建上下文菜单项 / Win32, VC++, Windows, DLL, ATL, COM
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。