Export (0) Print
Expand All

Registering Shell Extensions

The capabilities of the Shell can be extended with registry entries and .ini files. While this approach to extending the Shell is simple, and adequate for many purposes, it is limited. For example, if you use the registry to specify a custom icon for a file class, the same icon will appear for every file in that class. Extending the Shell with the registry does not allow you to vary the icon for different members of the class. Other aspects of the Shell, such as the Properties property sheet that can be displayed when a file is right-clicked, cannot be modified at all with the registry.

A more powerful and flexible approach to extending the Shell is to implement shell extension handlers. These handlers can be implemented for a variety of actions that the Shell can perform. Before taking the action, the Shell queries the extension handler, giving it the opportunity to modify the action. A common example is a shortcut menu extension handler. If one is implemented for a file class, it will be queried every time one of the files is right-clicked. The handler can then specify additional menu items on a file-by-file basis, rather than having the same set for the entire file class.

This document discusses how to implement the extension handlers that allow you to modify a variety of Shell actions. The following handlers are associated with a particular file class and allow you to specify on a file-by-file basis:

Handler Description
Shortcut menu handler Called before a file's shortcut menu is displayed. It enables you to add items to the shortcut menu on a file-by-file basis.
Data handler Called when a drag-and-drop operation is performed on dragShell objects. It enables you to provide additional clipboard formats to the drop target.
Drop handler Called when a data object is dragged over or dropped on a file. It enables you to make a file into a drop target.
Icon handler Called before a file's icon is displayed. It enables you to replace the file's default icon with a custom icon on a file-by-file basis.
Property sheet handler Called before an object's Properties property sheet is displayed. It enables you to add or replace pages.
Thumbnail Image handler Provides an image to represent the item.
Infotip handler Provides pop-up text when the user hovers the mouse pointer over the object.
Metadata handler Provides read and write access to metadata (properties) stored in a file. This can be used to extend the Details view, infotips, the property page, and grouping features.

Others are not associated with a particular file class but are called before some Shell operations.

Handler Description
Column handler Called by Microsoft Windows Explorer before it displays the Details view of a folder. It enables you to add custom columns to the Details view.
Copy hook handler Called when a folder or printer object is about to be moved, copied, deleted, or renamed. It enables you to approve or veto the operation.
Drag-and-drop handler Called when a file is dragged with the right mouse button. It enables you to modify the shortcut menu that is displayed.
Icon Overlay handler Called before a file's icon is displayed. It enables you to specify an overlay for the file's icon.
Search handler Called to launch a search engine. It enables you to implement a custom search engine accessible from the Start menu or Windows Explorer.

The details of how to implement specific extension handlers are covered in the sections listed above. The remainder of this document covers some implementation issues that are common to all Shell extension handlers.

Implementing Shell Extension Handlers

Much of the implementation of a Shell extension handler object is dictated by its type. There are, however, some common elements. This section discusses those aspects of implementation that are shared by all Shell extension handlers.

All Shell extension handlers are in-process Component Object Model (COM) objects. They must be assigned a GUID and registered as described in Registering Shell Extension Handlers. They are implemented as DLLs and must export the following standard functions:

  • DllMain. The standard entry point to the DLL.
  • DllGetClassObject. Exposes the object's class factory
  • DllCanUnloadNow. COM calls this function to determine whether the object is serving any clients. If not, the system can unload the DLL and free the associated memory.

Like all COM objects, Shell extension handlers must implement an IUnknown interface and a class factory. Most must also implement either an IPersistFile or IShellExtInit interface in Windows XP or earlier. These were replaced by IInitializeWithStream, IInitializeWithItem and IInitializeWithFile in Windows Vista. The Shell uses these interfaces to initialize the handler.

The IPersistFile interface must be implemented by the following:

  • Icon handlers
  • Data handlers
  • Drop handlers

The IShellExtInit interface must be implemented by the following:

  • Shortcut menu handlers
  • Drag-and-drop handlers
  • Property sheet handlers

Implementing IPersistFile

The IPersistFile interface is intended to permit an object to be loaded from or saved to a disk file. It has six methods in addition to IUnknown, five of its own, and the GetClassID method that it inherits from IPersist. With Shell extensions, IPersist is used only to initialize a Shell extension handler object. Because there is typically no need to read from or write to the disk, only the GetClassID and Load methods require a nontoken implementation.

