ShellMenu Class
Properties Methods Events Config Settings Errors
The ShellMenu class enables customizing Shell context menu items and commands.
Syntax
ShellMenu
Remarks
The ShellMenu class provides a simple way to create custom context menu items for any items selected in the Windows Shell. An application may add such menu items to perform global or item-specific operations when a user chooses the command in the context menu displayed by the Shell for the selected items.
The class communicates with the Windows Shell through a proxy DLL that is loaded by Explorer in order to add a custom menu item to context menus and handle invocation of that menu item. The set of modules included in this product is discussed in the Deployment Instructions.
Installation and Initialization
First, call the Install method to register the proxy DLL with the Windows Shell. Installation should be done at least once before using the library on a new system, but may be done several times to update the values of the ProxyPath and Scope properties.
component.Install();
Following the installation, any custom menu items that will be added to the Windows context menu must be registered in the Windows Registry. To do this, call the RegisterMenuItem method for each custom menu item.
component.RegisterMenuItem("MyMenuItem");
Note:In Windows 11, additional steps must be taken to make menu items visible in the "main" context menus. See the Shell Menu in Windows 11 section below for more information.
The next step is to call Initialize, which will perform the necessary operations to facilitate communication between the system and your code. Initialization only needs to be called once per application launch.
component.Initialize();
Adding Menu Items
Call the Activate method to start serving context menu items and begin handling requests from the Windows Shell. After calling Activate, the MenuItems collection will be populated with the previously registered menu items.
component.Activate();
// If activation was successful this prints out "MyMenuItem"
Console.WriteLine(component.MenuItems[0].Verb);
The Windows Registry only stores the unique text identifiers, or verbs, of the added menu items. As such, their additional properties, such as captions and icons are initialized to their default values every time the MenuItems collection is populated. To customize these properties, they must be set manually after calling the Activate method, or by handling the UpdateMenu event. For example:
component.OnUpdateMenu += (s, e) =>
{
int itemCount = 0;
foreach (MenuItem item in component.MenuItems)
{
if (item != null)
{
item.Caption = "Menu item #" + itemCount;
item.Icon = "shell32.dll,-249"; // icon resource string included with the Windows Shell
itemCount++;
}
}
};
Once the component is activated, the menu items from the MenuItems collection will appear in the File-Explorer's right-click context menu for any selected Windows Shell items.
Note: Menu items may not be visible in the context menu if their caption property is set to an empty string.
When a user clicks on a context menu item, the InvokeMenu event is fired, and the SelectedItems collection is populated with the Windows Shell items selected in Windows File Explorer. An application may use the context provided by the SelectedItems collection to perform actions specifically tailored to the user's selections. For example:
component.OnInvokeMenu += (s, e) =>
{
if (e.Verb.Equals("MyMenuItem"))
{
Console.WriteLine("Selected items: ");
for (int i = 0; i < component.SelectedItems.Count; i++)
{
SelectedItem item = component.SelectedItems[i];
Console.WriteLine(item.FileName);
}
}
};
Deactivation and Uninstall
To stop handling Windows Shell requests and render all custom menu items inactive, call the Deactivate method.
component.Deactivate();
Since the menu items registered via the RegisterMenuItem method are not automatically removed from the Windows Registry, it is recommended to call UnregisterMenuItem to unregister each menu item individually during the application's uninstall routine.
component.UnregisterMenuItem("MyMenuItem");
Finally, to detach the component from the Windows Shell and unregister the proxy DLL from the system, call the Uninstall method. Normally, this is done when the application is removed from the system.
component.Uninstall();
PIDLs
A PIDL (or an IDL) is a fundamental Windows Shell concept. At a high level, it is pretty simple, as it is just a value that represents a Windows Shell item in the Windows Shell Namespace. It is a bit like a full filesystem path for a physical file or folder, except that it is a binary object and not a string. The name "PIDL" and "IDL" can be used interchangeably. The leading P stands for pointer, the IDL stands for item identifier list, and PIDL generally refers to an IDL itself rather than the pointer to it.
The below information is provided as a general knowledge. Your application will deal with PIDLs only when they denote some Windows Shell items that are not necessarily a part of the Windows Shell namespace extension that you create. Such PIDLs can be used with the Windows Shell API if you decide to call it directly. When CBFS Shell exposes these PIDL values they will appear hex-encoded. If an application needs to call a shell function, it has to decode the PIDL before calling that function.
Just like a full filesystem path is a list of strings separated by the directory separator (on Windows, it is the \ (backslash) character), a PIDL is a list (L is for list) of Ids (identifiers). Unlike a filesystem path, though, a PIDL is binary, and Ids are separated by a special PIDL separator (two consecutive zero bytes).
Microsoft provides more details about PIDLs here Identifying Namespace Objects.
Verbs
The ShellMenu class is built so that one Explorer command with one GUID is registered in the registry. Verbs are used to identify individual menu items.
A verb is an alphanumeric string that identifies a menu item. Use verbs specific to your application to avoid collisions with other applications. For example, generic words "open" or "edit" are inappropriate because they are or may be used by the Windows Shell or other applications, while "OpenWithMyFineTool" should be ok, as long as "MyFineTool" is not generic.
Each menu item with a distinct verb must be registered before it can be used. This is done by creating the corresponding keys in the registry. Registration is done using the RegisterMenuItem. To remove an item, use UnregisterMenuItem.
Shell Menu in Windows 11
In Windows 11, menu commands by default appear only in the secondary menu that is shown when you choose "More Options" in the context menu. Windows 11, with its redesigned Shell, and the ShellMenu class support adding one main menu item into the main context menu of Windows 11 Shell.
For this, the menu item (command) and its GUID should be declared in a sparse package manifest that is then converted to a sparse package file. A separate manifest and sparse package file is required for each supported processor architecture.
The sparse package manifest you prepare should include the block similar to the following:
<?xml version="1.0" encoding="utf-8"?>
<Package
...
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:desktop5="http://schemas.microsoft.com/appx/manifest/desktop/windows10/5"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
IgnorableNamespaces="uap uap2 uap3 rescap desktop desktop4 desktop5 uap10 com">
<Identity Name="<your-package-name-here>" ProcessorArchitecture="..." Publisher="CN=<your-certificate-common-name-here>" Version="1.0.0.0" />
...
<Applications>
<Application Id="<your-app-id-here>" Executable="..." uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
<Extensions>
<desktop4:Extension Category="windows.fileExplorerContextMenus">
<desktop4:FileExplorerContextMenus>
<desktop5:ItemType Type="*">
<desktop5:Verb Id="<your-verb-here>" Clsid="<your-command-guid-here>" />
</desktop5:ItemType>
</desktop4:FileExplorerContextMenus>
</desktop4:Extension>
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:SurrogateServer DisplayName="Context menu verb handler">
<com:Class Id="<your-command-guid-here>" Path="CBFSShell.<Id>.<processor-architecture-here>.dll" ThreadingModel="STA"/>
</com:SurrogateServer>
</com:ComServer>
</com:Extension>
</Extensions>
</Application>
</Applications>
</Package>
- "<your-verb-here>" should be replaced with the verb of the menu command. It should be used by the system to tell the command handler, which command was invoked, however, at least on some systems, this doesn't work right. Due to this bug, only one main menu item is currently supported.
- "<your-command-guid-here>" should be replaced with the command GUID. This value can be obtained using the CommandGUID configuration setting. Note that the value in the manifest should not include curly brackets, whereas the configuration setting returns a value in the standard registry format with curly brackets. Several menu items (commands) in one sparse package manifest are possible, but require different command GUIDs, which in turn require proxy DLLs with different license IDs.
- "<processor-architecture-here>" should be replaced with the processor architecture, for which the sparse package manifest is prepared. It can be "x86", "x64", or "ARM64".
- "CBFSShell.<Id>.<processor-architecture-here>.dll" will look similar to "CBFSShell.12345678.x64.dll", where "12345678" should be replaced by your real proxy Id or "TRIAL", and the processor architecture is described above.
- "<your-certificate-common-name-here>" is the value of the Subject CN ("Common Name") field of the code signing certificate that is used to sign the application and the package.
Registration and unregistration of such a manifest are normally done via WinRT APIs, which are not easy to use from non-.NET applications. To assist with the complications, the class supports registration and unregistration of an application-provided manifest when the application calls Install and Uninstall respectively. To make use of this assistance, the application must set two configuration settings: SparsePackageFile (contains the path to the package file) and SparsePackageName (contains the name of the package, "<your-package-name-here>" in the above snippet). Note that SparsePackageFile must point not at the manifest but at the prepared and signed sparse package file (see below).
In addition to the sparse package manifest and file, one more step is required. Next to the application EXE, there must be the <application>.exe.manifest present with the following content:
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="0.0.0.1" name="<your-app-name-here>.app"/>
<msix xmlns="urn:schemas-microsoft-com:msix.v1" publisher="CN=<your-certificate-common-name-here>" packageName="<your-package-name-here>" applicationId="<your-app-id-here>"/>
</assembly>
- "<your-package-name-here>" in this manifest must match with the corresponding value of the sparse file manifest.
- "<your-app-id-here>" in this manifest must match with the corresponding value of the sparse file manifest.
- The "CN" value ("<your-certificate-common-name-here>") comes from your code signing certificate. This value must match the corresponding value in the sparse file manifest.
The sparse package manifest should be converted into a sparse package file. This is done by running two commands:
makeappx.exe pack /d <directory-with-manifest> /p <your-app-name-here>.msix /nv
signtool.exe sign /fd SHA256 /a /n "<your-certificate-common-name-here>" <your-app-name-here>.msix
or
signtool.exe sign /fd SHA256 /a /f "<your-certificate-file-name-here>.pfx" /p <certificate-password-here>
Both tools come from Windows SDK. makeappx.exe creates the sparse file package from the manifest, and signtool.exe signs it.
Signtool takes a certificate either from the Personal/My certificate storage in your system (the common name is used for selecting the correct certificate) or from a specified PFX file. A file can be used in development/test scenarios, whereas production code signing certificates usually come on hardware and are reachable via the Windows Certificate Store.
The sparse package manifest should reside in a subdirectory, as the makeappx.exe accepts a directory with the manifest as a parameter. The manifest for each processor architecture should reside in its own subdirectory, as it is converted to a signed package separately.
Troubleshooting
Following are some helpful resources for troubleshooting issues related to the display of menu items.
- If you are developing your application and you stop and start repeatedly while keeping Windows File Explorer open, there may be a memory/cache issue. To avoid this situation one should terminate Explorer and reopen it.
- If your context menu items do not appear at all or an excess number of menu items appear, this may indicate a registration/deregistration issue. Try running the application with administrative privileges.
- If you are seeing strange behavior not contained in this list, please reach out to us with a description of the problem and we are happy to help. Our support team is available over email at support@callback.com
Property List
The following is the full list of the properties of the class with short descriptions. Click on the links for further details.
MenuItems | This property contains a collection of registered menu items. |
ProxyPath | This property specifies the path to the native proxy DLL. |
Scope | This property specifies whether the class is registered for the current user or for all users. |
SelectedItems | This property contains a collection of selected Windows Shell items. |
Method List
The following is the full list of the methods of the class with short descriptions. Click on the links for further details.
Activate | This method tells the class to start handling the requests sent to the namespace extension. |
Config | Sets or retrieves a configuration setting. |
Deactivate | This method tells the class to stop handling the requests sent to the namespace extension. |
Initialize | This method initializes the core library. |
Install | This method registers context menu information to the system. |
RegisterMenuItem | This method adds a menu item to the Windows Registry. |
Uninstall | This method unregisters context menu information from the system. |
UnregisterMenuItem | This method unregisters a previously registered menu item. |
Event List
The following is the full list of the events fired by the class with short descriptions. Click on the links for further details.
Error | This event is fired if an unhandled error occurs during an event. |
InvokeMenu | This event is fired when an item of the context menu is invoked. |
UpdateMenu | This event is fired when the context menu needs to be updated. |
Config Settings
The following is a list of config settings for the class with short descriptions. Click on the links for further details.
CanonicalName | A human-readable name of the command. |
CommandGUID | A GUID of the Explorer command. |
IPCFormat | The fixed name of the RPC endpoint. |
IsInstalled | Specifies whether the installation was performed. |
ProductGUID | ID of the proxy DLL. |
ServerStartArguments | The arguments to pass with the command. |
ServerStartCommandLine | The command line to run when the server is not available. |
ServerStartOperation | The operation verb. |
ServerStartShowOption | Defines how the application windows should be shown. |
ServerStartTimeToWait | Optional time to wait before retrying RPC connection. |
ServerStartWorkingDirectory | The working directory. |
SparsePackageFile | The path to the sparse package file. |
SparsePackageName | The name of the sparse package. |
BuildInfo | Information about the product's build. |
LicenseInfo | Information about the current license. |
MenuItems Property (ShellMenu Class)
This property contains a collection of registered menu items.
Syntax
CBFSShellList<CBFSShellMenuItem>* GetMenuItems();
int cbfsshell_shellmenu_getmenuitemscount(void* lpObj);
char* cbfsshell_shellmenu_getmenuitemcaption(void* lpObj, int menuitemindex);
int cbfsshell_shellmenu_setmenuitemcaption(void* lpObj, int menuitemindex, const char* lpszMenuItemCaption);
int cbfsshell_shellmenu_getmenuitemenabled(void* lpObj, int menuitemindex);
int cbfsshell_shellmenu_setmenuitemenabled(void* lpObj, int menuitemindex, int bMenuItemEnabled);
int cbfsshell_shellmenu_getmenuitemflags(void* lpObj, int menuitemindex);
char* cbfsshell_shellmenu_getmenuitemicon(void* lpObj, int menuitemindex);
int cbfsshell_shellmenu_setmenuitemicon(void* lpObj, int menuitemindex, const char* lpszMenuItemIcon);
char* cbfsshell_shellmenu_getmenuitemverb(void* lpObj, int menuitemindex);
int cbfsshell_shellmenu_getmenuitemvisible(void* lpObj, int menuitemindex);
int cbfsshell_shellmenu_setmenuitemvisible(void* lpObj, int menuitemindex, int bMenuItemVisible);
int GetMenuItemsCount(); QString GetMenuItemCaption(int iMenuItemIndex);
int SetMenuItemCaption(int iMenuItemIndex, QString qsMenuItemCaption); bool GetMenuItemEnabled(int iMenuItemIndex);
int SetMenuItemEnabled(int iMenuItemIndex, bool bMenuItemEnabled); int GetMenuItemFlags(int iMenuItemIndex); QString GetMenuItemIcon(int iMenuItemIndex);
int SetMenuItemIcon(int iMenuItemIndex, QString qsMenuItemIcon); QString GetMenuItemVerb(int iMenuItemIndex); bool GetMenuItemVisible(int iMenuItemIndex);
int SetMenuItemVisible(int iMenuItemIndex, bool bMenuItemVisible);
Remarks
This property holds a collection of MenuItem objects.
Customizing Menu Items
When Activate is called to start handling Windows Shell requests the first time after the application is launched, the MenuItems collection gets populated with the menu items, registered in the Windows Registry. The items in the MenuItems collection initially don't contain any values in their properties except for Verb and ParentVerb. An application should fill those items' properties either right after using the Activate method or dynamically, in response to the UpdateMenu event.Note: Registered menu items may not appear in the context menu if their Caption property is set to an empty string.
This property is read-only and not available at design time.
Data Type
ProxyPath Property (ShellMenu Class)
This property specifies the path to the native proxy DLL.
Syntax
ANSI (Cross Platform) char* GetProxyPath();
int SetProxyPath(const char* lpszProxyPath); Unicode (Windows) LPWSTR GetProxyPath();
INT SetProxyPath(LPCWSTR lpszProxyPath);
char* cbfsshell_shellmenu_getproxypath(void* lpObj);
int cbfsshell_shellmenu_setproxypath(void* lpObj, const char* lpszProxyPath);
QString GetProxyPath();
int SetProxyPath(QString qsProxyPath);
Default Value
""
Remarks
This property may be used to specify the path to the native proxy DLL, which is loaded by the Windows Shell. The value may be in one of these formats:
- The name of the directory with Proxy DLLs. In this case, the class will choose the first DLL with the appropriate architecture.
- The full path with the name of the DLL. In this case, just this DLL will be loaded.
- The full path with wildcards in the name part (a pattern). In this case, the class will choose the first DLL that matches the passed pattern.
If left empty, the class will automatically attempt to locate the appropriate DLL by searching the directory where the application's executable resides.
Data Type
String
Scope Property (ShellMenu Class)
This property specifies whether the class is registered for the current user or for all users.
Syntax
ANSI (Cross Platform) int GetScope();
int SetScope(int iScope); Unicode (Windows) INT GetScope();
INT SetScope(INT iScope);
Possible Values
IS_ALL_USERS(0),
IS_CURRENT_USER(1)
int cbfsshell_shellmenu_getscope(void* lpObj);
int cbfsshell_shellmenu_setscope(void* lpObj, int iScope);
int GetScope();
int SetScope(int iScope);
Default Value
1
Remarks
This property specifies whether the information related to the class is written to the registry for the current user or for all users.
In the latter case, administrative rights are required to successfully execute the Install and Uninstall methods. If the user account of the process that calls these methods does not have such rights, the call will fail with an error.
Data Type
Integer
SelectedItems Property (ShellMenu Class)
This property contains a collection of selected Windows Shell items.
Syntax
CBFSShellList<CBFSShellSelectedItem>* GetSelectedItems();
int cbfsshell_shellmenu_getselecteditemscount(void* lpObj);
char* cbfsshell_shellmenu_getselecteditemfilename(void* lpObj, int selecteditemindex);
char* cbfsshell_shellmenu_getselecteditemid(void* lpObj, int selecteditemindex);
int cbfsshell_shellmenu_getselecteditempidl(void* lpObj, int selecteditemindex, char** lpSelectedItemPIDL, int* lenSelectedItemPIDL);
int GetSelectedItemsCount(); QString GetSelectedItemFileName(int iSelectedItemIndex); QString GetSelectedItemId(int iSelectedItemIndex); QByteArray GetSelectedItemPIDL(int iSelectedItemIndex);
Remarks
This property holds a collection of SelectedItem objects, which is populated when a menu is invoked or clicked.
This property is read-only and not available at design time.
Data Type
Activate Method (ShellMenu Class)
This method tells the class to start handling the requests sent to the namespace extension.
Syntax
ANSI (Cross Platform) int Activate(); Unicode (Windows) INT Activate();
int cbfsshell_shellmenu_activate(void* lpObj);
int Activate();
Remarks
This method is used to tell the component to begin handling Windows Shell requests and start firing the corresponding events.
Customizing Menu Items
When Activate is called to start handling Windows Shell requests the first time after the application is launched, the MenuItems collection gets populated with the menu items, registered in the Windows Registry. The items in the MenuItems collection initially don't contain any values in their properties except for Verb and ParentVerb. An application should fill those items' properties either right after using the Activate method or dynamically, in response to the UpdateMenu event.Note: Registered menu items may not appear in the context menu if their Caption property is set to an empty string.
Menu Item Persistence
When the Deactivate method is called to stop the class, registered menu items will remain in the MenuItems list. If the component is restarted by calling this method after deactivation, the properties of these menu items will not need to be repopulated.Error Handling (C++)
This method returns a result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message. (Note: This method's result code can also be obtained by calling the GetLastErrorCode() method after it returns.)
Config Method (ShellMenu Class)
Sets or retrieves a configuration setting.
Syntax
ANSI (Cross Platform) char* Config(const char* lpszConfigurationString); Unicode (Windows) LPWSTR Config(LPCWSTR lpszConfigurationString);
char* cbfsshell_shellmenu_config(void* lpObj, const char* lpszConfigurationString);
QString Config(const QString& qsConfigurationString);
Remarks
Config is a generic method available in every class. It is used to set and retrieve configuration settings for the class.
These settings are similar in functionality to properties, but they are rarely used. In order to avoid "polluting" the property namespace of the class, access to these internal properties is provided through the Config method.
To set a configuration setting named PROPERTY, you must call Config("PROPERTY=VALUE"), where VALUE is the value of the setting expressed as a string. For boolean values, use the strings "True", "False", "0", "1", "Yes", or "No" (case does not matter).
To read (query) the value of a configuration setting, you must call Config("PROPERTY"). The value will be returned as a string.
Error Handling (C++)
This method returns a String value; after it returns, call the GetLastErrorCode() method to obtain its result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message.
Deactivate Method (ShellMenu Class)
This method tells the class to stop handling the requests sent to the namespace extension.
Syntax
ANSI (Cross Platform) int Deactivate(); Unicode (Windows) INT Deactivate();
int cbfsshell_shellmenu_deactivate(void* lpObj);
int Deactivate();
Remarks
This method tells the component to stop handling Windows Shell requests and stop firing the corresponding events.
Error Handling (C++)
This method returns a result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message. (Note: This method's result code can also be obtained by calling the GetLastErrorCode() method after it returns.)
Initialize Method (ShellMenu Class)
This method initializes the core library.
Syntax
ANSI (Cross Platform) int Initialize(); Unicode (Windows) INT Initialize();
int cbfsshell_shellmenu_initialize(void* lpObj);
int Initialize();
Remarks
This method initializes the core library and must be called each time the application starts before attempting to use other class's methods. The only exceptions to this are Install, Uninstall, RegisterMenuItem, and UnregisterMenuItem.
If the application explicitly specifies the path to the proxy DLL, it should do this through the ProxyPath property before calling this method.
Error Handling (C++)
This method returns a result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message. (Note: This method's result code can also be obtained by calling the GetLastErrorCode() method after it returns.)
Install Method (ShellMenu Class)
This method registers context menu information to the system.
Syntax
ANSI (Cross Platform) int Install(); Unicode (Windows) INT Install();
int cbfsshell_shellmenu_install(void* lpObj);
int Install();
Remarks
This method is used to install the native proxy DLL that integrates with the Windows Shell.
Before calling this method, you may change the default values of the ProxyPath, and Scope properties. These values are used during installation.
Registry Scope and User Permissions
The Scope property specifies whether the information is written to the registry for the current user or for all users.In the latter case, administrative rights are required to execute this method successfully. If the user account of the process that calls this method does not have such rights, the call will fail with an ERROR_PRIVILEGE_NOT_HELD (0x0522) error.
Error Handling (C++)
This method returns a result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message. (Note: This method's result code can also be obtained by calling the GetLastErrorCode() method after it returns.)
RegisterMenuItem Method (ShellMenu Class)
This method adds a menu item to the Windows Registry.
Syntax
ANSI (Cross Platform) int RegisterMenuItem(const char* lpszVerb); Unicode (Windows) INT RegisterMenuItem(LPCWSTR lpszVerb);
int cbfsshell_shellmenu_registermenuitem(void* lpObj, const char* lpszVerb);
int RegisterMenuItem(const QString& qsVerb);
Remarks
This method registers a menu item to the Windows Registry. Menu items must be registered before they can be used in a context menu. Normally, this is only needs to be done once during application installation.
The Verb parameter specifies a unique text identifier of the context menu item, further referred to as Verb. A verb is the only aspect of the menu item that gets stored in the Windows Registry.
It is possible to create a menu item with a submenu that contains child items. Note that only one level of submenus is supported on Windows 11, so the class limits addition of items to one level of submenus too.
To create a submenu, when adding a child item, set Verb to the format <ParentVerb>::<Verb>, where ParentVerb denotes the menu item that is a parent for a submenu. Note that the parent's verb is used only in this method to specify the parent, and the class passes just the Verb part to the event handlers. Thus, the verb must be unique across all items added via ShellMenu.
Windows Registry Pollution
Menu items registered with the RegisterMenuItem method are not automatically removed from the Windows Registry. To avoid polluting the Registry, it is recommended to unregister each item before the Uninstall method is called.
Customizing Menu Items
When Activate is called to start handling Windows Shell requests the first time after the application is launched, the MenuItems collection gets populated with the menu items, registered in the Windows Registry. The items in the MenuItems collection initially don't contain any values in their properties except for Verb and ParentVerb. An application should fill those items' properties either right after using the Activate method or dynamically, in response to the UpdateMenu event.Note: Registered menu items may not appear in the context menu if their Caption property is set to an empty string.
Registry Scope and User Permissions
The Scope property specifies whether the information is written to the registry for the current user or for all users.In the latter case, administrative rights are required to execute this method successfully. If the user account of the process that calls this method does not have such rights, the call will fail with an ERROR_PRIVILEGE_NOT_HELD (0x0522) error.
Error Handling (C++)
This method returns a result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message. (Note: This method's result code can also be obtained by calling the GetLastErrorCode() method after it returns.)
Uninstall Method (ShellMenu Class)
This method unregisters context menu information from the system.
Syntax
ANSI (Cross Platform) int Uninstall(); Unicode (Windows) INT Uninstall();
int cbfsshell_shellmenu_uninstall(void* lpObj);
int Uninstall();
Remarks
This method is used to uninstall the proxy DLL that integrates with the Windows Shell from the system.
Before calling this method, you may change the default value of the Scope property.
Windows Registry Pollution
Menu items registered with the RegisterMenuItem method are not automatically removed from the Windows Registry. To avoid polluting the Registry, it is recommended to unregister each item before the Uninstall method is called.
Registry Scope and User Permissions
The Scope property specifies whether the information is written to the registry for the current user or for all users.In the latter case, administrative rights are required to execute this method successfully. If the user account of the process that calls this method does not have such rights, the call will fail with an ERROR_PRIVILEGE_NOT_HELD (0x0522) error.
Handling Multiple Components
As ShellFolder and ShellMenu classes share a proxy DLL and a product GUID, they store some common information in a registry key. Calling the Uninstall method of one of the components will delete a shared registry key as well.
Each class should be uninstalled properly by calling the corresponding Uninstall method. At the same time, if an application needs to uninstall just one class and keep the other(s), it should call the Uninstall method of that class and then call the Install method of the other classes to restore the common information in the shared registry key.
Error Handling (C++)
This method returns a result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message. (Note: This method's result code can also be obtained by calling the GetLastErrorCode() method after it returns.)
UnregisterMenuItem Method (ShellMenu Class)
This method unregisters a previously registered menu item.
Syntax
ANSI (Cross Platform) int UnregisterMenuItem(const char* lpszVerb); Unicode (Windows) INT UnregisterMenuItem(LPCWSTR lpszVerb);
int cbfsshell_shellmenu_unregistermenuitem(void* lpObj, const char* lpszVerb);
int UnregisterMenuItem(const QString& qsVerb);
Remarks
This method is used to remove a menu item that was registered with RegisterMenuItem from the Windows Registry. This should normally be done once per each menu item after the Uninstall method has been called.
The Verb parameter specifies the unique text identifier of the context menu item. If an item is a child in a submenu, this child's own verb is enough (a parent verb should not be specified).
Registry Scope and User Permissions
The Scope property specifies whether the information is written to the registry for the current user or for all users.In the latter case, administrative rights are required to execute this method successfully. If the user account of the process that calls this method does not have such rights, the call will fail with an ERROR_PRIVILEGE_NOT_HELD (0x0522) error.
Error Handling (C++)
This method returns a result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. If an error occurs, the GetLastError() method can be called to retrieve the associated error message. (Note: This method's result code can also be obtained by calling the GetLastErrorCode() method after it returns.)
Error Event (ShellMenu Class)
This event is fired if an unhandled error occurs during an event.
Syntax
ANSI (Cross Platform) virtual int FireError(ShellMenuErrorEventParams *e);
typedef struct {
int ErrorCode;
const char *Description; int reserved; } ShellMenuErrorEventParams;
Unicode (Windows) virtual INT FireError(ShellMenuErrorEventParams *e);
typedef struct {
INT ErrorCode;
LPCWSTR Description; INT reserved; } ShellMenuErrorEventParams;
#define EID_SHELLMENU_ERROR 1 virtual INT CBFSSHELL_CALL FireError(INT &iErrorCode, LPSTR &lpszDescription);
class ShellMenuErrorEventParams { public: int ErrorCode(); const QString &Description(); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void Error(ShellMenuErrorEventParams *e);
// Or, subclass ShellMenu and override this emitter function. virtual int FireError(ShellMenuErrorEventParams *e) {...}
Remarks
This event fires if an unhandled error occurs. Developers can use this information to track down unhandled errors that occur in the class.
ErrorCode contains an error code and Description contains a textual description of the error.
InvokeMenu Event (ShellMenu Class)
This event is fired when an item of the context menu is invoked.
Syntax
ANSI (Cross Platform) virtual int FireInvokeMenu(ShellMenuInvokeMenuEventParams *e);
typedef struct {
const char *Verb;
int64 Context; int reserved; } ShellMenuInvokeMenuEventParams;
Unicode (Windows) virtual INT FireInvokeMenu(ShellMenuInvokeMenuEventParams *e);
typedef struct {
LPCWSTR Verb;
LONG64 Context; INT reserved; } ShellMenuInvokeMenuEventParams;
#define EID_SHELLMENU_INVOKEMENU 2 virtual INT CBFSSHELL_CALL FireInvokeMenu(LPWSTR &lpszVerb, LONG64 &lContext);
class ShellMenuInvokeMenuEventParams { public: const QString &Verb(); qint64 Context(); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void InvokeMenu(ShellMenuInvokeMenuEventParams *e);
// Or, subclass ShellMenu and override this emitter function. virtual int FireInvokeMenu(ShellMenuInvokeMenuEventParams *e) {...}
Remarks
This event is fired when a user invokes, or clicks on, a context menu item that has been registered with RegisterMenuItem. To obtain the list of the Windows Shell items for which the context menu was displayed, use the SelectedItems property.
The Verb parameter contains the unique text identifier of the menu item that was invoked.
The Context parameter is a unique identifier that remains the same across multiple event calls for the same operation. Since the event may fire multiple times for the same operation, its value may be used to avoid performing the same tasks more than once.
UI Considerations
Event handlers are called in the context of threads that run in the MTA (multithreaded apartment) state. This state is not suitable for showing UI elements. Thus, event handlers should create an STA thread and use it to display a needed window. For example:var thread = new Thread(() => { ... } // "..." is the code that an event handler executes in a helper thread
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
thread.Join(); // optional, if your code should work synchronously
UpdateMenu Event (ShellMenu Class)
This event is fired when the context menu needs to be updated.
Syntax
ANSI (Cross Platform) virtual int FireUpdateMenu(ShellMenuUpdateMenuEventParams *e);
typedef struct {
const char *Verb;
int64 Context; int reserved; } ShellMenuUpdateMenuEventParams;
Unicode (Windows) virtual INT FireUpdateMenu(ShellMenuUpdateMenuEventParams *e);
typedef struct {
LPCWSTR Verb;
LONG64 Context; INT reserved; } ShellMenuUpdateMenuEventParams;
#define EID_SHELLMENU_UPDATEMENU 3 virtual INT CBFSSHELL_CALL FireUpdateMenu(LPWSTR &lpszVerb, LONG64 &lContext);
class ShellMenuUpdateMenuEventParams { public: const QString &Verb(); qint64 Context(); int EventRetVal(); void SetEventRetVal(int iRetVal); };
// To handle, connect one or more slots to this signal. void UpdateMenu(ShellMenuUpdateMenuEventParams *e);
// Or, subclass ShellMenu and override this emitter function. virtual int FireUpdateMenu(ShellMenuUpdateMenuEventParams *e) {...}
Remarks
This event is fired when the system needs to update the context menu before it is displayed. The event fires separately for each menu item that was registered via RegisterMenuItem. An event handler is expected to update the menu item in the MenuItems collection if such an update is required, and such updates will be reflected in the displayed menu. To obtain the list of Windows Shell items for which the context menu is about to be displayed, use the SelectedItems property.
The Verb parameter contains the unique text identifier of the corresponding menu item that may be updated.
The Context parameter is a unique identifier that remains the same across multiple event calls for the same operation. Since the event may fire multiple times for the same operation, its value may be used to avoid performing the same tasks more than once.
UI Considerations
Event handlers are called in the context of threads that run in the MTA (multithreaded apartment) state. This state is not suitable for showing UI elements. Thus, event handlers should create an STA thread and use it to display a needed window. For example:var thread = new Thread(() => { ... } // "..." is the code that an event handler executes in a helper thread
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
thread.Join(); // optional, if your code should work synchronously
MenuItem Type
Represents a registered menu item.
Syntax
CBFSShellMenuItem (declared in cbfsshell.h)
Remarks
This type represents a registered menu item.
Fields
Caption
char*
Default Value: ""
Specifies the menu item's caption.
This field contains the caption or title of the menu item - the text of the item, visible to a user.
Enabled
int
Default Value: TRUE
Specifies that a menu item is enabled.
This field specifies whether the menu item is enabled and can be selected by a user.
Flags
int
Default Value: 0
Flags of the item.
This field is a combination of zero or more flags that specify the attributes of the menu item. The possible flags include:
CMF_DEFAULT | 0x00 | No command flags are set |
CMF_HAS_SUBCOMMANDS | 0x01 | Not used. |
CMF_HASSPLITBUTTON | 0x02 | A split button is displayed. |
CMF_HIDELABEL | 0x04 | The label is hidden. |
CMF_ISSEPARATOR | 0x08 | The command is a separator. |
CMF_HASLUASHIELD | 0x0010 | A UAC shield is displayed. |
CMF_ISDROPDOWN | 0x0080 | Selecting the command opens a drop-down submenu. |
CMF_TOGGLEABLE | 0x0100 | The item is a switch. |
Icon
char*
Default Value: ""
Specifies the icon of the menu item.
The field may be set to an icon resource string in the standard format, for instance "shell32.dll,-249". When set, this icon will be displayed next to the menu item caption.
Verb
char* (read-only)
Default Value: ""
A verb (text identifier) of the item.
This field contains a Verb, which is a unique text identifier of the item. If a menu item is a child item, this value of this field is <ParentVerb>::<Verb>.
Visible
int
Default Value: TRUE
Specifies that a menu item is visible.
This field specifies whether the menu item is visible and can be seen by a user.
SelectedItem Type
Represents a selected Windows Shell item.
Syntax
CBFSShellSelectedItem (declared in cbfsshell.h)
Remarks
This type represents a Windows Shell item in the list of items selected in ShellMenu.
Fields
FileName
char* (read-only)
Default Value: ""
Contains a file name of the selected item.
If an item is a filesystem object and its PIDL can be resolved to a filesystem path, this field contains a full path on the filesystem; otherwise, the field is empty.
Id
char* (read-only)
Default Value: ""
Contains an Id of the selected item.
If a selected item comes from within the virtual Windows Shell folder managed by the ShellFolder class, this field contans an application-defined Id. In other cases, this field is empty and the application may use the PIDL field to identify the item.
PIDL
char* (read-only)
Default Value:
Contains a PIDL of the selected item.
This field contains the PIDL of the selected item.
CBFSShellList Type
Syntax
CBFSShellList<T> (declared in cbfsshell.h)
Remarks
CBFSShellList is a generic class that is used to hold a collection of objects of type T, where T is one of the custom types supported by the ShellMenu class.
Methods | |
GetCount |
This method returns the current size of the collection.
int GetCount() {}
|
SetCount |
This method sets the size of the collection. This method returns 0 if setting the size was successful; or -1 if the collection is ReadOnly. When adding additional objects to a collection call this method to specify the new size. Increasing the size of the collection preserves existing objects in the collection.
int SetCount(int count) {}
|
Get |
This method gets the item at the specified position. The index parameter specifies the index of the item in the collection. This method returns NULL if an invalid index is specified.
T* Get(int index) {}
|
Set |
This method sets the item at the specified position. The index parameter specifies the index of the item in the collection that is being set. This method returns -1 if an invalid index is specified. Note: Objects created using the new operator must be freed using the delete operator; they will not be automatically freed by the class.
T* Set(int index, T* value) {}
|
Config Settings (ShellMenu Class)
The class accepts one or more of the following configuration settings. Configuration settings are similar in functionality to properties, but they are rarely used. In order to avoid "polluting" the property namespace of the class, access to these internal properties is provided through the Config method.ShellMenu Config Settings
Set this configuration setting before installing the native proxy DLL.
Set this configuration setting before installing the native proxy DLL.
Set this configuration setting before installing the native proxy DLL.
The time is specified in milliseconds. The default value is 3000 (3 seconds). Set this configuration setting before installing the native proxy DLL.
Set this configuration setting before installing the native proxy DLL.
Base Config Settings
- Product: The product the license is for.
- Product Key: The key the license was generated from.
- License Source: Where the license was found (e.g., RuntimeLicense, License File).
- License Type: The type of license installed (e.g., Royalty Free, Single Server).
Trappable Errors (ShellMenu Class)
Error Handling (C++)
Call the GetLastErrorCode() method to obtain the last called method's result code; 0 indicates success, while a non-zero error code indicates that this method encountered an error during its execution. Known error codes are listed below. If an error occurs, the GetLastError() method can be called to retrieve the associated error message.
ShellMenu Errors
2 | An item with given ID cannot be found. The CBFSSHELL_ERR_FILE_NOT_FOUND constant is provided for convenience and may be used in place of the numeric value. |
20 | Cannot load native proxy DLL. The CBFSSHELL_ERR_CANT_LOAD_PROXY constant is provided for convenience and may be used in place of the numeric value. |
28 | The major version of the proxy DLL doesn't match the major version of the .NET assembly. The CBFSSHELL_ERR_PROXY_VERSION_MISMATCH constant is provided for convenience and may be used in place of the numeric value. |
38 | End of data stream has been reached and no data could be read. The CBFSSHELL_ERR_STREAM_EOF constant is provided for convenience and may be used in place of the numeric value. |
55 | Proxy DLL not installed properly. The CBFSSHELL_ERR_NOT_INSTALLED constant is provided for convenience and may be used in place of the numeric value. |
56 | Installation of the native proxy DLL failed. The CBFSSHELL_ERR_INSTALL_FAILED constant is provided for convenience and may be used in place of the numeric value. |
57 | Uninstallation of the native proxy DLL failed. The CBFSSHELL_ERR_UNINSTALL_FAILED constant is provided for convenience and may be used in place of the numeric value. |
58 | Initialization of the native proxy DLL failed. The CBFSSHELL_ERR_INIT_FAILED constant is provided for convenience and may be used in place of the numeric value. |
59 | The current license and the ID in the native proxy DLL name don't match. The CBFSSHELL_ERR_PROXY_NAME_MISMATCH constant is provided for convenience and may be used in place of the numeric value. |
60 | Writing to the Windows registry failed. The CBFSSHELL_ERR_CANT_WRITE_TO_REGISTRY constant is provided for convenience and may be used in place of the numeric value. |
61 | This Menu instance has already been started. The CBFSSHELL_ERR_ALREADY_STARTED constant is provided for convenience and may be used in place of the numeric value. |
62 | A menu item with the same verb is already registered. The CBFSSHELL_ERR_MENU_ITEM_ALREADY_REG constant is provided for convenience and may be used in place of the numeric value. |
63 | No menu items have been registered. The CBFSSHELL_ERR_MENU_ITEM_NOT_REG constant is provided for convenience and may be used in place of the numeric value. |
87 | The passed parameter was not valid. The CBFSSHELL_ERR_INVALID_PARAMETER constant is provided for convenience and may be used in place of the numeric value. |
122 | The provided buffer is too small to accommodate all the data that must be placed in it. The CBFSSHELL_ERR_INSUFFICIENT_BUFFER constant is provided for convenience and may be used in place of the numeric value. |