How to Register and Implement a Property Sheet Handler for a File Type

When the user right-clicks a member of a file type to display the Properties property sheet, the Shell calls the property sheet handlers that are registered for the file type. Each handler can add one custom page to the default property sheet.

What you need to know

Technologies

  • Shell

Prerequisites

  • An understanding of shortcut menus

Instructions

Step 1: Registering a Property Sheet Handler for a File Type

In addition to normal Component Object Model (COM) registration, add a PropertySheetHandlers subkey to the shellex subkey of the ProgID key of the application associated with the file type. Create a subkey of PropertySheetHandlers with the handler's name, and set the default value to the string form of the property sheet handler's class identifier (CLSID) GUID.

To add more than one page to the property sheet, register a handler for each page. The maximum number of pages that a property sheet can support is 32. To register multiple handlers, create a key under the shellex key for each handler, with the default value set to the handler's CLSID GUID. It is not necessary to create a distinct object for each handler, which means that multiple handlers can all have the same GUID value. The pages will be displayed in the order that their keys are listed under shellex.

The following example illustrates a registry entry that enables two property sheet extension handlers for an example .myp file type. In this example, a separate object is used for each page, but a single object could also be used for both.

HKEY_CLASSES_ROOT
   .myp
      (Default) = MyProgram.1
   CLSID
      {Page 1 Property Sheet Handler CLSID GUID}
         InProcServer32
            (Default) = C:\MyDir\MyPropSheet1.dll
            ThreadingModel = Apartment
      {Page 2 Property Sheet Handler CLSID GUID}
         InProcServer32
            (Default) = C:\MyDir\MyPropSheet2.dll
            ThreadingModel = Apartment
   MyProgram.1
      (Default) = MyProgram Application
      shellex
         PropertySheetHandlers
            MyPropSheet1
               (Default) = {Page1 Property Sheet Handler CLSID GUID}
            MyPropSheet2
               (Default) = {Page2 Property Sheet Handler CLSID GUID}

Step 2: Implementing a Property Sheet Handler for a File Type

In addition to the general implementation discussed in How Property Sheet Handlers Work, a property sheet handler for a file type must also have an appropriate implementation of the IShellPropSheetExt interface. Only the IShellPropSheetExt::AddPages method needs a nontoken implementation. The Shell does not call IShellPropSheetExt::ReplacePage.

The IShellPropSheetExt::AddPages method allows a property sheet handler to add a page to a property sheet. The method has two input parameters. The first, lpfnAddPage, is a pointer to an AddPropSheetPageProc callback function that is used to provide the Shell with the information needed to add the page to the property sheet. The second, lParam, is a Shell-defined value that is not processed by the handler. It is simply passed back to the Shell when the callback function is called.

The general procedure for implementing AddPages is as follows.

Implementing the AddPages Method

  1. Assign appropriate values to the members of a PROPSHEETPAGE structure. In particular:
    • Assign the variable that holds the handler's reference count to the pcRefParent member. This practice prevents the handler object from being unloaded while the property sheet is still being displayed.
    • You can also implement a PropSheetPageProc callback function and assign its pointer to a pfnCallback member. This function is called when the page is created and when it is about to be destroyed.
  2. Create the page's HPAGE handle by passing the PROPSHEETPAGE structure to the CreatePropertySheetPage function.
  3. Call the function that is pointed to by lpfnAddPage. Set its first parameter to the HPAGE handle that was created in the previous step. Set its second parameter to the lParam value that was passed in to AddPages by the Shell.
  4. Any messages associated with the page will be passed to the dialog box procedure that was assigned to the pfnDlgProc member of the PROPSHEETPAGE structure.
  5. If you assigned a PropSheetPageProc callback function to pfnCallback, it will be called when the page is about to be destroyed. Your handler can then perform any needed cleanup operations, such as releasing any references that it holds.

The following code sample illustrates a simple AddPages implementation.

STDMETHODIMP CShellPropSheetExt::AddPages(LPFNADDPROPSHEETPAGE, lpfnAddPage, LPARAM lParam)
{
    PROPSHEETPAGE  psp;
    HPROPSHEETPAGE hPage;

    psp.dwSize        = sizeof(psp);
    psp.dwFlags       = PSP_USEREFPARENT | PSP_USETITLE | PSP_USECALLBACK;
    psp.hInstance     = g_hInst;
    psp.pszTemplate   = MAKEINTRESOURCE(IDD_PAGEDLG);
    psp.hIcon         = 0;
    psp.pszTitle      = TEXT("Extension Page");
    psp.pfnDlgProc    = (DLGPROC)PageDlgProc;
    psp.pcRefParent   = &g_DllRefCount;
    psp.pfnCallback   = PageCallbackProc;
    psp.lParam        = (LPARAM)this;

    hPage = CreatePropertySheetPage(&psp);
            
    if(hPage) 
    {
        if(lpfnAddPage(hPage, lParam))
        {
            this->AddRef();
            return S_OK;
        }
        else
        {
            DestroyPropertySheetPage(hPage);
        }
    }
    else
    {
        return E_OUTOFMEMORY;
    }
    return E_FAIL;
}

The g_hInst variable is the instance handle to the DLL, and IDD_PAGEDLG is the resource ID of the page's dialog box template. The PageDlgProc function is the dialog box procedure that handles the page's messages. The g_DllRefCount variable holds the object's reference count. The AddPages method calls AddRef to increment the count. However, the reference count is released by the callback function, PageCallbackProc, when the page is about to be destroyed.

Remarks

For a general discussion of how to register Shell extension handlers, see Creating Shell Extension Handlers.

IShellPropSheetExt