The Shell calls GetClassID first, and the function returns the class identifier (CLSID) of the extension handler object. The Shell then calls Load and passes in two values. The first, pszFileName, is a Unicode string with the name of the file or folder that Shell is about to operate on. The second is dwMode, which indicates the file access mode. Because there is normally no need to access files, dwMode is typically zero. The method stores these values as needed for later reference.

The following code fragment illustrates how a typical Shell extension handler implements the GetClassID and Load methods. It is designed to handle either ANSI or Unicode. CLSID_SampleExtHandler is the extension handler object's GUID, and CSampleExtHandler is the name of the class used to implement the interface. The m_szFileName and m_dwMode variables are private variables that are used to store the file's name and access flags.


TCHAR m_szFileName[MAX_PATH];    // The file name
DWORD m_dwMode;                  // The file access mode

CSampleExtHandler::GetClassID(CLSID *pCLSID)
{
    *pCLSID = CLSID_SampleExtHandler;
}

CSampleExtHandler::Load(LPCOLESTR pOleStr, DWORD dwMode)
{
    HRESULT hr = S_OK;
    size_t count = 0;

    #ifdef UNICODE    // If the handler is Unicode, copy the string.
        hr = StringCchCopyNW(m_szFileName, 
                             MAX_PATH, 
                             (LPWSTR)pOleStr, MAX_PATH-1); 
							 
        // Add error handling here to check HRESULT returned 
        // by StringCchCopyNW.

    #else    // If the handler is ANSI, first convert the string to ANSI.
        hr = StringCchLength(pOleStr, STRSAFE_MAX_CCH, &count);
        if (SUCCEEDED(hr))
        {
            WideCharToMultiByte(CP_ACP,
                                0,
                                pOleStr,    
                                count,       
                                m_szFileName, 
                                MAX_PATH * sizeof(TCHAR),  
                                NULL,
                                NULL);
        }
        if (FAILED(hr))
        {
            // Problem with the string - perhaps not null-terminated?
        }
    #endif

    m_dwMode = dwMode;
	
    return hr;
}

Implementing IShellExtInit

The IShellExtInit interface has only one method, Initialize, in addition to IUnknown. The method has three parameters that the Shell can use to pass in various types of information. The values passed in depend on the type of handler, and some can be set to NULL.

  • pIDFolder holds a folder's pointer to an item identifier list (PIDL). For property sheet extensions, it is NULL. For shortcut menu extensions, it is the PIDL of the folder that contains the item whose shortcut menu is being displayed. For nondefault drag-and-drop handlers, it is the PIDL of the target folder.
  • pDataObject holds a pointer to a data object's IDataObject interface. The data object holds one or more file names in CF_HDROP format.
  • hRegKey holds a registry key for the file object or folder type.

The Initialize method stores the file name, IDataObject pointer, and registry key as needed for later use. The following code fragment illustrates an implementation of Initialize. For simplicity, this example assumes that the data object contains only a single file. In general, it might contain multiple files that will each need to be extracted.


LPCITEMIDLIST  m_pIDFolder;           //The folder's PIDL
TCHAR          m_szFile[MAX_PATH];    //The file name
IDataObject   *m_pDataObj;            //The IDataObject pointer
HKEY           m_hRegKey;             //The file or folder's registry key

STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pIDFolder, 
                                   IDataObject *pDataObj, 
                                   HKEY hRegKey) 
{ 
    // If Initialize has already been called, release the old PIDL
    ILFree(m_pIDFolder);
    m_pIDFolder = NULL;

    //Store the new PIDL.
    if(pIDFolder)
    {
        m_pIDFolder = ILClone(pIDFolder);
    }
	
    // If Initialize has already been called, release the old
    // IDataObject pointer.
    if (m_pDataObj)
    { 
        m_pDataObj->Release(); 
    }
	 
    // If a data object pointer was passed in, save it and
    // extract the file name. 
    if (pDataObj) 
    { 
        m_pDataObj = pDataObj; 
        pDataObj->AddRef(); 
      
        STGMEDIUM   medium;
        FORMATETC   fe = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
        UINT        uCount;

        if(SUCCEEDED(m_pDataObj->GetData(&fe, &medium)))
        {
            // Get the count of files dropped.
            uCount = DragQueryFile((HDROP)medium.hGlobal, (UINT)-1, NULL, 0);

            // Get the first file name from the CF_HDROP.
            if(uCount)
                DragQueryFile((HDROP)medium.hGlobal, 0, m_szFile, 
                              sizeof(m_szFile)/sizeof(TCHAR));

            ReleaseStgMedium(&medium);
        }
    }

    // Duplicate the registry handle. 
    if (hRegKey) 
        RegOpenKeyEx(hRegKey, 
                     NULL, 
                     0L, 
                     MAXIMUM_ALLOWED, 
                     &m_hRegKey); 
    return S_OK; 
}

