Creating Context Menu / 创建上下文菜单项 / Win32, VC++, Windows, DLL, ATL, COM

Posted 兰亭集

tags:

篇首语:本文由小常识网(cha138.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 #endif
16 
17 using namespace ATL;
18 
19 
20 // CMyContextMenu
21 
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 IContextMenu
29 {
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 Method
55     HRESULT STDMETHODCALLTYPE Initialize(
56         _In_opt_  PCIDLIST_ABSOLUTE pidlFolder,
57         _In_opt_  IDataObject *pdtobj,
58         _In_opt_  HKEY hkeyProgID);
59 
60     // IContextMenu Method
61     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)
MyContextMenu.h
  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 added
124     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 item
132     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 ask
182     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 here
197             return E_INVALIDARG;
198             break;
199         }
200         if (uType & GCS_UNICODE)
201         {
202             lstrcpynW((LPWSTR)pszName, T2CW(szPrompt), cchMax);
203         }
204         else
205         {
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 ShellEx
20         {
21             NoRemove ContextMenuHandlers
22             {
23                 ForceRemove MyContextMenu = s \'{9C50C98F-E1FF-41CF-BD54-E9A3BBDDDEF8}\'
24             }
25         }
26     }
27 }

8、Build Project 后打开cmd.exe,通过regsvr32命令注册或解注册生成的 .dll文件。

 

10、查看效果如下图所示。

 

 

——————————————————

本文为本人原创,如需转载请注明出处。

http://www.cnblogs.com/lantingji/p/5857380.html

以上是关于Creating Context Menu / 创建上下文菜单项 / Win32, VC++, Windows, DLL, ATL, COM的主要内容,如果未能解决你的问题,请参考以下文章

CONTEXT_CREATION_ERROR: Renderer: Error creating Canvas3D graphics context/Not a GL2 implementation

Android 中实现上下文菜单(Context menu)详解

Context Menu

启动时候报错由于没有扫包 error creating bean with name

Android 上下文菜单(Context Menu)

Spring 报错:Error creating bean with name