CustomContextMenu, ver. 2.0.0

[How To Use] [Properties] [Methods] [Stand-alone Methods]
[Hints] [Known Bugs] [Comments]

CustomContextMenu is intended to make it easy to add your own menu items to the shell context menu (the menu you get when you right-click a file or folder).

It is an abstract class which contains four methods you must override, in order to add your menu items and execute them.

How To Use

To add your own menu items to the shell context menu you must create a DLL file. This file is known as a context menu handler (or a shortcut menu extension).

Windows defines an interface, IContextMenu, which third-party developers can implement. Whenever Windows is about to show a shell context menu it looks in the Registry to see if there are any DLLs that have been registered as context menu handlers. If so, the registered handlers are then called. Windows provides them with the relevant information, like which files are currently selected, and the handlers are expected to provide (implement) the methods defined in IContextMenu.

Writing a context menu handler from scratch is tricky stuff, so I wrote CustomContextMenu in order to encapsulate the basic details and let you concentrate on the essentials. Here's how to use it:

CustomContextMenu comes with a couple of demos. Take a look at them, and you will probably quickly catch on. The CopyPath demo is the easiest one to understand.

I have provided *.inf files for the demos. They do more than simply registering the corresponding DLLs, they also allow you to uninstall them again through the Control Panel. Open one of the files, and at the bottom you'll find a number of constants you can substitute with your own. Make especially sure the GUID matches the GUID found in your handler, and remember the GUID must be unique for each handler (and everything else that is registered).

The handler can be registered for different file types (so it will only be called if the selected file is a *.txt file, for example). You can find these file types in the Registry under the HKEY_CLASSES_ROOT key. Here are some common types:

If you need to register your handler for a specific file type, look in the Registry under HKEY_CLASSES_ROOT. Say you want to register a handler for *.dpk files. The default value for the HKEY_CLASSES_ROOT\.dpk key (dot dpk) is "DelphiPackage". That means you must specify "DelphiPackage" as the file type when you register (or unregister) your handler. You can register the handler for multiple file types.

By convention context menu handlers should be installed in the folder ShellExt below the Windows System folder.

Properties

