Question

How can I change or set the category of my shell extension based on this example?

reference screenshot

On the screenshot the extension is in the category More or in german Weitere.

Was it helpful?

Solution

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 designed 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, pszFile, 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 CSampleShellExtension 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.

class CSampleShellExtension : public IPersistFile
{
    // Method declarations not included

    private:
    WCHAR m_szFileName[MAX_PATH];    // The file name
    DWORD m_dwMode;                  // The file access mode
}

IFACEMETHODIMP CSampleShellExtension::GetClassID(__out CLSID *pCLSID)
{
    *pCLSID = CLSID_SampleExtHandler;
}

IFACEMETHODIMP CSampleShellExtension::Load(PCWSTR pszFile, DWORD dwMode)
{
    m_dwMode = dwMode;
    return StringCchCopy(m_szFileName, ARRAYSIZE(m_szFileName), pszFile); 
}

// The implementation sample is continued in the next section.

Implementing IShellExtInit The IShellExtInit interface has only one method, IShellExtInit::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. pidlFolder holds a folder's pointer to an item identifier list (PIDL). This is an absolute PIDL. For property sheet extensions, this value 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 IShellExtInit::Initialize method stores the file name, IDataObject pointer, and registry key as needed for later use. The following code fragment illustrates an implementation of IShellExtInit::Initialize. For simplicity, this example assumes that the data object contains only a single file. In general, the data object might contain multiple files, each of which will need to be extracted.

 // This code continues the CSampleShellExtension sample shown in the
 // "Implementing IPersistFile" section above.

 class CSampleShellExtension : public IShellExtInit {
     // Method declarations not included

     private:
     // IDList of the folder for extensions invoked on the folder, such as 
     // background context menu handlers or nondefault drag-and-drop handlers. 
     PIDLIST_ABSOLUTE m_pidlFolder;

     // The data object contains an expression of the items that the handler is 
     // being initialized for. Use SHCreateShellItemArrayFromDataObject to 
     // convert this object to an array of items. Use SHGetItemFromObject if you
     // are only interested in a single Shell item. If you need a file system
     // path, use IShellItem::GetDisplayName(SIGDN_FILESYSPATH, ...).
     IDataObject *m_pdtobj;

     // For context menu handlers, the registry key provides access to verb 
     // instance data that might be stored there. This is a rare feature to use 
     // so most extensions do not need this variable.
     HKEY m_hRegKey;              }
      // This method must be very efficient. Do not do any unnecessary work here.  
    // Use Initialize to acquire resources that will be used later.
     IFACEMETHODIMP CSampleShellExtension::Initialize(__in_opt  PCIDLIST_ABSOLUTEpidlFolder,__in_opt IDataObject *pDataObject, __in_opt HKEY hRegKey)  
    { 
     // In some cases,handlers are initialized multiple times. Therefore, 
     // clear any previous state here.
     CoTaskMemFree(m_pidlFolder);
     m_pidlFolder = NULL;

     if (m_pdtobj)
     { 
         m_pdtobj->Release(); 
     }

     if (m_hRegKey)
     {
         RegCloseKey(m_hRegKey);
         m_hRegKey = NULL;
     }

     // Capture the inputs for use later.
     HRESULT hr = S_OK;

     if (pidlFolder)
     {
         m_pidlFolder = ILClone(pidlFolder);   // Make a copy to use later.
         hr = m_pidlFolder ? S_OK : E_OUTOFMEMORY;
     }

     if (SUCCEEDED(hr))
     {
         // If a data object pointer was passed into the method, save it and
         // extract the file name. 
         if (pDataObject) 
         { 
             m_pdtobj = pDataObject; 
             m_pdtobj->AddRef(); 
         }

         // It is uncommon to use the registry handle, but if you need it,
         // duplicate it now.
         if (hRegKey)
         {
             LSTATUS const result = RegOpenKeyEx(hRegKey, NULL, 0, KEY_READ, &m_hRegKey); 
             hr = HRESULT_FROM_WIN32(result);
         }
     }

     return hr; }

Any time you create or change a Shell extension handler, it is important to notify the system that you have made a change. Do so by calling 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 Windows 2000 systems. For details, see the Registering Shell Extension Handlers on Windows 2000 Systems section. As with all Component Object Model (COM) objects, you must create a GUID for the handler using a tool such as Guidgen.exe, which is provided with the Windows Software Development Kit (SDK). Create a subkey under HKEY_CLASSES_ROOT\CLSID whose name is the string form of that GUID. Because Shell extension handlers are in-process servers, you also must create an InprocServer32 subkey under that GUID subkey with the (Default) value set to the path of the handler's DLL. Use the apartment threading model. An example is shown here:

 HKEY_CLASSES_ROOT    CLSID
       {00021500-0000-0000-C000-000000000046}
          InprocServer32
             (Default) = %windir%\System32\Example.dll
             ThreadingModel = Apartment

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top