C++ programming: How does Shell Context Menu Work ? - Part 2

by Mohamed Saood Khan

Explore the details of how a Shell Explorer Context Menu works and learn the role played by the registry database.

In part 1 we understood what a context menu was and how Visual studio helps to create one at the design time and runtime level on a windows form.
In this tutorial we are going touch base on some of the key aspects of Context Menu controlled and generated by the shell explorer with the help of the demo code included with this article.

You should have observed that the context menu items change wrt to the object or context on which a right click is performed. These activities are actually controlled by Windows Shell Explorer.

The Shell Explorer is also called the file manager that is shipped with every release of Windows Operating system. It provides a graphical user interface for managing files. The process that host the Shell Explorer is the explorer.exe

Here's a list of operations Shell Explorer is responsible for

  1. Render the graphics for the taskbar and the desktop

  2. Render the graphics for windows, folders, icons, file menu's, toolbars

  3. Render the graphics for the start menu

  4. Render the graphics to display the tree structure of your file system, which is also called the explorer

  5. It provides the search engine feature for your file system

  6. And most important and the topic of this article - the context menu

(Try this: On your computer kill the explorer.exe process. You would observe that the task bar disappears, the desktop shows no sign of any icons. Active windows on your desktop would still be visible, minimizing the same would make them disappear.

Note that following the above step will not crash or delete data from your computer. You can bring back your desktop by launching the Task Manager, goto File->New Task, and then type explorer.)

Understanding the Context Menu Interfaces

In order to add new items to the default context menu, you need to understand two important interface classes

  • IContextMenu
  • IShellExtInit

The other interface classes that are not very important but could be useful in your development are

  • IContextMenu2
  • IContextMenu3

Above interface classes have been defined in shlobj.h header file. You can find this header file in your installed Visual Studio directory.

IContextMenu interface
This interface defines 3 functions

 * Description: 
 *           The method adds a text item to the Context Pop-Menu.
 * Arguments:
 *           hmenu - handle to the context menu
 *           indexMenu - the index position at which context menu item gets inserted
 *           idCmdFirst - lowest value for new menu ID's
 *           idCmdLast - highest value for new menu ID's
 *           uFlags - parameter specifies the context of the invocation

QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) 

 * Description: 
 *           InvokeCommand is the core api that is used to 
 *           execute the required functionality on selecting a menu-item. 
 * Arguments:
 *           lpici - Pointer to the structure CMINVOKECOMMANDINFO. This structure contains 
 *           added information about the context menu.


 * Description: 
 *           Called to do one of three things: Get a help string, make sure the item exists, 
 *           and to get a language-independent string. The language-independent command name, 
 *           or verb, is a name that can be passed to IContextMenu::InvokeCommand method.
 *           The help text is a description of the command that Windows Explorer displays in 
 *           its status bar. It should be reasonably short.
 * Arguments:
 *           idCmd - Menu item identifier offset.
 *           uType - Flags specifying the information to return.
 *           pwReserved - Reserved parameter. Applications must specify NULL when calling this method and handlers 
 *           must ignore this parameter when called.
 *           pszName - The address of the buffer to receive the null-terminated string being retrieved.
 *           cchMax - Size of the buffer, in characters, to receive the null-terminated string. 

GetCommandString(UINT idCmd, UINT  uType, UINT *pwReserved, LPSTR pszName, UINT cchMax)

IShellExtInit Interface

This interface defines 1 function:

 * Description: 
 *           This method performs the necessary initializations eg property sheet extension, 
 *           shortcut menu extension, or drag-and-drop handler. The initialization is a critical step 
 *           needed to carry out execution of functions defined in the interface IContextMenu

 * Arguments:
 *           pidlFolder : Defines a pointer to ITEMIDLIST structure that uniquely identifies a folder. 
 *           For property sheet extensions, this parameter is NULL. For shortcut menu extensions, it is 
 *           the item identifier list for the folder that contains the item whose shortcut menu is being displayed. 
 *           For nondefault drag-and-drop menu extensions, this parameter specifies the target folder.
 *           lpdobj: Defines a pointer to an IDataObject interface object that can be used to retrieve the 
 *           information on the objects being acted upon.
 *           hkeyProgID : The registry key for the file object or folder type.

STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder, LPDATAOBJECT lpdobj, HKEY hkeyProgID);

IContextMenu2 and IContextMenu3 Interface

These interfaces defines 1 function each. The functions are more less the same.

 * Description: 
 *           The difference between these interfaces is that, IContextMenu2 interface processes the WM_INITMENUPOPUP, WM_MEASUREITEM and WM_DRAWITEM messages where as
 *           IContextMenu3 interface will process the WM_MENUCHAR Message (handle menus using keyboard). 
 * Arguments:
 *           uMsg - The message to be processed. In the case of some messages, such as WM_INITMENUPOPUP, 
 *           WM_DRAWITEM, WM_MENUCHAR, or WM_MEASUREITEM, the client object being called may provide owner-drawn 
 *           menu items.
 *           wParam - Stores additional message information. The value of this parameter depends on the value of 
 *           the uMsg parameter. 
 *           lParam - Stores additional message information. The value of this parameter depends on the value of 
 *           the uMsg parameter. 
 *           plResult - The address of an LRESULT value that the owner of the menu will return from the message. 
 *           This parameter can be NULL.

