如何注册和实现文件类型的属性表处理程序

当用户右键单击某个文件类型的成员以显示“属性”属性表时,Shell 会调用为该文件类型注册的属性表处理程序。 每个处理程序可以向默认属性表添加一个自定义页。

需要了解的事项

技术

  • Shell

先决条件

  • 了解快捷菜单

Instructions

步骤 1:为文件类型注册属性表处理程序

除了正常组件对象模型 (COM) 注册外,还向与文件类型关联的应用程序的 ProgID 键的 shellex 子项添加 PropertySheetHandlers 子项。 使用处理程序的名称创建 PropertySheetHandlers 的子项,并将默认值设置为属性表处理程序的类标识符的字符串形式 (CLSID) GUID。

若要向属性表添加多个页面,请为每个页面注册一个处理程序。 属性表可支持的最大页数为 32。 若要注册多个处理程序,请在每个处理程序的 shellex 键下创建一个键,默认值设置为处理程序的 CLSID GUID。 无需为每个处理程序创建不同的对象,这意味着多个处理程序都可以具有相同的 GUID 值。 页面将按其键在 shellex 下列出的顺序显示。

以下示例演示了一个注册表项,该注册表项为示例 .myp 文件类型启用两个属性表扩展处理程序。 在此示例中,每个页面使用一个单独的 对象,但也可以将单个对象用于这两个页面。

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}

步骤 2:实现文件类型的属性表处理程序

除了 属性表处理程序的工作原理中讨论的常规实现外,文件类型的属性表处理程序还必须具有 IShellPropSheetExt 接口的适当实现。 只有 IShellPropSheetExt::AddPages 方法需要非ken 实现。 Shell 不调用 IShellPropSheetExt::ReplacePage

IShellPropSheetExt::AddPages 方法允许属性表处理程序将页面添加到属性表。 方法有两个输入参数。 第一个 lpfnAddPage 是指向 AddPropSheetPageProc 回调函数的指针,该回调函数用于向 Shell 提供将页面添加到属性表所需的信息。 第二个 lParam 是 Shell 定义的值,不由处理程序处理。 调用回调函数时,它只是传递回 Shell。

实现 AddPages 的 一般过程如下所示。

实现 AddPages 方法

  1. 将适当的值分配给 PROPSHEETPAGE 结构的成员。 具体而言:
    • 将保存处理程序引用计数的变量分配给 pcRefParent 成员。 这种做法可防止在仍显示属性表时卸载处理程序对象。
    • 还可以实现 PropSheetPageProc 回调函数,并将其指针分配给 pfnCallback 成员。 创建页面时和即将销毁页面时,将调用此函数。
  2. 通过将 PROPSHEETPAGE 结构传递给 CreatePropertySheetPage 函数来创建页面的 HPAGE 句柄。
  3. 调用 lpfnAddPage 指向的函数。 将其第一个参数设置为在上一步中创建的 HPAGE 句柄。 将其第二个参数设置为 Shell 传递到 AddPageslParam 值。
  4. 与页面关联的任何消息都将传递到分配给 PROPSHEETPAGE 结构的 pfnDlgProc 成员的对话框过程。
  5. 如果将 PropSheetPageProc 回调函数分配给 pfnCallback,则会在页面即将销毁时调用该回调函数。 然后,处理程序可以执行任何所需的清理操作,例如释放它保留的任何引用。

以下代码示例演示了一个简单的 AddPages 实现。

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;
}

g_hInst变量是 DLL 的实例句柄,IDD_PAGEDLG是页面对话框模板的资源 ID。 PageDlgProc 函数是处理页面消息的对话框过程。 g_DllRefCount变量保存对象的引用计数。 AddPages 方法调用 AddRef 以递增计数。 但是,当页面即将被销毁时,引用计数由回调函数 PageCallbackProc 释放。

备注

有关如何注册 Shell 扩展处理程序的一般讨论,请参阅 创建 Shell 扩展处理程序

IShellPropSheetExt