Creating Context Menu / 创建上下文菜单项 / 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给出实现。
// MyContextMenu.h : Declaration of the CMyContextMenu #pragma once
#include "resource.h" // main symbols #include "ContextMenuExample_i.h"
#include <Shlobj.h> #if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
#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."
#endif using namespace ATL; // CMyContextMenu class ATL_NO_VTABLE CMyContextMenu :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyContextMenu, &CLSID_MyContextMenu>,
public IDispatchImpl<IMyContextMenu, &IID_IMyContextMenu,
&LIBID_ContextMenuExampleLib, /*wMajor =*/ , /*wMinor =*/ >,
public IShellExtInit,
public IContextMenu
{
public:
CMyContextMenu()
{
} DECLARE_REGISTRY_RESOURCEID(IDR_MYCONTEXTMENU) BEGIN_COM_MAP(CMyContextMenu)
COM_INTERFACE_ENTRY(IMyContextMenu)
COM_INTERFACE_ENTRY(IDispatch)
COM_INTERFACE_ENTRY(IShellExtInit)
COM_INTERFACE_ENTRY(IContextMenu)
END_COM_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT() HRESULT FinalConstruct(); void FinalRelease(); public:
// IShellExtInit Method
HRESULT STDMETHODCALLTYPE Initialize(
_In_opt_ PCIDLIST_ABSOLUTE pidlFolder,
_In_opt_ IDataObject *pdtobj,
_In_opt_ HKEY hkeyProgID); // IContextMenu Method
HRESULT STDMETHODCALLTYPE QueryContextMenu(
_In_ HMENU hmenu,
_In_ UINT indexMenu,
_In_ UINT idCmdFirst,
_In_ UINT idCmdLast,
_In_ UINT uFlags); HRESULT STDMETHODCALLTYPE InvokeCommand(
_In_ CMINVOKECOMMANDINFO *pici); HRESULT STDMETHODCALLTYPE GetCommandString(
_In_ UINT_PTR idCmd,
_In_ UINT uType,
_Reserved_ UINT *pReserved,
_Out_writes_bytes_((uType & GCS_UNICODE) ? (cchMax * sizeof(wchar_t)) : cchMax) _When_(!(uType & (GCS_VALIDATEA | GCS_VALIDATEW)), _Null_terminated_) CHAR *pszName,
_In_ UINT cchMax); private:
HBITMAP MenuIcon1;
HBITMAP MenuIcon2;
HBITMAP MenuIcon3;
HBITMAP MenuIcon4; }; OBJECT_ENTRY_AUTO(__uuidof(MyContextMenu), CMyContextMenu)
MyContextMenu.h
// MyContextMenu.cpp : Implementation of CMyContextMenu #include "stdafx.h"
#include "MyContextMenu.h" // CMyContextMenu HRESULT CMyContextMenu::FinalConstruct()
{
HINSTANCE hInstance = _AtlBaseModule.GetModuleInstance();
MenuIcon1 = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP1));
MenuIcon2 = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP2));
MenuIcon3 = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP3));
MenuIcon4 = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BITMAP4)); return S_OK;
} void CMyContextMenu::FinalRelease()
{
if (MenuIcon1 != NULL)
{
DeleteObject(MenuIcon1);
}
if (MenuIcon2 != NULL)
{
DeleteObject(MenuIcon2);
}
if (MenuIcon3 != NULL)
{
DeleteObject(MenuIcon3);
}
if (MenuIcon4 != NULL)
{
DeleteObject(MenuIcon4);
}
} HRESULT CMyContextMenu::Initialize(
_In_opt_ PCIDLIST_ABSOLUTE pidlFolder,
_In_opt_ IDataObject *pdtobj,
_In_opt_ HKEY hkeyProgID) {
HRESULT hr;
UINT nFileCount; FORMATETC fmt =
{
CF_HDROP,
NULL,
DVASPECT_CONTENT,
-,
TYMED_HGLOBAL
}; STGMEDIUM sm =
{
TYMED_HGLOBAL
}; hr = pdtobj->GetData(&fmt, &sm); if (FAILED(hr))
{
return hr;
} // query quantity of selected files
nFileCount = DragQueryFile((HDROP)sm.hGlobal, 0xFFFFFFFF, NULL, ); if (nFileCount == ) // deal with only one file
{
// analyze selected file }
else
{
hr = E_INVALIDARG;
} ReleaseStgMedium(&sm); return hr;
} // IContextMenu Method
HRESULT CMyContextMenu::QueryContextMenu(
_In_ HMENU hmenu,
_In_ UINT indexMenu,
_In_ UINT idCmdFirst,
_In_ UINT idCmdLast,
_In_ UINT uFlags) { UINT uCmdID = idCmdFirst;
LPCWSTR text1 = TEXT("新增层叠菜单项1");
LPCWSTR text2 = TEXT("新增菜单项2");
LPCWSTR text3 = TEXT("新增菜单项3");
LPCWSTR text4 = TEXT("新增菜单项4");
// do nothing when flag includes CMF_DEFAULTONLY.
if (uFlags & CMF_DEFAULTONLY)
{
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, );
}
InsertMenu(hmenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, , NULL);
indexMenu++;
HMENU hSubMenu = CreateMenu();
if (hSubMenu)
{
InsertMenu(hSubMenu, , MF_STRING | MF_BYPOSITION, uCmdID++, text2);
SetMenuItemBitmaps(hSubMenu, , MF_BYPOSITION, MenuIcon2, MenuIcon2);
InsertMenu(hSubMenu, , MF_STRING | MF_BYPOSITION, uCmdID++, text3);
SetMenuItemBitmaps(hSubMenu, , MF_BYPOSITION, MenuIcon3, MenuIcon3);
InsertMenu(hSubMenu, , MF_STRING | MF_BYPOSITION, uCmdID++, text4);
SetMenuItemBitmaps(hSubMenu, , MF_BYPOSITION, MenuIcon4, MenuIcon4);
// InsertMenu(hSubMenu, 3, MF_SEPARATOR | MF_BYPOSITION, 0, NULL);//插入分隔线
}
InsertMenu(hmenu, indexMenu, MF_STRING | MF_POPUP | MF_BYPOSITION, (UINT_PTR)hSubMenu, text1);
SetMenuItemBitmaps(hmenu, indexMenu, MF_BYPOSITION, MenuIcon1, MenuIcon1);
indexMenu++;
InsertMenu(hmenu, indexMenu, MF_SEPARATOR | MF_BYPOSITION, , NULL);
indexMenu++; // inform the explorer how many menu item we have added
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, uCmdID - idCmdFirst);
} HRESULT CMyContextMenu::InvokeCommand(
_In_ CMINVOKECOMMANDINFO *pici) {
if ( != HIWORD(pici->lpVerb))
return E_INVALIDARG;
// get index of added menu item
switch (LOWORD(pici->lpVerb))
{
case :
{
// 执行新增菜单项2触发的操作
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
TCHAR szCommandLine[] = TEXT("notepad");
BOOL bCreateRet = CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, , NULL, NULL, &si, &pi); break;
}
case :
{
// 执行新增菜单项3触发的操作
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
TCHAR szCommandLine[] = TEXT("write");
BOOL bCreateRet = CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, , NULL, NULL, &si, &pi); break;
}
case :
{
// 执行新增菜单项4触发的操作
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
TCHAR szCommandLine[] = TEXT("cmd");
BOOL bCreateRet = CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, , NULL, NULL, &si, &pi); break;
}
default:
{
return E_INVALIDARG;
break;
}
}
return S_OK;
} HRESULT CMyContextMenu::GetCommandString(
_In_ UINT_PTR idCmd,
_In_ UINT uType,
_Reserved_ UINT *pReserved,
_Out_writes_bytes_((uType & GCS_UNICODE) ? (cchMax * sizeof(wchar_t)) : cchMax) _When_(!(uType & (GCS_VALIDATEA | GCS_VALIDATEW)), _Null_terminated_) CHAR *pszName,
_In_ UINT cchMax) {
USES_CONVERSION;
LPCTSTR szPrompt;
// copy help info to cache when explorer ask
if (uType & GCS_HELPTEXT)
{
switch (idCmd)
{
case :
szPrompt = _T("新增菜单项2说明文字");
break;
case :
szPrompt = _T("新增菜单项3说明文字");
break;
case :
szPrompt = _T("新增菜单项4说明文字");
break;
default:
//ATLASSERT(0); // should never get here
return E_INVALIDARG;
break;
}
if (uType & GCS_UNICODE)
{
lstrcpynW((LPWSTR)pszName, T2CW(szPrompt), cchMax);
}
else
{
lstrcpynA(pszName, T2CA(szPrompt), cchMax);
}
return S_OK;
}
return E_INVALIDARG;
}
7、在 .rgs文件中添加注册表信息,确保各GUID与 .idl文件中的一致。
HKCR
{
NoRemove CLSID
{
ForceRemove {9C50C98F-E1FF-41CF-BD54-E9A3BBDDDEF8} = s 'MyContextMenu Class'
{
ForceRemove Programmable
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Apartment'
}
TypeLib = s '{EB1C2F43-315D-4D8F-9A2A-70E67BE888E2}'
Version = s '1.0'
}
} NoRemove *
{
NoRemove ShellEx
{
NoRemove ContextMenuHandlers
{
ForceRemove MyContextMenu = s '{9C50C98F-E1FF-41CF-BD54-E9A3BBDDDEF8}'
}
}
}
}
8、Build Project 后打开cmd.exe,通过regsvr32命令注册或解注册生成的 .dll文件。
10、查看效果如下图所示。
——————————————————
本文为本人原创,如需转载请注明出处。
http://www.cnblogs.com/lantingji/p/5857380.html
Creating Context Menu / 创建上下文菜单项 / VC++, Windows, DLL, ATL, COM的更多相关文章
- Creating Contextual Menus创建上下文菜单
A contextual menu offers actions that affect a specific item or context frame in the UI. You can pro ...
- Creating Icon Overlay Handlers / 创建图标标记 Handlers (续) / VC++, Windows, DLL, ATL, COM
创建图标标记 Handlers (续) 1.新建一个ATL Project. 2.建议将 Project Property 中 Linker – General - “Register Output” ...
- Creating Icon Overlay Handlers / 创建图标标记 Handlers (翻译自MSDN) / VC++, Windows, DLL, ATL, COM
创建图标标记 Handlers Creating Icon Overlay Handlers 图标标记是放在代表着某个 Shell 对象的图标之左下角的小图像.它们通常被加在一个对象的图标的身上来提供 ...
- Android Dialog 创建上下文菜单
Android Dialog中的listview创建上下文菜单 listView.setOnCreateContextMenuListener(new OnCreateContextMenuListe ...
- ContextMenu菜单创建 上下文菜单的基本认识q
MainActivity.class public class MainActivity extends AppCompatActivity { @Override protected void on ...
- android 开发-(Contextual Menu)上下文菜单的实现
在android3.0以后,安卓设备不在提供物理的菜单按键,同时,android应用提供了另外的菜单实现机制,来替代之前的菜单创建方式.安卓设备中,平常可以使用长按住某个内容弹出菜单选项.这就是我们需 ...
- Android开发之Menu:OptionMenu(选项菜单)、ContextMenu(上下文菜单)、SubMenu(子菜单)
菜单的概念,现在已经很普及了.Windows系统.Mac.桌面版Linux.Java Swing等,都有可视化菜单.一.Android平台3种菜单 选项菜单(OptionMenu).上下文菜单(Co ...
- 安卓开发笔记——Menu菜单组件(选项菜单,上下文菜单,子菜单)
菜单是用户界面中最常见的元素之一,使用非常频繁,在Android中,菜单被分为如下三种,选项菜单(OptionsMenu).上下文菜单(ContextMenu)和子菜单(SubMenu). 菜单的实现 ...
- Android菜单详解(四)——使用上下文菜单ContextMenu
之前在<Android菜单详解(二)——创建并响应选项菜单>和<Android菜单详解(三)——SubMenu和IconMenu>中详细讲解了选项菜单,子菜单和图标菜单.今天接 ...
随机推荐
- luogu P1824 进击的奶牛
题目描述 Farmer John建造了一个有N(2<=N<=100,000)个隔间的牛棚,这些隔间分布在一条直线上,坐标是x1,...,xN (0<=xi<=1,000,000 ...
- 【bzoj1486】【[HNOI2009]梦幻布丁】启发式链表合并(详解)
(画师当然是武内崇啦) Description N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3 ...
- 【欧拉函数表】POJ2478-Farey Sequence
[题目大意] 求∑φ(i)(1<=i<=N). [思路] 欧拉函数具有如下的重要推论: 当b是素数时 性质①若b|a,有φ(ab)=φ(a)*b: 性质②若b不|a,有φ(ab)=φ(a) ...
- Problem D: 零起点学算法24——判断奇偶数
#include<stdio.h> int main() { int a; while(scanf("%d",&a)!=EOF) ==) printf(&quo ...
- hadoop map(分片)数量确定
之前学习hadoop的时候,一直希望可以调试hadoop源码,可是一直没找到有效的方法,今天在调试矩阵乘法的时候发现了调试的方法,所以在这里记录下来. 1)事情的起因是想在一个Job里设置map的数量 ...
- Swift中计算String的长度
extension String { var length: Int { return countElements(self) } // Swift 1.1 } extension ...
- 【POI】修改已存在的xls,新添一列后,再保存本文件+获取最大有效行号+获取单元格内容
使用POI版本: ① ② ③ ④ package com.poi.dealXlsx; import java.io.File; import java.io.FileInputStream; impo ...
- javascript模块化有什么意义?
以前,所有的javascript都写在一个文件里,方便只加载一个文件就可以了,但是代码越来越多,必须分成多个文件加载,类似: <script src="1.js">&l ...
- iOS:Objective-c的MD5/SHA1加密算法的实现
介绍: Objective-c实现MD5和SHA1算法相对还是比较简单的,可以直接调用系统的C/C++共享库来实现调用MD5即Message Digest Algorithm 5(信息-摘要算法 5) ...
- 本机搭建PHP环境全教程(图文)
为了更好的维护空间网站,研究和调试PHP程序,许多人需要在自己的计算机内搭建PHP环境.本文将介绍使用phpnow环境组件搭建的全过程.使用搜索工具,搜索phpnow<ignore_js_op& ...