ATL右键文件菜单
自己写的小程序中用到的,网上资料相对还是毕竟全的,这里再整理下。毕竟我也不是很了解ATL,里面估计还是有不少问题的,就当作参考吧。
1.创建ATL工程,这个没什么好讲的。

我对COM组件没什么研究,这边就没勾选COM。

2.Project >> Add New Item >> ATL >> ATL Simple Object


3.添加继承关系,需要继承自IShellExtInit和IContextMenu。
IShellExtInit接口用于Shell初始化Shell扩展对象的初始化工作。当用户需要定制Shell的快捷菜单或者属性页时,需实现IContextMenu或IShellPropSheetExt接口的同时,还需实现IShellExtInit接口.Shell会自动调用该接口的Initialize方法来初始化Shell扩展对象。
class ATL_NO_VTABLE CAtlMenuImpl :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CAtlMenuImpl, &CLSID_AtlMenuImpl>,
public IDispatchImpl<IAtlMenuImpl, &IID_IAtlMenuImpl, &LIBID_AtlMenuLib, /*wMajor =*/ , /*wMinor =*/ >,
public IShellExtInit, //继承IShellExtInit
public IContextMenu //继承IContextMenu
添加到映射表:
BEGIN_COM_MAP(CAtlMenuImpl)
COM_INTERFACE_ENTRY(IShellExtInit)
COM_INTERFACE_ENTRY(IContextMenu)
END_COM_MAP()
添加几个变量:
std::vector<std::wstring> m_fileNameVector; //文件列表容器
UINT m_uiFileNum;
HBITMAP m_hRegBmp; //图标
实现继承的虚函数:
//IShellExtInit
STDMETHODIMP Initialize(LPCITEMIDLIST, LPDATAOBJECT, HKEY); //初始化Shell扩展对象 //IContextMenu
STDMETHODIMP GetCommandString(UINT_PTR, UINT, UINT*, LPSTR, UINT); //获取有关快捷菜单命令的信息,包括帮助字符串以及命令的语言无关或规范名称
STDMETHODIMP InvokeCommand(LPCMINVOKECOMMANDINFO); //执行与快捷菜单项关联的命令
STDMETHODIMP QueryContextMenu(HMENU, UINT, UINT, UINT, UINT); //将命令添加到快捷菜单
4.具体的实现
CAtlMenuImpl::CAtlMenuImpl()
{
//m_hRegBmp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDC_MENU));
} STDMETHODIMP CAtlMenuImpl::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT pDataObj, HKEY hProgID)
{
FORMATETC fmt = { CF_HDROP, NULL, DVASPECT_CONTENT, -, TYMED_HGLOBAL };
STGMEDIUM stg = { TYMED_HGLOBAL };
HDROP hDrop; // Look for CF_HDROP data in the data object.
if (FAILED(pDataObj->GetData(&fmt, &stg)))
{
// Nope! Return an "invalid argument" error back to Explorer.
return E_INVALIDARG;
} // Get a pointer to the actual data.
hDrop = (HDROP)GlobalLock(stg.hGlobal); // Make sure it worked.
if (NULL == hDrop)
return E_INVALIDARG; // Sanity check - make sure there is at least one filename.
m_uiFileNum = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, );
HRESULT hr = S_OK; WCHAR wcFileName[MAX_PATH];
for (UINT i = ; i < m_uiFileNum; i++)
{
memset(wcFileName, , MAX_PATH);
if ( == DragQueryFileW(hDrop, i, wcFileName, MAX_PATH))
{
hr = E_INVALIDARG;
break;
} m_fileNameVector.push_back(wstring(wcFileName));
} GlobalUnlock(stg.hGlobal);
ReleaseStgMedium(&stg); return hr;
} STDMETHODIMP CAtlMenuImpl::GetCommandString(UINT_PTR idCmd, UINT uFlags, UINT* pwReserved, LPSTR pszName, UINT cchMax)
{
USES_CONVERSION; // Check idCmd, it must be 0 since we have only one menu item.
if ( != idCmd)
return E_INVALIDARG; // If Explorer is asking for a help string, copy our string into the
// supplied buffer.
if (uFlags & GCS_HELPTEXT)
{
LPCTSTR szText = _T("This is the simple shell extension's help"); if (uFlags & GCS_UNICODE)
{
// We need to cast pszName to a Unicode string, and then use the
// Unicode string copy API.
lstrcpynW((LPWSTR)pszName, T2CW(szText), cchMax);
}
else
{
// Use the ANSI string copy API to return the help string.
lstrcpynA(pszName, T2CA(szText), cchMax);
} return S_OK;
} return E_INVALIDARG;
} STDMETHODIMP CAtlMenuImpl::InvokeCommand(LPCMINVOKECOMMANDINFO pCmdInfo)
{
// If lpVerb really points to a string, ignore this function call and bail out.
if ( != HIWORD(pCmdInfo->lpVerb))
return E_INVALIDARG; wchar_t szCurrentDir[MAX_PATH] = { };
wstring exePath = L"";
wstring paramStr = L"";
wstring parms = L"\""; GetModuleFileNameW(g_hInstance, szCurrentDir, MAX_PATH);
exePath = szCurrentDir;
exePath = exePath.substr(, exePath.find_last_of(L'\\'));
exePath += L"\\DF.exe"; for (UINT i = ; i < m_uiFileNum; i++)
{
parms += m_fileNameVector.at(i).c_str();
if (i != m_uiFileNum - )
{
parms += L"*";
}
}
parms += L'\"'; paramStr += parms; g_log.LogInfo(L"[InvokeCommand]exePath:%s, param:%s", exePath.c_str(), paramStr.c_str()); ShellExecuteW(pCmdInfo->hwnd, L"open", exePath.c_str(), paramStr.c_str(), NULL, SW_HIDE);
return S_OK; } STDMETHODIMP CAtlMenuImpl::QueryContextMenu(HMENU hmenu, UINT uMenuIndex, UINT uidFirstCmd, UINT uidLastCmd, UINT uFlags)
{
UINT uCmdID = uidFirstCmd;
UINT uMenuCount = ;
// If the flags include CMF_DEFAULTONLY then we shouldn't do anything.
if (uFlags & CMF_DEFAULTONLY)
return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, ); InsertMenu(hmenu, uMenuIndex++, MF_SEPARATOR | MF_BYPOSITION, , NULL);
uMenuCount++; HMENU hNextDocSecurity = CreateMenu();
InsertMenuW(hmenu, uMenuIndex, MF_POPUP | MF_BYPOSITION, (UINT_PTR)uCmdID, _T("呵呵呵呵"));
SetMenuItemBitmaps(hmenu, , MF_BYPOSITION, NULL, NULL); uMenuIndex++;
uMenuCount++; return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, uMenuCount);
}
5.代码注册
打开idl文件,记录下最下面的uuid

