这似乎是一个常见的问题,但经过一些搜索,我真的找不到答案。这里有一篇关于这方面的文章:
http://www.codeproject.com/KB/shell/shellextguide1.aspx
但它是为一个非常旧的Visual Studio版本设计的。我使用的是VS2008,所以指令和接口似乎与我看到的不匹配。
我想用C++创建一个简单的shell扩展,为扩展名为.GZ的文件创建一个上下文菜单。当右键单击这些文件时,我应该能够单击上下文菜单项,并在代码中有一个回调来对该文件进行某种操作。
其他上下文菜单项会做一些事情,比如生成无模块对话框,以便在执行某些操作之前接受用户输入。
据我所见,ATL是用来做这件事的,但我从未使用过ATL,所以所有的对象类型和接口都让我很困惑。如果我有合适的教程或文档可以阅读,那也不会那么糟糕。
有人能帮我吗?难道没有一种不是10年前的教程吗?
我不能确切地告诉您如何编写shell扩展,但我将提供一些技巧。与更简单的"仅注册表"方法相比,编写Shell扩展提供了一些显著的优势:
- 使用Shell Extension,可以动态创建与选定文件更相关的上下文菜单项(或子菜单)。例如,如果您正在为zip文件编写Shell Extension,则可以在上下文菜单中创建一个子菜单,显示zip的全部内容
- 您可以同时处理多个文件,这不仅对性能更有利,而且可以根据整个选择而不仅仅是针对每个文件来确定要做什么
Shell Extensions的一些缺点是:
-
大大增加了复杂性。准备在这方面花费大量的精力来让它发挥作用。在你的电脑旁边安装一台家用意式浓缩咖啡机和/或雇个人为你煮咖啡。
-
大大增加了调试难度。咖啡也是如此。
编写Shell扩展很困难,因为它们很难调试。
-
Shell扩展由
explorer.exe
进程加载,如果没有特定的Explorer配置,则需要强制退出explorer.exe
进程,以便安装新版本的Shell扩展。有一种方法可以让Explorer卸载它不再使用的DLL,但你应该只在开发机器上这样做,而不是在部署目标上:-
在RegEdit中,浏览到以下键:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer
-
添加一个名为"AlwaysUnloadDLL"的新DWORD键,并将其值设置为1。
-
重新启动资源管理器。
这在大多数情况下都有效,但有时可能仍然需要关闭Explorer,因为Shell扩展程序没有卸载。
-
-
请记住,您的Shell Extension可能会被其他应用程序加载,例如,如果您右键单击具有应用程序"打开文件"对话框的文件,则您的Shell Extensions将加载到该应用程序中,而不是Explorer中。
-
如果您的Shell Extension导致运行时错误,通常情况下,结果只是您的上下文菜单项没有显示,很少会告诉您Shell Extension加载失败或导致运行时出错。
-
配置可能很困难,即使安装了,注册表数据也需要在多个位置创建,并且根据上下文菜单的显示位置,不同版本的Windows在注册表中的位置可能不同。
您需要做的事情:
- Visual Studio提供了一些创建Shell扩展的快捷方式,但基本上您需要创建一个COM DLL。上下文菜单项的Shell扩展必须同时实现
IContextMenu
接口和IShellExtInit
接口 - 在
IShellExtInit::Initialize()
方法中,可以从IDataObject
参数中获取选定的文件。从内存中,数据是"Drag-n-Drop"格式的,因此您需要从IDataObject
中获取HDROP
句柄,并从中查询文件(这是从内存中获取的,实际上可能与我在这里描述的不同,因此请谨慎操作) - 一旦您的DLL准备好"安装",您必须将其复制到某个位置,然后运行
regsvr32
以确保它已注册 - 按照本指南了解将注册表项放在哪里
- 64位Windows可能存在问题,如果您构建32位DLL,它可能无法在64位资源管理器中加载…因此,如果您在64位Windows中遇到问题,请记住这一点
- 你的DLL实际上会有两个GUID与之关联。我记不清它是如何工作的,但一个GUID指的是DLL本身,另一个指的是实际的Shell扩展。在注册表中创建需要GUID的项时,请确保使用实际Shell扩展的GUID
综合考虑…(太长了,读不下去了)
权衡Shell扩展是否值得。如果你想根据所选文件动态创建菜单项,那么Shell扩展可能是唯一的方法。如果您想同时处理所有文件,那么您可能还需要一个Shell扩展插件。
上下文菜单方法的替代方法可以是在用户的桌面上设置一个drag-n-drop目标或其他什么。探索让用户将文件提交到应用程序的其他方法,因为Shell扩展的工作量往往远远超过它的价值。我发现这是一条艰难的道路,我想其他人也一样。