CSampleExtHandler is the name of the class used to implement the interface. The m_pIDFolder, m_pDataObject, m_szFileName, and m_hRegKey variables are private variables used to store the information that is passed in. For simplicity, this example assumes that only one file name will be held by the data object. After the FORMATETC structure is retrieved from the data object, DragQueryFile is used to extract the file name from the FORMATETC structure's medium.hGlobal member. If a registry key is passed in, the method uses RegOpenKeyEx to open the key and assigns the handle to m_hRegKey.

Infotip Customization

There are two ways to customize infotips. One way is to implement an object that supports IQueryInfo and then register the object under the proper subkey in the registry (see below). Alternatively, you can specify either a fixed string or a list of certain file properties to be displayed.

To display a fixed string for a namespace extension, create a subkey called InfoTip beneath the CLSID key of your namespace extension. Set the data of that subkey to be the string you want to display.

  • HKEY_CLASSES_ROOT
    • CLSID
      • {CLSID}

      • InfoTip = InfoTip string for your namespace extension

To display a fixed string for a file type, create a subkey called InfoTip beneath the ProgID key of the file type you want to supply infotips for. Set the data of that subkey to be the string you want to display.

  • HKEY_CLASSES_ROOT
    • ProgID

    • InfoTip = InfoTip string for all files of this type

If you want the Shell to show certain file properties in the infotip for a specific file type, create a subkey called InfoTip beneath the ProgID key of that file type. Set the data of that subkey to be a semicolon-delineated list of canonical property names or {fmtid}, pid pairs where propname is a canonical property name and {fmtid},pid is a FMTID/PID pair.

  • HKEY_CLASSES_ROOT
    • ProgID

    • InfoTip = propname;propname;{fmtid},pid;{fmtid},pid

The following property names can be used:

Property NameDescriptionRetrieved From
AuthorAuthor of the documentOLE document properties (PIDSI_AUTHOR)
TitleTitle of the documentOLE document properties (PIDSI_TITLE)
SubjectSubject summaryOLE document properties (PIDSI_SUBJECT)
CommentDocument commentsOLE document properties (PIDSI_COMMENT) or folder/drive properties
PageCountNumber of pagesOLE document properties (PIDSI_PAGECOUNT)
NameFriendly nameStandard folder view
OriginalLocationLocation of original fileBriefcase folder and Recycle Bin folder
DateDeletedDate file was deletedRecycle Bin folder
TypeType of fileStandard folder details view
SizeSize of fileStandard folder details view
SyncCopyInSame as OriginalLocationSame as OriginalLocation
ModifiedDate last modifiedStandard folder details view
CreatedDate createdStandard folder details view
AccessedDate last accessedStandard folder details view
InFolderDirectory containing the fileDocument search results
RankQuality of search matchDocument search results
FreeSpaceAvailable storage spaceDisk drives
NumberOfVisitsNumber of visitsFavorites folder
AttributesFile AttributesStandard folder details view
CompanyCompany nameOLE document properties (PIDDSI_COMPANY)
CategoryDocument categoryOLE document properties (PIDDSI_CATEGORY)
CopyrightMedia copyrightOLE document properties (PIDMSI_COPYRIGHT)
HTMLInfoTipFileHTML InfoTip fileDesktop.ini file for folder

Registering Shell Extension Handlers

A Shell extension handler object must be registered before the Shell can use it. This section is a general discussion of how to register a Shell extension handler.

Any time you create or change a Shell extension handler, it is important to notify the system that you have made a change with SHChangeNotify, specifying the SHCNE_ASSOCCHANGED event. If you do not call SHChangeNotify, the change might not be recognized until the system is rebooted.

There are some additional factors that apply to Microsoft Windows NT and Windows 2000 systems. For details, see Registering Shell Extension Handlers on Windows NT and Windows 2000 Systems.

As with all COM objects, you must create a GUID for the handler using a tool such as UUIDGEN.exe. Create a key under HKEY_CLASSES_ROOT\CLSID named as the string form of the GUID. Because Shell extension handlers are in-process servers, you must create an InProcServer32 key under the GUID key with the default value set to the path of the handler's DLL. Use the Apartment threading model.