fc71b946-3310-4bb2-9f54-ac8a98a02f22
在AtlMenu.cpp中DllRegisterServer和DllUnregisterServer增加对应的注册表信息
// DllRegisterServer - Adds entries to the system registry.
_Use_decl_annotations_
STDAPI DllRegisterServer(void)
{
// registers object, typelib and all interfaces in typelib
if ( == (GetVersion() & 0x80000000UL))
{
g_log.LogInfo(L"[DllRegisterServer] start"); //写相应的注册表键值
CRegKey reg;
LONG lRet = reg.Open(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"), KEY_SET_VALUE); if (ERROR_SUCCESS != lRet)
{
g_log.LogError(L"[DllRegisterServer] Open HKEY_LOCAL_MACHINE failed:%d", GetLastError());
return E_ACCESSDENIED;
} lRet = reg.SetStringValue(_T("AtlMenu"), _T("{fc71b946-3310-4bb2-9f54-ac8a98a02f22}")); if (ERROR_SUCCESS != lRet)
{
g_log.LogError(L"[DllRegisterServer] SetStringValue failed:%d", GetLastError());
return E_ACCESSDENIED;
} lRet = reg.Create(HKEY_CLASSES_ROOT, _T("*\\shellex\\ContextMenuHandlers\\AtlMenu"));
if (ERROR_SUCCESS != lRet)
{
g_log.LogError(L"[DllRegisterServer] Creating shellex\\ContextMenuHandlers register failed:%d", GetLastError());
return E_ACCESSDENIED;
} lRet = reg.SetStringValue(NULL, _T("{fc71b946-3310-4bb2-9f54-ac8a98a02f22}")); if (ERROR_SUCCESS != lRet)
{
g_log.LogError(L"[DllRegisterServer] Set \\shellex\\ContextMenuHandlers register failed:%d", GetLastError());
return E_ACCESSDENIED;
} //写文件夹注册表项
lRet = reg.Create(HKEY_CLASSES_ROOT, _T("Folder\\shellex\\ContextMenuHandlers\\AtlMenu")); if (ERROR_SUCCESS != lRet)
{
g_log.LogError(L"[DllRegisterServer] Create Folder reg failed:%d", GetLastError());
return E_ACCESSDENIED;
} lRet = reg.SetStringValue(_T("AtlMenu"), _T("{fc71b946-3310-4bb2-9f54-ac8a98a02f22}")); if (ERROR_SUCCESS != lRet)
{
g_log.LogError(L"[DllRegisterServer] SetStringValue ( Folder AtlMenu ) failed:%d", GetLastError());
return E_ACCESSDENIED;
} lRet = reg.Create(HKEY_CLASSES_ROOT, _T("Directory\\shellex\\ContextMenuHandlers\\AtlMenu"));
if (ERROR_SUCCESS != lRet)
{
g_log.LogError(L"[DllRegisterServer] Creating HKEY_CLASSES_ROOT\\Directory\\shellex register failed:%d", GetLastError());
return E_ACCESSDENIED;
} lRet = reg.SetStringValue(NULL, _T("{fc71b946-3310-4bb2-9f54-ac8a98a02f22}")); if (ERROR_SUCCESS != lRet)
{
g_log.LogError(L"[DllRegisterServer] Set HKEY_CLASSES_ROOT\\diretory\\shell register failed:%d", GetLastError());
return E_ACCESSDENIED;
} g_log.LogInfo(L"[DllRegisterServer] finished");
} // registers object, typelib and all interfaces in typelib
HRESULT hr = _AtlModule.DllRegisterServer();
return hr;
} // DllUnregisterServer - Removes entries from the system registry.
_Use_decl_annotations_
STDAPI DllUnregisterServer(void)
{
//删除相关注册表键、值
if ( == (GetVersion() & 0x80000000UL))
{
CRegKey reg;
LONG lRet; lRet = reg.Open(HKEY_LOCAL_MACHINE, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved"), KEY_SET_VALUE);
if (ERROR_SUCCESS == lRet)
{
lRet = reg.DeleteValue(_T("AtlMenu"));
}
lRet = RegDeleteKeyW(HKEY_CLASSES_ROOT, L"*\\shellex\\ContextMenuHandlers\\AtlMenu");
lRet = RegDeleteKeyW(HKEY_CLASSES_ROOT, L"Folder\\shellex\\ContextMenuHandlers\\AtlMenu");
lRet = RegDeleteKeyW(HKEY_CLASSES_ROOT, L"Directory\\shellex\\ContextMenuHandlers\\AtlMenu");
} HRESULT hr = _AtlModule.DllUnregisterServer();
return hr;
}
6.管理员启动cmd运行regsvr32注册dll就可以看到具体的效果了

ATL右键文件菜单的更多相关文章
- win8.1右键新建菜单添加新建php文件
最近在学习php没使用IDE,一直使用编辑器,但每次新建文件都要手动该扩展名比较麻烦.于是想着能不能在右键新建菜单直接新建php文件.于是开始百度... 步骤一:win+R打开运行(管理员身份运行) ...
- Linux下nautilus的右键快捷菜单项设置
某一天我的Linux更新完后, 我照常在文件夹下点击右键想打开终端, 却发现右键快捷菜单没有Open in terminal的菜单项了. 在网上查找了一下, 结合自己系统的情况发现了解决办法. 由于我 ...
- 【MyEcplise】设置右键快捷菜单的方法
在我们右键新建项目或文件时,有许多的选项我们几乎是不用的,那就没有必要放在右键的快捷菜单中:而有些选项是我们经常会用的,但是右键快捷菜单有没有,我们总是需要选择其它去到弹出的对话框中取选取.这些操作很 ...
- 16. Ext.ux.TabCloseMenu插件的使用(TabPanel右键关闭菜单) 示例
转自:https://crabdave.iteye.com/blog/327978 Ext.ux.TabCloseMenu插件的使用(TabPanel右键关闭菜单) 示例 效果: 创建调用的HTML: ...
- WPF模拟Office2010文件菜单的TabControl模板
原文:WPF模拟Office2010文件菜单的TabControl模板 这是Office2010中的文件菜单点开后的效果.本文我将以强大的WPF(www.itstrike.cn)来实现类似的效果.希望 ...
- windows7_删除”右键-新建“菜单中的多余项
这边文章比较好用:分享下 https://blog.csdn.net/ddgweb/article/details/17993251 在使用windows7的过程中,由于安装了较多的软件,在桌面或者资 ...
- 添加找回鼠标右键新建菜单里的新建office2003/2007/2010文档的简洁方法
鼠标右键新建菜单里的新建office文档丢失了怎么办?我们可以通过一些优化设置软件如优化大师来定制,但更简单的方法是只需要导入相应的注册表设置就行了. 下面即在鼠标右键新建菜单里添加新建office2 ...
- paip.网页右键复制菜单限制解除解决方案
paip.网页右键复制菜单限制解除解决方案 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.net ...
- Windows上右键git菜单出来的原因
Windows上右键git菜单出来的原因 Git下载地址https://code.google.com/p/msysgit/downloads/list?q=full+installer+offici ...
随机推荐
- python—day9 函数的定义、操作使用方法、函数的分类、函数的嵌套调用
一.函数的定义 函数的四个组成部分: 函数名. 函数体. 函数返回值. 函数参数 1.概念:重复利用的工具,可以完成特定功能的代码块,函数是存放代码块的容器 2.定义: def:声明函数的关键词 函数 ...
- Zabbix Server端配置文件说明
zabbix作为运维邻域不可缺少的一员,它的各种文档可是数不胜数啊,但是关于配置文件的解释与说明就有点少.这里列出zabbix配置文件篇之zabbix_server. Zabbix Server端配置 ...
- jni c++
java与c/c++之间的数据交互 JNI 上述两篇文章对jni的讲解比较详细,各有利弊,就文章1来说,开门见山,直接阐述了java和C/C++的交互方式:文章2是一篇百度文库 ...
- Unity 点乘&叉乘 应用实例
一 前言 1.概述 主要概述了点乘,叉乘的实用例子,没有讲述什么原理性的,偏向应用层.点乘叉乘数学原理性的东西比较“难记”,网上很多.实用举例,网上算是比较少吧.故,来总结一番. 2.可以解决的问题 ...
- webpack 2 系列
webpack 2 系列 webpack 是一个强大的工具,学会通过工具来解决开发效率问题,是每一个 工程师都必备的技能之一. 那么我们来从零开始搭建一个 基于webpack 2 到 开发架子,来提升 ...
- Solr 03 - Solr的模式设计与优化 - 最详细的schema.xml模式文件解读
目录 1 关于schema.xml文件 2 解读schema.xml文件 2.1 field - 配置域 2.2 fieldType - 配置域类型 2.3 copyField - 配置复制域 2.4 ...
- Android Hybrid App自动化测试实战讲解(基于python)
1.Hybrid App自动化测试概要 什么是Hybrid App? Hybrid App(混合模式移动应用)是指介于web-app.native-app这两者之间的app,兼具“Native App ...
- Django的静态资源
如果你的静态资源是某个APP专属,那么就在这个APP目录下建立一个static目录,就像上图report这个APP中的static目录.当浏览这个APP的网页时它会从这里去找资源,当然,它首先会从共用 ...
- 设计模式总结篇系列:适配器模式(Adapter)
网上看到不少关于适配器模式的讲解,其中对于适配器模式解释的过于专业,一时不是特别理解适配器模式到底是用来干嘛的,具体的适用场景在哪,其最精髓的地方到底在哪. 本文结合自己的理解,阐述下对适配器模式的看 ...
- RDIFramework.NET ━ .NET快速信息化系统开发框架 V3.2->Web版本新增新的角色授权管理界面效率更高、更规范
角色授权管理模块主要是对角色的相应权限进行集中设置.在角色权限管理模块中,管理员可以添加或移除指定角色所包含的用户.可以分配或授予指定角色的模块(菜单)的访问权限.可以收回或分配指定角色的操作(功能) ...