FileNames property FileNames: TStringList;
When the context menu handler is initially called, Windows tells it what files or folders are selected by the user. FileNames contains the fully qualified file names (complete path). It can contain names of both files and folders.
NOTE: You can change the items in FileNames without problems (eg. remove the file names that don't match certain criteria, or sort the list alphabetically).

FolderName property FolderName: String;
This property is the path of the folder containing the user-selected items.
Read-only
ExtendedMenu property ExtendedMenu: Boolean;
This flag is true when the user holds down the SHIFT key while right-clicking a file or folder.
Read-only
IdCmdFirstOffset property IdCmdFirstOffset: UINT;
This property stores the value of the IdCmdFirst parameter when the AddMenuItems method is called.
Read-only

Methods

AddMenuItems function AddMenuItems(Menu: HMENU; MenuIndex, IdCmdFirst, IdCmdLast: UINT): UINT; virtual; abstract;
This method is called when the context menu is about to display. At this point you add your menu items.
Parameters:
Menu is the context menu's handle.
MenuIndex is the current position in the context menu. You can insert your menu item(s) in another position if you like.
IdCmdFirst is the minimum possible ID your menu item(s) can have. Each menu item you insert must have a unique ID (as represented by TMenuItemInfo.wID). Without a proper ID your menu items will either fail to display, fail to execute, or even cause other menu items not to display. A good rule of thumb is to use IdCmdFirst as the first ID and then increment the ID for each additional menu item. This maximizes the potential number of menu items that can be added.
IdCmdLast is the maximum possible ID your menu item(s) can have. Typically there's a difference of about 100 between IdCmdFirst and IdCmdLast, and this number is shared between all menu items - so limit the number of menu items you insert, and use IdCmdFirst as a base for your IDs.
Return value:
Your implementation of AddMenuItems must return the highest ID used by your menu items, or 0 if no menu items were inserted.
GetHelpText function GetHelpText(IdCmdOffset: UINT): String; virtual; abstract;
This method is called when a menu item is highlighted. It must return a descriptive text. This text is displayed in the folder window's status bar.
Parameters:
IdCmdOffset is the ID of the highlighted menu item (which you specified in AddMenuItems) minus the original ID offset. In other words, if you inserted a menu item in AddMenuItems with an ID of IdCmdFirst, then IdCmdOffset will have a value of 0.
GetVerb function GetVerb(IdCmdOffset: UINT): String; virtual; abstract;
Like GetHelpText this method is called when a menu item is highlighted. A verb is a command that is registered for a particular file type. Common verbs are "open" and "print" (go to HKEY_CLASSES_ROOT\txtfile\shell in the Registry to see the verbs associated with *.txt files). It doesn't matter what you specify the verb to be, since verbs are only used by external programs that call the context menu's items. CustomContextMenu doesn't support external programs calling your custom menu items.
Parameters:
IdCmdOffset is the ID of the highlighted menu item (which you specified in AddMenuItems) minus the original ID offset.
ExecuteCommand procedure ExecuteCommand(IdCmdOffset: UINT); virtual; abstract;
This method is called when the menu item is selected (clicked). Use it to run your own code.
Parameters:
IdCmdOffset is the ID of the highlighted menu item (which you specified in AddMenuItems) minus the original ID offset.

Stand-alone Methods

Initialize procedure Initialize(ComClass: TComClass; ClassID: TGUID; ClassName: String);
You must call this method in the Initialization part of the unit that descends from TCustomContextMenu.
Parameters:
ComClass is the class descended from TCustomContextMenu.
ClassID is the GUID specific to your handler.
ClassName is a class name for your handler. I believe the naming convention says the name must not contain spaces, but the class name isn't really important unless you expect other applications to identify your handler.
RegisterHandler RegisterHandler(ClassID: TGUID; Path: String; Description: String);
Registers your context menu handler in the Registry. You don't have to register it programmatically; you can also do it through an *.inf file or some other install script. Using this method in your context menu handler doesn't make sense (an unregistered handler can't register itself) - use it in an external application instead.
Parameters:
ClassID is the GUID specific to your handler.
Path is the path to your handler (the DLL file).
Description is a description for your handler.
NOTE: You must also associate the handler with a file type. Use the RegisterFileType method for this purpose.
UnregisterHandler UnregisterHandler(ClassID: TGUID);
Unregisters your context menu handler in the Registry.
Parameters:
ClassID is the GUID specific to your handler.
NOTE: If you unregister your handler you should also call the UnregisterFileType method to remove the association to registered file types (provided you know these file types, of course).
RegisterFileType RegisterFileType(ClassID: TGUID; FileType, Name: String);
Associates your context menu handler with files or folders of a specific type. The handler can be associated with multiple types (call this method several times in that case).
Parameters:
ClassID is the GUID specific to your handler.
FileType is the file type you want to register the handler for (as found in the Registry - eg. 'txtfile').
Name is the name your handler should be registered under.
NOTE: You must also register the handler itself. Use the RegisterHandler method for this purpose.
UnregisterFileType UnregisterFileType(ClassID: TGUID; FileType, Name: String);
Unassociates your context menu handler from files or folders of a specific type.
Parameters:
ClassID is the GUID specific to your handler.
FileType is the file type you want to unregister the handler for.
Name is the name your handler is registered under.

Hints

Known Bugs

WinME (and maybe also Win95 and Win98, please tell me) has a bug: If you attempt to install your DLL using an *.inf file, Windows will report it can't find the DLL if the DLL has a long file name (more than 8.3 letters). Using the "Browse" button in the dialog Windows presents makes no difference. So consider using a filename in the 8.3 format, if you intend to install your handler via an *.inf file.

Comments

CustomContextMenu and OwnerDrawContextMenu are freeware. Feel free to use and improve them, but please include all original files if you redistribute the zip-file. If you have any comments or corrections I would very much like to hear them.

Get the latest version from http://www3.brinkster.com/troels/delphi.asp.

Troels Jakobsen
delphiuser@get2net.dk