Any time the Shell takes an action that can involve a Shell extension handler, it checks the appropriate registry key. The key under which an extension handler is registered controls when it will be called. For instance, it is a common practice to call a shortcut menu handler when the Shell displays a shortcut menu for a member of a file class. In this case, the handler must be registered under the file class's ProgID key.

Handler Names

To enable a Shell extension handler, create a subkey with the handler subkey name (see below) under the ShellEx subkey of either the ProgID (for file classes) or the Shell object type name (for predefined_shell_objects).

For example, if you wanted to register a shortcut menu extension handler for MyProgram.1, you would begin by creating the following subkey:

  • HKEY_CLASSES_ROOT
    • MyProgram.1
      • ShellEx
        • ContextMenuHandlers

For the following handlers, create a subkey underneath the "Handler Subkey name" key named as the string version of the CLSID of the Shell extension. Multiple extensions can be registered under the handler subkey name key by creating multiple subkeys. (For backward compatibility with Windows 95, you can also create a key under the hndler subkey name key with a descriptive name and store the string version of the CLSID of the Shell extension as the default value of the key. This older method of registering Shell extensions is deprecated but is described here for comprehensiveness.)

HandlerInterfaceHandler Subkey Name
Column provider handlerIColumnProviderColumnHandlers
Shortcut menu handlerIContextMenuContextMenuHandlers
Copyhook handlerICopyHookCopyHookHandlers
Drag-and-drop handlerIContextMenuDragDropHandlers
Property sheet handlerIShellPropSheetExtPropertySheetHandlers

For the following handlers, the default value of the "Handler Subkey Name" key is the string version of the CLSID of the Shell extension. Only one extension can be registered for these handlers.

HandlerInterfaceHandler Subkey Name
Data handlerIDataObjectDataHandler
Drop handlerIDropTargetDropHandler
Icon handlerIExtractIconA/WIconHandler
Thumbnail image handlerIThumbnailProvider{E357FCCD-A995-4576-B01F-234630154E96}
Infotip handlerIQueryInfo{00021500-0000-0000-C000-000000000046}
Shell link (ANSI )IShellLinkA{000214EE-0000-0000-C000-000000000046}
Shell link (UNICODE)IShellLinkW{000214F9-0000-0000-C000-000000000046}
Structured storageIStorage{0000000B-0000-0000-C000-000000000046}
MetadataIPropertySetStoragePropertyHandler

Predefined Shell Objects

The Shell defines additional objects under HKEY_CLASSES_ROOT which can be extended in the same way as file types. For example, to add a property sheet handler for all files, you can register under the PropertySheetHandlers key.

  • HKEY_CLASSES_ROOT
    • *
      • shellex
        • PropertySheetHandlers

The following table gives the various subkeys of HKEY_CLASSES_ROOT under which extension handlers can be registered. Note that many extension handlers cannot be registered under all of the listed subkeys. For further details, see the specific handler's documentation.

SubkeyDescriptionPossible HandlersVersion
*All filesShortcut Menu, Property Sheet, Verbs (see below)All
AllFileSystemObjectsAll files and file foldersShortcut Menu, Property Sheet, Verbs4.71
FolderAll foldersShortcut Menu, Property Sheet, VerbsAll
DirectoryFile foldersShortcut Menu, Property Sheet, VerbsAll
Directory\BackgroundFile folder backgroundShortcut Menu only4.71
DriveAll drives in MyComputer, such as "C:\"Shortcut Menu, Property Sheet, VerbsAll
NetworkEntire network (under My Network Places)Shortcut Menu, Property Sheet, VerbsAll
Network\Type\#All objects of type # (see below)Shortcut menu, Property Sheet, Verbs4.71
NetShareAll network sharesShortcut menu, Property Sheet, Verbs4.71
NetServerAll network serversShortcut menu, Property Sheet, Verbs4.71
network_provider_nameAll objects provided by network provider "network_provider_name "Shortcut menu, Property Sheet, VerbsAll
PrintersAll printersShortcut Menu, Property SheetAll
AudioCDAudio CD in CD driveVerbs onlyAll
DVDFileDVD drive (Windows 98)Shortcut Menu, Property Sheet, Verbs4.71
DVDDVD drive (Windows 2000)Shortcut Menu, Property Sheet, Verbs4.71

