调用Windows资源管理器外壳扩展

4
有没有一种通过编程的方式调用作为shell扩展的DLL的方法?我们使用一个在Windows资源管理器上注册了一个shell扩展的软件,我需要调用其中一个可用于其上下文菜单中的项目。我没有想要调用的软件源代码。
编辑
只有当我在Windows资源管理器上选择PDF文件时,这个上下文菜单才会出现。所以我需要传递一个dll文件来调用它。
编辑
注册表信息:
[HKEY_CLASSES_ROOT\CLSID{2DC8E5F2-C89C-4730-82C9-19120DEE5B0A}] @="PDFTransformer3.PDFTContextMenu.1"
[HKEY_CLASSES_ROOT\CLSID{2DC8E5F2-C89C-4730-82C9-19120DEE5B0A}\InprocServer32] @="C:\Program Files\ABBYY PDF Transformer 3.0\PDFTContextMenu.dll" "ThreadingModel"="Apartment"
[HKEY_CLASSES_ROOT\CLSID{2DC8E5F2-C89C-4730-82C9-19120DEE5B0A}\ProgID] @="PDFTransformer3.PDFTContextMenu.1"
[HKEY_CLASSES_ROOT\CLSID{2DC8E5F2-C89C-4730-82C9-19120DEE5B0A}\Programmable]
[HKEY_CLASSES_ROOT\CLSID{2DC8E5F2-C89C-4730-82C9-19120DEE5B0A}\VersionIndependentProgID] @="PDFTransformer3.PDFTContextMenu"
编辑
是否可以使用我想要的动作(而不是默认值)调用ShellExecuteEx?如果可以,如何调用我想要的动作(它使用DLL)?
这是我想要为PDF文件调用的动作:

这个软件不是我自己的。这就是为什么我要在Stack Overflow上询问它。 - Rafael Colucci
1
除非你弄清楚它是哪种类型的 shell 扩展,否则你将得不到答案。有许多不同类型的 shell 扩展。 - David Heffernan
在网上查找CLSID值并从中解决问题。 - David Heffernan
查找 HKCR\.pdf 并查看 (Default) 的值,我们称之为 <FileTypeName>。然后查找 HKCR\<FileTypeName>,以此类推。 - David Heffernan
1
顺便加一,以弥补那些没有留下任何评论就点踩的人。 - yms
显示剩余9条评论
3个回答

11

DLL显然是一个上下文菜单扩展。如果你想像shell一样调用它,那么你需要托管这个DLL实现的IContextMenu接口。几年前,Raymond Chen写了一系列关于这个主题的广泛文章:

如何托管IContextMenu

  1. 初步尝试
  2. 显示上下文菜单
  3. 调用位置
  4. 关键上下文
  5. 处理菜单消息
  6. 显示菜单帮助
  7. 调用默认动词
  8. 优化默认命令
  9. 添加自定义命令
  10. 复合扩展 - 基础工作
  11. 复合扩展 - 组合

前两篇文章是最重要的。它们介绍了如何首先获取文件的IContextMenu接口,然后如何调用该菜单提供的一个或多个命令。基本上,获取IContextMenu接口,填充CMINVOKECOMMANDINFOEX结构,然后将其传递给接口的InvokeCommand方法。这些文章调用TrackPopupMenu来向用户显示菜单,然后使用选择项填充结构,但如果您已经确切地知道要运行哪个命令,那么可以跳过显示菜单。(不过可能仍需要创建菜单,因为IContextMenu对象可能希望首先调用QueryContextMenu。)


他为什么不能直接调用ShellExecuteEx函数? - David Heffernan
4
不清楚,@David。他问如何“调用DLL”,但我猜你通过经验知道按照问题所询问的方式回答可能会让我们陷入麻烦。即使他使用ShellExecuteEx,他仍然需要执行这个过程一次来查找可用的动词,因为它们不在注册表中。 - Rob Kennedy
没关系,如果有人能向我展示如何使用ShellExecuteEx调用上下文菜单,那就太好了。我正在研究您发布的链接,但是目前还没有任何进展。 - Rafael Colucci

6
你可以使用 IContextMenu 接口。从这里,你可以枚举接口返回的条目,然后使用 InvokeCommand 执行所需选项。

听起来不错,但我对C#还很陌生。你能给我提供一个示例或Delphi代码吗? - Rafael Colucci
2
请查看此问题:https://dev59.com/IG865IYBdhLWcg3whO7E,以及Craig Peterson的答案。 - RRUZ
@RRUZ https://dev59.com/IG865IYBdhLWcg3whO7E - Rafael Colucci
@Rafael,首先我在这个链接中没有发布任何代码,只是提供了一些建议。这些代码是Craig Peterson发布的。如果这些代码可以帮助你解决问题,那太好了。但是如果不符合你的期望,你可以在S.O上发布一个新的问题,并包含代码。同时指出哪部分对你来说“不起作用”。 - RRUZ
@RRUZ,抱歉。我指的是您发布链接中的源代码。 - Rafael Colucci

2

这是一个COM对象。你只需要创建它,并传递接口(具有足够的实现),它就可以工作了。

资源管理器(即您)将要求shell扩展程序向不同的HMENUs添加项目。然后资源管理器(即您)响应用户时会调用菜单项。

幸运的是,shell中的所有内容都是接口-所以你可以假装成任何你想要的东西。你只需要从另一边阅读SDK契约

记住Shell扩展程序不必在资源管理器中托管。许多扩展程序并没有。许多扩展程序托管在CommCtrl的"另存为"对话框中。


在您的情况下,甚至更简单

  • 创建COM对象
  • 查询其IShellExtInit接口,并调用.Initialize
  • 查询其IContextMenu接口
  • 调用IContextMenu.QueryContextMenu,允许其向HMENU添加项目
  • 调用IContextMenu.Invoke

再次阅读另一边的契约即可。


一些伪代码:

var
   ClassID: TGUID;
   unk: IUnknown;
   shellext: IShellExtInit;
   dataObject: IDataObject;
   hkeyProgID: HKEY;
   contextMenu: IContextMenu;
   commandInfo: CMINVOKECOMMANDINFO;
begin
   ClassID := ProgIDToClassID('PDFTransformer3.PDFTContextMenu'); 
   unk := CreateComObject(ClassID);

   shellExt := unk as IShellExtInit;

    {
       For shortcut menu extensions, 
          pdtobj identifies the selected file objects,
          hkeyProgID identifies the file type of the object with focus, and 
          pidlFolder is either NULL (for file objects) or specifies the folder 
             for which the shortcut menu is being requested 
             (for folder background shortcut menus).
   }
   shellExt.Initialize(
         nil, //pidlFolder, null for file objects
         dataObject, //IDataObject of the selected file
         hkeyProgID); //HKEY of the file type of the object with focus    

   contextMenu := unk as IContextMenu;
   contextMenu.QueryContextMenu(
         menuHandle, //HMENU, A handle to the shortcut menu. The handler should specify this handle when adding menu items.
         0, //integer, The zero-based position at which to insert the first new menu item.
         100, //The minimum value that the handler can specify for a menu item identifier.
         200, //The maximum value that the handler can specify for a menu item identifier.
         CMF_NORMAL); //optional flags

   contextMenu.InvokeCommand(commandInfo);

这就是我通过阅读文档和猜测要做什么所能达到的程度。现在我需要上厕所,回家玩Portal 2。


我想我没有足够的知识来做那件事。也许有人可以向我展示如何使用ShellExecuteEx来调用动词。但还是谢谢你的帮助。 - Rafael Colucci

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接