4
votes

Is there any way of calling a DLL that is a shell extension programmatically? We use a software that registers a shell extension on windows explorer, and I need to call one of the items available on its context menu. I do not have the software source code that I want to call.

EDIT

This context menu only appears when I select a PDF file on windows explorer. So i need to call it passing a dll file.

EDIT

Registry information:

[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"

EDIT

Is it possible to call ShellExecuteEx with the verb i want (not the default one)? If so, how do I call the verb I want (which uses the DLL)?

Thats the verb i wanna call for a PDF file:

enter image description here

3
What does the shell extension do? What type of extension is it?David Heffernan
It works in a pdf file. I guess it is a COM DLL, but i am not sure.Rafael Colucci
You need to know what sort of shell extension it is in order to know how to call it. If you don't know what type it is then how will you know which COM interfaces to ask for?David Heffernan
You won't get an answer until you work out what sort of shell extension it is. There are lots of different types of shell extension.David Heffernan
By the way, +1 to compensate for someone who down-voted without leaving any comment.yms

3 Answers

11
votes

The DLL is evidently a context-menu extension. If you want to call it the same way the shell does, then you want to host the IContextMenu interface that the DLL implements. Several years ago, Raymond Chen wrote an extensive series on this topic:

How to host an IContextMenu

  1. Initial foray
  2. Displaying the context menu
  3. Invocation location
  4. Key context
  5. Handling menu messages
  6. Displaying menu help
  7. Invoking the default verb
  8. Optimizing for the default command
  9. Adding custom commands
  10. Composite extensions - groundwork
  11. Composite extensions - composition

The first two articles are the most important. They introduce how to get the IContextMenu interface of a file in the first place, and then how to invoke one or more of the commands offered by that menu. Essentially, get the IContextMenu interface, fill a CMINVOKECOMMANDINFOEX structure, and then pass it to the interface's InvokeCommand method. The articles call TrackPopupMenu to display a menu to the user, and then use the selection to fill the structure, but if you already know exactly which command you want to run, then you can forgo displaying the menu. (You might still have to create the menu, though, since the IContextMenu object probably expects to have QueryContextMenu called on it first.)

6
votes

Rafael, you can use the IContextMenu Interface. from here you can enumerate the entries returned by the interface and then execute the option which you want using the InvokeCommand

2
votes

It's a COM object. You just need to create it, and pass it interfaces (with enough implementation behind it) it make it work.

Explorer (i.e. you) will ask the shell extension to add items to an different HMENUs. Then Explorer (i.e. you) invokes a menu item in response to the user.

Fortunately everything in the shell is an interface - so you can pretend to be whatever you want. You just need to read the SDK contract from the other side.

Remember: A shell extension doesn't have to be hosted in Explorer. Many aren't. A lot are hosted in the "Save As" dialog from CommCtrl.


In your case it's even simpler.

  • Create the COM Object
  • query for its IShellExtInit interface, and call .Initialize.
  • query for its IContextMenu interface
  • call IContextMenu.QueryContextMenu, allowing it to add items to an HMENU
  • call IContextMenu.Invoke

Again, a case of reading the contract from the other side.


Some pseudo-code:

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);

That's as far as i get from reading documentation and guessing what to do. Now i have to pee, and go home to play Portal 2