Notes:

  • The file folder background shortcut menu is accessed by right-clicking within a file folder, but not over any of the folder's contents.
  • "Verbs" are special commands registered under HKEY_CLASSES_ROOT\Subkey\Shell\Verb .
  • For Network\Type\# , "#" is a network provider type code in decimal. The network provider type code is the high word of a network type. The list of network types is given in the Winnetwk.h header file (WNNC_NET_* values). For example, WNNC_NET_SHIVA is 0x00330000, so the corresponding type key would be HKEY_CLASSES_ROOT\Network\Type\51 .
  • "network_provider_name " is a network provider name as specified by WNetGetProviderName, with the spaces converted into underscores. For example, if the Microsoft Networking network provider is installed, its provider name is "Microsoft Windows Network", and the corresponding network_provider_name is Microsoft_Windows_Network .

Example of an Extension Handler Registration

To enable a particular handler, create a subkey under the extension handler type key with the name of the handler. The Shell does not use the handler's name, but it must be different from all other names under that type subkey. Set the default value of the name subkey to the string form of the handler's GUID.

The following example illustrates registry entries that enable shortcut menu and property sheet extension handlers, using an example .myp file class.

  • HKEY_CLASSES_ROOT
    • .myp

    • (Default) = MyProgram.1
    • CLSID
      • {00000000-1111-2222-3333-444444444444}
        • InProcServer32

        • (Default) = C:\MyDir\MyCommand.dll
          ThreadingModel = Apartment
      • {11111111-2222-3333-4444-555555555555}
        • InProcServer32

        • (Default) = C:\MyDir\MyPropSheet.dll
          ThreadingModel = Apartment
    • MyProgram.1

    • (Default) = MyProgram Application
      • Shellex
        • ContextMenuHandler
          • MyCommand

          • (Default) = {00000000-1111-2222-3333-444444444444}
        • PropertySheetHandlers
          • MyPropSheet

          • (Default) = {11111111-2222-3333-4444-555555555555}

The registration procedure discussed in this section must be followed for all Windows systems. However, with Windows NT and Windows 2000 systems, an additional step might be necessary:

Registering Shell Extension Handlers on Windows NT and Windows 2000 Systems

Because Windows NT and Windows 2000 systems are designed to be used in a managed environment, installing a Shell extension handler might be somewhat different than for Windows 95 and Windows 98 systems. In particular, access to the registry could be administratively restricted, requiring a somewhat different approach to installation than described in the previous section.

Note  The following discussion applies to both Windows NT and Windows 2000 systems. However, with Windows 2000 and later systems, setup programs should generally not write directly to the registry. Instead, setup should be accomplished with Windows Installer packages. These tools ensure that software runs well under Windows 2000, and provides access to new capabilities, such as per-user class registration.

Shell extension handlers run in the Shell process. Because it is a system process, the administrator of a Windows NT system can limit Shell extension handlers to those on an approved list by setting the EnforceShellExtensionSecurity value of the Explorer key to 1 (one), as shown here.

  • HKEY_CURRENT_USER
    • Software
      • Microsoft
        • Windows
          • CurrentVersion
            • Policies
              • Explorer

              • EnforceShellExtensionSecurity = 1

To place a Shell extension handler on the approved list, create a REG_SZ value whose name is the string form of the handler's GUID under the Approved key.

  • HKEY_LOCAL_MACHINE
    • Software
      • Microsoft
        • Windows
          • CurrentVersion
            • Shell Extensions
              • Approved

The following example adds the MyCommand and MyPropSheet handlers to the approved list.

  • HKEY_LOCAL_MACHINE
    • Software
      • Microsoft
        • Windows
          • CurrentVersion
            • Shell Extensions
              • Approved

              • {00000000-1111-2222-3333-444444444444} = MyCommand
                {11111111-2222-3333-4444-555555555555} = MyPropSheet

The Shell does not use the value that is assigned to the GUID, but it should be set to make inspecting the registry easier.

Your setup application can add values to the Approved key only if the person installing the application has sufficient privileges. If the attempt to add an extension handler fails, you should inform the user that administrative privileges are required to fully install the application. If the handler is essential to the application, you should fail the setup and notify the user to contact an administrator.

While there is no need to add values to the Approved key on Windows 95 or Windows 98 systems, there is no harm in doing so. The system will simply ignore them. However, there is no guarantee that the key will exist on these systems. Your setup program must be able to handle this case.

Community Additions

Show:
© 2014 Microsoft