Dynamic Context Menus

Static context menus are limited because they are the same for every file object of a given type. Also, the number of files that can be processed through a static menu is limited by the program that is used to carry out the command. What if you need to process 20 files? What if you need different processing options based on the state of the file itself? There are also situations where you might need one context menu for a group of files and another for a single file. This is where dynamic context menus come into play.

A context menu handler is an ActiveX DLL that implements two interfaces: IShellExtInit and IContextMenu. A third interface, IDataObject, is required to implement IShellExtInit. It is not implemented by the object itself but exists as a method parameter in IShellExtInit. We’ll explore these interfaces in greater depth after we examine how the shell uses a context menu handler to assemble a context menu.

The process begins when one or more files is right-clicked in Explorer. When this occurs, the shell checks the shellex key under the application identifier key to see if a context menu handler has been defined for the selected file type. In the case of the .rad file, the shell would look under the following key:

HKEY_CLASSES_ROOT/
    radfile/
        shellex/
            ContextMenuHandlers/

If you select 15 files that are of all different types, there is still only one file with active focus: the last file selected in the group. It is this file for which the shell attempts to find an associated context menu handler.

If a context menu handler exists, the shell loads the handler and calls IShellExtInit::Initialize. One of the parameters of Initialize is a reference to IDataObject. The shell uses IDataObject to tell us how many files are selected and what their names happen to be. This gives us the opportunity (as the implementors of IShellExtInit) to save the filenames and the number of selected files for later use. This information can be stored in private member variables within the class. Later, when a command is actually selected from the context menu, the array of files can be referenced and processing decisions can be made.

Next, the shell calls IContextMenu::QueryContextMenu. This method is responsible for adding items to the context menu. The shell passes into the method a handle to the context menu, called an HMENU. An index representing a valid insertion point for the menu item is also passed in. Adding the menu item is simply a matter of calling the InsertMenu API .

You might want different menu items displayed based on whether one or multiple files have been selected. Since the number of files selected can be determined in IShellExtInit::Initialize, this becomes a trivial matter. You also have the ability to base the menu item on the file itself. In addition to the number of files selected, you would also already know the filenames in question. This means you could open the file, retrieve information, and base the menu item on actual data. Or you could examine some other attribute of the file (such as its creation date, its size, or its read-only status) and base the menu item on that information as well.

At this point, the shell displays the context menu with the additional menu items. Once the context menu is displayed, the shell attempts to call IContextMenu::GetCommandString whenever the mouse is moved over the new context menu item. This allows you to provide a help string that will be displayed in the status bar of Explorer when the context menu item is highlighted.

When the command is actually selected, the shell calls IContextMenu::InvokeCommand on the handler. The method allows you to determine which context menu item has been selected, and as a result your handler can carry out the appropriate actions.

Get VB Shell Programming now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.