STDMETHOD(HandleMenuMsg)(UINT uMsg, WPARAM wParam, LPARAM lParam);    

STDMETHOD(HandleMenuMsg2)(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* plResult);

When windows processes one the above mentioned messages you can call the HandleMenuMsg or HandleMenuMsg2 methods to handle them appropriately. These interfaces add minimum support needed for bit mapped menus especially if you are programming for cascading pop up menus as shown below

How Does Context Menu Work?

A context menu works by using the Shell extensions. A shell extension is a COM DLL that can be placed in any folder. Windows shell looks for these dll's using the registry database.

There are no of ways a shell explorer recognizes events through customized modules for eg when a context menu is invoked or file is highlighted or file is drag and dropped to a different location, for each such events explorer looks for the modules registered in the registry database invokes the corresponding dlls and executes the required functions to process the events.

A Look at the Registry

Windows registry is a hierarchical database which contains the primary source of system information for all the applications installed and configuration settings in an OS.

Primarily the registry information is categorized based on 4 different parent keys also known as hives, they are

HKEY_CLASSES_ROOT(HKCR) - stores information about registered applications, such as file associations and OLE Object Class IDs,

HKEY_CURRENT_USER(HKCU) - stores configuration settings that are specific to the currently logged-in user

HKEY_LOCAL_MACHINE(HKLM) - stores settings that are specific to the local computer typically the software's installed

HKEY_CURRENT_CONFIG(HKCC) - contains information gathered at runtime

HKEY_USERS(HKU) - contains subkeys corresponding to the HKEY_CURRENT_USER keys for each user profile actively.

For our understanding we would primarily focus on the HKEY_CLASSES_ROOT (Note: HKEY stands for Handle to a registry key)

Let's take a real case to see what happens behind the scenes

  • We will examine the background process involved when a right click is initiated on a directory.

  • Before we begin, download the CopyPath.zip to your computer

  • Unzip the file and build the VC++ solution to generated the COM dll CopyPath.dll

  • Copy the dll to a different folder location, preferably some place where it would not be accidentally deleted

  • Register the dll by opening the Run command window and type regsvr32 "<DLL Path>" for eg regsvr32 "C:\example\CopyPath.dll"

  • Once the registrations process is complete, open the registry by typing regedit.exe in the Run Command window

  • Look for the following key HKEY_CLASSES_ROOT\Directory\shellex\ContextMenuHandlers

  • Shellex is the shell extension keys. You will notice that under ContextMenuHandlers key, there are many subkeys, one of which is "MyCopyPath". So basically what we are telling here is when a right click action is performed on a directoy invoke the shell extn - MyCopyPath

  • When you open this key, you will notice that the key has a CLSID (Class ID) value like {4F4EE291-8333-4317-A1FA-A78EDFC1019C}. This is called a registry GUID, which is 128 bit Hex key guaranteed to be unique over space and time. It basically acts a reference for the explorer to search for the shell extension module
  • Once the registration process is complete, right click on a directory/folder. When context menu pops up, the explorer loads the default or standard menu items like Cut, Copy, Paste and then looks for the shell extensions. It searches for the CLSID in the registry to read the path where the COM dll is placed.

  • On finding the dll, the explorer loads the shell extension module (in our case it should be CopyPath.dll) into its own address space and first invokes the IShellExtInit::Initialise()function followed by a call to IContextMenu:: QueryContextMenu() requesting the module for the context menu items.

  • Select the context menu "Copy Directory Path". When the user selects this item, the IContextMenu::GetCommand() is called to get the string to be displayed on the status bar. You should see something like this


  • Finally when the user clicks the context menu item, IContexMenu:: InvokeCommand() is called to take the necessary action for that item.

Summary of the Events called when a Context Menu Is Invoked


Registration and Un-registration Process of a COM DLL

The registration process of a dll is to archive the details of the dll into the registry database. The specified registry key holds information about the name of the shell extn and the class id.

Likewise the un-registration process of a dll is to remove the details of the dll from the registry.
The COM dll contains all the needed information for adding or removing the contents from the registry. During registration, regsvr32 executable calls the DllRegisterServer() function and DllUnregisterServer() during the un-registration. The implementation details of these functions can be viewed in CopyPath.cpp file enclosed in CopyPath.zip file

To register the dll, as mentioned at the beginning of this page call the regsvr32.exe and pass the dll path as an argument to the executable
for eg regsvr32 "C:\example\CopyPath.dll"

To un-register the dll, the process is similar to registration.
eg regsvr32 /u "C:\example\CopyPath.dll"

What Does CopyPath.zip Contain?

CopyPath.zip is a shell extension program built on COM technology written using VC++ 6. The program adds a menu item to the standard shell context menu. When compiled and registered, the context menu item copies the absolute path of the shell object to the clipboard. Depending on the object selected, the menu-item text changes to reflect if the user is copying the file path or directory path.

Note: If you no longer wish to use CopyPath.dll, Uninstalling the same might be slightly tricky. The reason is if you have registered and already loaded the dll by invoking the context menu, then even if you unregister, the explorer process still has a hook to the shell extension and would not allow you to delete. In such scenarios unregister the dll and kill the explorer.exe process. Re-load the explorer process and then delete the dll.

This article was originally published on Friday Aug 13th 2010
Mobile Site | Full Site