创建上下文菜单项

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的更多相关文章

  1. Creating Contextual Menus创建上下文菜单

    A contextual menu offers actions that affect a specific item or context frame in the UI. You can pro ...

  2. Creating Icon Overlay Handlers / 创建图标标记 Handlers (续) / VC++, Windows, DLL, ATL, COM

    创建图标标记 Handlers (续) 1.新建一个ATL Project. 2.建议将 Project Property 中 Linker – General - “Register Output” ...

  3. Creating Icon Overlay Handlers / 创建图标标记 Handlers (翻译自MSDN) / VC++, Windows, DLL, ATL, COM

    创建图标标记 Handlers Creating Icon Overlay Handlers 图标标记是放在代表着某个 Shell 对象的图标之左下角的小图像.它们通常被加在一个对象的图标的身上来提供 ...

  4. Android Dialog 创建上下文菜单

    Android Dialog中的listview创建上下文菜单 listView.setOnCreateContextMenuListener(new OnCreateContextMenuListe ...

  5. ContextMenu菜单创建 上下文菜单的基本认识q

    MainActivity.class public class MainActivity extends AppCompatActivity { @Override protected void on ...

  6. android 开发-(Contextual Menu)上下文菜单的实现

    在android3.0以后,安卓设备不在提供物理的菜单按键,同时,android应用提供了另外的菜单实现机制,来替代之前的菜单创建方式.安卓设备中,平常可以使用长按住某个内容弹出菜单选项.这就是我们需 ...

  7. Android开发之Menu:OptionMenu(选项菜单)、ContextMenu(上下文菜单)、SubMenu(子菜单)

    菜单的概念,现在已经很普及了.Windows系统.Mac.桌面版Linux.Java Swing等,都有可视化菜单.一.Android平台3种菜单  选项菜单(OptionMenu).上下文菜单(Co ...

  8. 安卓开发笔记——Menu菜单组件(选项菜单,上下文菜单,子菜单)

    菜单是用户界面中最常见的元素之一,使用非常频繁,在Android中,菜单被分为如下三种,选项菜单(OptionsMenu).上下文菜单(ContextMenu)和子菜单(SubMenu). 菜单的实现 ...

  9. Android菜单详解(四)——使用上下文菜单ContextMenu

    之前在<Android菜单详解(二)——创建并响应选项菜单>和<Android菜单详解(三)——SubMenu和IconMenu>中详细讲解了选项菜单,子菜单和图标菜单.今天接 ...

随机推荐

  1. 【set】bzoj3715 [PA2014]Lustra

    对每种属性开一个set,只要某个厂家符合该属性的最值,就加进set,最后判断是否有某个厂家在4个set里都存在即可. #include<cstdio> #include<set> ...

  2. 【矩阵乘法+快速乘】BZOJ2875-[NOI2012]随机数生成器

    [题目大意] 已知Xn+1=(aXn+c) mod m,求Xn mod g. [思路] get到了longlong乘法的正确方法,快速乘.什么是快速乘呢? 简单来讲,快速幂就是模拟了二进制的竖式乘法. ...

  3. 10.2(java学习笔记)JDBC事务简述

    一.事务 事务是指作为一系列操作组成的一个整体,该整体只有两种状态,要么全部执行,要么全部不执行. 当组成这个事务的所有语句都执行成功则该事务执行,只要有一条语句执行失败则该事务不执行. 假设这里有一 ...

  4. 10.1(java学习笔记)JDBC基本操作(连接,执行SQL语句,获取结果集)

    一.JDBC JDBC的全称是java database connection java数据库连接. 在java中需要对数据库进行一系列的操作,这时就需要使用JDBC. sun公司制定了关于数据库操作 ...

  5. 统计正数和负数的个数,然后计算这些数的平均值 Exercise05_01

    import java.util.Scanner; /** * @author 冰樱梦 * * */ public class Exercise05_01{ public static void ma ...

  6. 通信编码解码 c11 实现 [ lua 专用版]

    #include <istream> #include <ostream> #include <iostream> #include <strstream&g ...

  7. tomcat访问(access)日志配置、记录Post请求参数(转)

    一.配置与说明 tomcat访问日志格式配置,在config/server.xml里Host标签下加上 <Valve className="org.apache.catalina.va ...

  8. Metesploit使用随笔

    平时在工作中真正用到metesploit机会不多,偶尔也会用来做漏洞验证,但是每次使用的时候都需要花点时间回忆一下具体是怎么用的,因此索性记下来方便自己,以使用Nessus扫描YS的某个硬件设备发现的 ...

  9. Telnet窗口尺寸选项

    转:http://www.cnpaf.net/Class/Telnet/200408/6.html 1.命令名称和选项代码 名称=NAWS(NegotiateAboutWindowSize)协商窗口的 ...

  10. java实现发送邮件功能

    项目中实现发送邮件功能,先书写一个小Demo,记录如下: POM.XML中导入依赖 <!-- start java 提供的支持邮件发送相关业务的类 --> <dependency&g ...