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>中详细讲解了选项菜单,子菜单和图标菜单.今天接 ...
随机推荐
- 某考试 T1 lcm
把lcm写成 (a+n)*(b+n) / gcd(a+n,b+n). 因为gcd可以辗转相减,所以就成了gcd(abs(a-b),a+n),一个常量一个变量之间的gcd,我们可以直接把abs(a-b) ...
- 【数位dp】hdu2089 不要62
http://www.cnblogs.com/xiaohongmao/p/3473599.html #include<cstdio> using namespace std; int n, ...
- 【记忆化搜索】bzoj1055 [HAOI2008]玩具取名
f(l,r,c)表示sl...sr能否被合成字符c. #include<cstdio> #include<cstring> using namespace std; int m ...
- 【树链剖分】【线段树】bzoj3626 [LNOI2014]LCA
引用题解: http://blog.csdn.net/popoqqq/article/details/38823457 题目大意: 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深 ...
- Problem H: 零起点学算法28——参加程序设计竞赛
#include<stdio.h> int main() { int a,b; while(scanf("%d %d",&a,&b)!=EOF) ||b ...
- 阿里云乌班图16配置-PHP环境(包括mysql及apache安装)
1. 安装apache apt-get update apt-get install apache2 service apache2 restart 通过浏览器访问服务器的IP,如果出现Apac ...
- TQ2440学习笔记——Linux上I2C驱动的两种实现方法(1)
作者:彭东林 邮箱:pengdonglin137@163.com 内核版本:Linux-3.14 u-boot版本:U-Boot 2015.04 硬件:TQ2440 (NorFlash:2M Na ...
- Nginx实现图片防盗链(referer指令)
什么是图片盗链 每张图片在浏览器中都有对应的图片地址,在浏览器中输入这个地址是可以直接拿到图片. 图片盗链,就是盗用者在他的站上需要显示我们的图片,他没有把图片拿下来,放到他的服务器上, 而是直接 ...
- 深入理解JS函数作用域链与闭包问题
function fun(n,o) { console.log(o) return { fun:function(m){ return fun(m,n); } }; } ); a.fun(); a.f ...
- IDEA Maven 下载jar
转载地址:https://www.cnblogs.com/hongwz/p/5456578.html 本文主要介绍通过配置Maven来下载需要用的jar包. 比如我现在用到把字符串转成json对象,这 ...