创建快捷菜单处理程序

快捷菜单处理程序(也称为上下文菜单处理程序或谓词处理程序)是文件类型处理程序的类型。 这些处理程序可以通过某种方式实现,导致它们加载在其自己的进程或资源管理器或其他第三方进程中。 创建进程内处理程序时请小心,因为它们可能会对加载它们的进程造成损害。

注意

注册在 32 位应用程序的上下文中工作的处理程序时,64 位版本的 Windows 有一些特殊注意事项:在应用程序不同位的上下文中调用时,WOW64 子系统将文件系统访问重定向到某些路径。 如果 .exe 处理程序存储在其中一个路径中,则在此上下文中无法访问它。 因此,解决方法是将 .exe 存储在未重定向的路径中,或存储启动实际版本的 .exe 的存根版本。

本主题的组织方式如下:

规范谓词

应用程序通常负责为所定义的谓词提供本地化的显示字符串。 但是,为了提供一定程度的语言独立性,系统定义了一组常用的谓词,称为规范谓词。 规范谓词永远不会向用户显示,并且可用于任何 UI 语言。 系统使用规范名称自动生成正确本地化的显示字符串。 例如,打开谓词的显示字符串设置为英语系统上的“打开,并设置为德语系统上的德语等效项。

规范谓词 说明
打开 打开文件或文件夹。
Opennew 在新窗口中打开文件或文件夹。
打印 打印文件。
Printto 允许用户通过将文件拖动到打印机对象来打印文件。
探究 打开 Windows 资源管理器,其中选择了文件夹。
属性 打开对象的属性表。

注意

Printto 谓词也是规范的,但它永远不会显示。 其包含使用户能够通过将其拖动到打印机对象来打印文件。

快捷菜单处理程序可以通过 IContextMenu::GetCommandStringGCS_VERBWGCS_VERBA提供自己的规范谓词。 系统将使用规范谓词作为传递给 ShellExecute 的第二个参数(lpOperation),并且是 CMINVOKECOMMANDINFO传递给 IContextMenu::InvokeCommand 方法的 lpVerb 成员。

扩展谓词

当用户右键单击对象时,快捷菜单将显示默认谓词。 你可能希望在每个快捷菜单上不显示的某些快捷菜单上添加和支持命令。 例如,你可能具有不常用的命令,或者这些命令适用于有经验的用户。 因此,还可以定义一个或多个扩展谓词。 这些谓词类似于普通谓词,但通过注册谓词的方式与普通谓词区分开来。 若要有权访问扩展谓词,用户必须在按 Shift 键时右键单击对象。 当用户执行此操作时,除了默认谓词外,还会显示扩展谓词。

可以使用注册表定义一个或多个扩展谓词。 仅当用户右键单击某个对象的同时按下 SHIFT 键时,才会显示关联的命令。 若要将谓词定义为扩展,请将“extended” REG_SZ 值添加到谓词的子项。 该值不应包含与之关联的任何数据。

仅编程访问谓词

这些谓词永远不会显示在上下文菜单中。 可以使用 ShellExecuteEx 并指定 pExecInfo 参数的 lpVerb 字段(SHELLEXECUTEINFO 对象)来访问这些字段 若要仅将谓词定义为编程访问,请将“ProgrammaticAccessOnly” REG_SZ 值添加到谓词的子项。 该值不应包含与之关联的任何数据。

可以使用注册表定义一个或多个扩展谓词。 仅当用户右键单击某个对象的同时按下 SHIFT 键时,才会显示关联的命令。 若要将谓词定义为扩展,请将“extended” REG_SZ 值添加到谓词的子项。 该值不应包含与之关联的任何数据。

使用静态谓词自定义快捷菜单

为快捷菜单选择静态或动态谓词后,可以通过为文件类型注册静态谓词来扩展文件类型的快捷菜单。 为此,请在与文件类型关联的应用程序的 ProgID 的子项下面添加 Shell 子项。 (可选)可以通过将其设为 Shell 子项的默认值来定义文件类型的默认谓词。

默认谓词首先显示在快捷菜单上。 其用途是向 Shell 提供它在调用 ShellExecuteEx 函数时可以使用的谓词,但未指定谓词。 使用 ShellExecuteEx,Shell 不一定选择默认谓词。

Shell 按以下顺序使用第一个可用谓词:

  1. 默认谓词
  2. 注册表中的第一个谓词(如果指定谓词顺序)
  3. Open 谓词
  4. Open With 谓词

如果列出的谓词均不可用,操作将失败。

为要在 Shell 子项下添加的每个谓词创建一个子项。 每个子项都必须将 REG_SZ 值设置为谓词的显示字符串(本地化字符串)。 对于每个谓词子项,请创建一个命令子项,其默认值设置为用于激活项的命令行。 对于规范谓词(如 OpenPrint),可以省略显示字符串,因为系统会自动显示正确本地化的字符串。 对于非规范谓词,如果省略显示字符串,则会显示谓词字符串。

在以下注册表示例中,请注意:

  • 由于 Doit 不是规范谓词,因此会为其分配显示名称,可通过按 D 键来选择该名称。
  • Printto 谓词不会显示在快捷菜单上。 但是,它包含在注册表中后,用户可以通过在打印机图标上删除文件来打印文件。
  • 为每个谓词显示一个子项。 %1 表示文件名和 %2 打印机名称。
HKEY_CLASSES_ROOT
   .myp-ms
      (Default) = MyProgram.1
   MyProgram.1
      (Default) = My Program Application
      Shell
         (Default) = doit
         doit
            (Default) = &Do It
            command
               (Default) = c:\MyDir\MyProgram.exe /d "%1"
         open
            command
               (Default) = c:\MyDir\MyProgram.exe /d "%1"
         print
            command
               (Default) = c:\MyDir\MyProgram.exe /p "%1"
         printto
            command
               (Default) = c:\MyDir\MyProgram.exe /p "%1" "%2"

下图根据上面的注册表项说明了快捷菜单的扩展。 此快捷菜单在其菜单上具有 “打开”、“ 执行”“打印 谓词”,其中 “执行” 作为默认谓词。

执行默认谓词快捷菜单的屏幕截图

使用 IDropTarget 接口激活处理程序

动态数据交换 (DDE) 已弃用;请改用 IDropTarget IDropTarget 更可靠,并且具有更好的激活支持,因为它使用处理程序的 COM 激活。 对于多项选择,IDropTarget 不受 DDE 和 CreateProcess 中找到的缓冲区大小限制的约束。 此外,项作为数据对象传递给应用程序,该对象可以使用 SHCreateShellItemArrayFromDataObject 函数转换为项数组 这样做更简单,并且当项转换为命令行或 DDE 协议的路径时,不会丢失命名空间信息。

有关文件关联属性的 IDropTarget 和 Shell 查询的详细信息,请参阅感知类型和应用程序注册

指定静态谓词的位置和顺序

通常,谓词根据枚举方式在快捷菜单上排序;枚举首先基于关联数组的顺序,然后基于关联数组中项的顺序,由注册表的排序顺序定义。

可以通过为关联项指定 Shell 子项的默认值来排序谓词。 此默认值可以包含单个项,该项将显示在快捷菜单的顶部位置,或者用空格或逗号分隔的项列表。 在后一种情况下,列表中的第一个项是默认项,其他谓词以指定的顺序紧邻其下方显示。

例如,以下注册表项按以下顺序生成快捷菜单谓词:

  1. 显示
  2. 产品
  3. 个性化
HKEY_CLASSES_ROOT
   DesktopBackground
      Shell
         Display
         Gadgets
         Personalization

同样,以下注册表项按以下顺序生成快捷菜单谓词:

  1. 个性化
  2. 产品
  3. 显示
HKEY_CLASSES_ROOT
   DesktopBackground
      Shell = "Personalization,Gadgets"
      Display

将谓词定位在菜单顶部或底部

以下注册表属性可用于将谓词放置在菜单的顶部或底部。 如果有多个谓词指定此属性,则最后一个要执行此操作的谓词获得优先级:

Position=Top | Bottom 

创建静态级联菜单

在 Windows 7 及更高版本中,通过注册表设置支持级联菜单实现。 在 Windows 7 之前,只能通过 IContextMenu 接口的实现创建级联菜单。 在 Windows 7 及更高版本中,仅当静态方法不足时,才应使用基于 COM 代码的解决方案。

以下屏幕截图提供了级联菜单的示例。

显示级联菜单示例的屏幕截图

在 Windows 7 及更高版本中,有三种方法可以创建级联菜单:

使用 SubCommands 注册表项创建级联菜单

在 Windows 7 及更高版本中,可以使用 SubCommands 条目通过以下过程创建级联菜单。

使用 SubCommands 条目创建级联菜单

  1. 在 HKEY_CLASSES_ROOT\ProgID\shell创建子项来表示级联菜单。 在此示例中,我们将此子项命名为 CascadeTest。 确保 CascadeTest 子项的默认值为空,并显示为(未设置值)。

    HKEY_CLASSES_ROOT
       *
          shell
             CascadeTest
                (Default)
    
  2. 对于 CascadeTest 子项,请添加类型为 REG_SZMUIVerb 条目,并为其分配将在快捷菜单上显示为其名称的文本。 在此示例中,我们将它分配为“测试级联菜单”。

    HKEY_CLASSES_ROOT
       *
          shell
             CascadeTest
                (Default)
                MUIVerb = Test Cascade Menu
    
  3. 在 CascadeTest 子项中,添加一个类型为REG_SZSubCommands 条目,该条目由分号分隔的应按外观顺序显示在菜单上的谓词。 例如,此处我们分配了许多系统提供的谓词:

    HKEY_CLASSES_ROOT
       *
          Shell
             CascadeTest
                SubCommands
                Windows.delete;Windows.properties;Windows.rename;Windows.cut;Windows.copy;Windows.paste
    
  4. 对于自定义谓词,请使用任何静态谓词实现方法实现它们,并在 CommandStore 子项下列出它们,如此示例中虚构谓词 VerbName 所示:

    HKEY_LOCAL_MACHINE
       Software
          Microsoft
             Windows
                CurrentVersion
                   Explorer
                      CommandStore
                         Shell
                            VerbName
                            command
                               (Default) = notepad.exe %1
    

注意

此方法的优点是,可以通过在 SubCommands 条目下列出谓词名称来注册自定义谓词一次并重复使用。 但是,它要求应用程序有权在HKEY_LOCAL_MACHINE修改注册表。

 

使用 ExtendedSubCommandsKey 注册表项创建级联菜单

在 Windows 7 及更高版本中,可以使用 ExtendedSubCommandKey 条目创建扩展级联菜单:级联菜单中的级联菜单。

以下屏幕截图是扩展级联菜单的示例。

显示设备的扩展级联菜单的屏幕截图

由于HKEY_CLASSES_ROOT是HKEY_CURRENT_USERHKEY_LOCAL_MACHINE的组合,因此可以在HKEY_CURRENT_USER\软件\子项下注册任何自定义谓词。 这样做的主要优点是不需要提升的权限。 此外,其他文件关联还可以通过指定相同的 ExtendedSubCommandsKey 子项来重复使用整个谓词集。 如果不需要重复使用这组谓词,则可以在父级下列出谓词,但确保父级的默认值为空。

使用 ExtendedSubCommandsKey 条目创建级联菜单

  1. 在 HKEY_CLASSES_ROOT\ProgID\shell创建子项来表示级联菜单。 在此示例中,我们将此子项命名为 CascadeTest2。 确保 CascadeTest 子项的默认值为空,并显示为(未设置值)。

    HKEY_CLASSES_ROOT
       *
          shell
             CascadeTest2
                (Default)
    
  2. 对于 CascadeTest 子项,请添加类型为 REG_SZMUIVerb 条目,并为其分配将在快捷菜单上显示为其名称的文本。 在此示例中,我们将它分配为“测试级联菜单”。

    HKEY_CLASSES_ROOT
       *
          shell
             CascadeTest
                (Default)
                MUIVerb = Test Cascade Menu 2
    
  3. 已创建的 CascadeTest 子项下,添加 ExtendedSubCommandsKey 子项,然后添加文档子命令( REG_SZ 类型);例如:

    HKEY_CLASSES_ROOT
       txtfile
          Shell
             Test Cascade Menu 2
                (Default)
                ExtendedSubCommandsKey
                   Layout
                   Properties
                   Select all
    

    确保测试级联菜单 2 子项的默认值为空,并显示为(未设置值)。

  4. 使用以下任何静态谓词实现填充子项。 请注意,CommandFlags 子项表示 EXPCMDFLAGS 值。 如果要在级联菜单项之前或之后添加分隔符,请使用ECF_SEPARATORBEFORE(0x20)或ECF_SEPARATORAFTER(0x40)。 有关这些 Windows 7 及更高版本的标志的说明,请参阅 IExplorerCommand::GetFlags ECF_SEPARATORBEFORE仅适用于顶级菜单项。 MUIVerb 的类型 为 REG_SZ,CommandFlags 的类型 为 REG_DWORD

    HKEY_CLASSES_ROOT
       txtile
          Shell
             Test Cascade Menu 2
                (Default)
                ExtendedSubCommandsKey
                   Shell
                      cmd1
                         MUIVerb = Notepad
                         command
                            (Default) = %SystemRoot%\system32\notepad.exe %1
                      cmd2
                         MUIVerb = Wordpad
                         CommandFlags = 0x20
                         command
                            (Default) = "C:\Program Files\Windows NT\Accessories\wordpad.exe" %1
    

以下屏幕截图显示了前面的注册表项条目示例。

显示级联菜单示例的屏幕截图,其中显示了记事本和写字板选项

使用 IExplorerCommand 接口创建级联菜单

将谓词添加到级联菜单的另一个选项是通过 IExplorerCommand::EnumSubCommands 此方法允许通过 IExplorerCommandProvider 提供命令模块命令的数据源将这些命令用作快捷菜单上的谓词。 在 Windows 7 及更高版本中,可以使用 IExplorerCommand 提供与 IContextMenu 相同的谓词实现

以下两个屏幕截图演示了“设备”文件夹中级联菜单的使用。

显示设备文件夹中级联菜单示例的屏幕截图。

以下屏幕截图演示了“设备”文件夹中级联菜单的另一个实现。

显示设备文件夹中级联菜单示例的屏幕截图

注意

由于 IExplorerCommand 仅支持进程内激活,因此建议由需要共享命令和快捷菜单之间的实现的 Shell 数据源使用。

 

使用高级查询语法获取静态谓词的动态行为

高级查询语法(AQS)可以表示一个条件,该条件将使用正在实例化谓词的项中的属性进行评估。 此系统仅适用于快速属性。 这些属性是 Shell 数据源通过不从 IShellFolder2::GetDefaultColumnState 返回SHCOLSTATE_SLOW来快速报告的属性。

Windows 7 及更高版本支持避免本地化版本的问题的规范值。 本地化版本需要以下规范语法才能利用此 Windows 7 增强功能。

System.StructuredQueryType.Boolean#True

在以下示例注册表项中:

  • AppliesTo 值控制谓词是显示还是隐藏。
  • DefaultAppliesTo 值控制哪个谓词是默认值。
  • HasLUAShield 值控制是否显示用户帐户控制(UAC)防护。

在此示例中, DefaultAppliesTo 值使此谓词成为任何文件名中带有单词“exampleText1”的文件的默认值。 AppliesTo 值为名称中带有“exampleText1”的任何文件启用谓词。 HasLUAShield 值显示名称中带有“exampleText2”的文件的盾牌。

HKEY_CLASSES_ROOT
   txtile
      shell
         test.verb
            DefaultAppliesTo = System.ItemName:"exampleText1"
            HasLUAShield = System.ItemName:"exampleText2"
            AppliesTo = System.ItemName:"exampleText1"

添加 Command 子项和值:

HKEY_CLASSES_ROOT
   txtile
      shell
         test.verb
            Command
               (Default) = %SystemRoot%\system32\notepad.exe %1

在 Windows 7 注册表中,请参阅HKEY_CLASSES_ROOT\驱动器作为采用以下方法的 bitlocker 谓词示例:

  • AppliesTo = System.Volume.BitlockerProtection:=2
  • System.Volume.BitlockerRequiresAdmin:=System.StructuredQueryType.Boolean#True

有关 AQS 的详细信息,请参阅 高级查询语法

已弃用:将谓词与动态数据 Exchange 命令关联

DDE 已弃用;请改用 IDropTarget DDE 已弃用,因为它依赖于广播窗口消息来发现 DDE 服务器。 DDE 服务器挂起会停止广播窗口消息,从而挂起其他应用程序的 DDE 对话。 单个停滞的应用程序通常会在用户体验中导致后续挂起。

IDropTarget 方法更可靠,并且具有更好的激活支持,因为它使用处理程序的 COM 激活。 对于多项选择,IDropTarget 不受 DDE 和 CreateProcess 中找到的缓冲区大小限制的约束。 此外,项作为数据对象传递给应用程序,该对象可以使用 SHCreateShellItemArrayFromDataObject 函数转换为项数组 这样做更简单,并且当项转换为命令行或 DDE 协议的路径时,不会丢失命名空间信息。

有关文件关联属性的 IDropTarget 和 Shell 查询的详细信息,请参阅感知类型和应用程序注册

完成谓词实现任务

实现谓词的以下任务与静态和动态谓词实现相关。 有关动态谓词的详细信息,请参阅 使用动态谓词自定义快捷菜单。

自定义预定义 Shell 对象的快捷菜单

许多预定义的 Shell 对象都有可自定义的快捷菜单。 以注册典型文件类型的方式注册命令,但使用预定义对象的名称作为文件类型名称。

预定义对象的列表位于“创建 Shell 扩展处理程序预定义 Shell 对象”部分中。 可通过在注册表中添加谓词来自定义其快捷菜单的预定义 Shell 对象在表中标记了谓词谓词。

扩展新子菜单

当用户在 Windows 资源管理器中打开 “文件 ”菜单时,显示的命令之一是 “新建”。 选择此命令将显示子菜单。 默认情况下,子菜单包含两个命令“ 文件夹 ”和 “快捷方式”,使用户能够创建子文件夹和快捷方式。 此子菜单可以扩展为包含任何文件类型的文件创建命令。

若要将文件创建命令添加到 “新建 ”子菜单,应用程序的文件必须具有关联的文件类型。 在文件名下包括 ShellNew 子项。 选择“文件”菜单的“新建”命令时,Shell 会将文件类型添加到“新建”子菜单。 命令的显示字符串是分配给程序的 ProgID 的描述性字符串。

若要指定文件创建方法,请将一个或多个数据值分配给 ShellNew 子项。 下表中列出了可用值。

ShellNew 子项值 说明
命令 执行应用程序。 此 REG_SZ 值指定要执行的应用程序的路径。 例如,可以将它设置为启动向导。
Data 创建包含指定数据的文件。 此 REG_BINARY 值指定文件的数据。 如果指定了 NullFileFileName,则忽略数据
FileName 创建一个文件,该文件是指定文件的副本。 此 REG_SZ 值指定要复制的文件的完全限定路径。
NullFile 创建一个空文件。 NullFile 未分配值。 如果 指定 NullFile ,则 忽略 DataFileName 注册表值。

 

以下注册表项示例和屏幕截图演示了 .myp-ms 文件类型的新子菜单。 它有一个命令 MyProgram 应用程序

HKEY_CLASSES_ROOT
   .myp
      (Default) = MyProgram.1
      MyProgram.1
         ShellNew
         NullFile

屏幕截图演示 了“新建 ”子菜单。 当用户从“新建”子菜单选择 MyProgram 应用程序时,Shell 将创建名为 New MyProgram Application.myp-ms 的文件,并将其传递给MyProgram.exe

窗口资源管理器的屏幕截图,其中显示了“new”子菜单上的新“myprogram 应用程序”命令

创建拖放处理程序

实现拖放处理程序的基本过程与常规快捷菜单处理程序相同。 但是,快捷菜单处理程序通常只使用传递给处理程序的 IShellExtInit::Initialize 方法的 IDataObject 指针来提取对象的名称。 拖放处理程序可以实现更复杂的数据处理程序来修改拖动对象的行为。

当用户右键单击 Shell 对象以拖动对象时,当用户尝试删除该对象时,将显示快捷菜单。 以下屏幕截图演示了典型的拖放快捷菜单。

拖放快捷菜单的屏幕截图

拖放处理程序是一个快捷菜单处理程序,可将项添加到此快捷菜单。 拖放处理程序通常在以下子项下注册。

HKEY_CLASSES_ROOT
   Directory
      shellex
         DragDropHandlers

在为拖放处理程序命名的 DragDropHandlers 子项下添加一个子项,并将子项的默认值设置为处理程序的类标识符 (CLSID) GUID 的字符串形式。 以下示例启用 MyDD 拖放处理程序。

HKEY_CLASSES_ROOT
   Directory
      shellex
         DragDropHandlers
            MyDD
               (Default) = {MyDD CLSID GUID}

禁止动词和控制可见性

可以使用 Windows 策略设置来控制谓词可见性。 通过向谓词的注册表子项添加 SuppressPolicy 值或 SuppressPolicyEx GUID 值,可以通过策略设置取消谓词。 将 SuppressionPolicy 子项的值设置为策略 ID。 如果启用策略,则会取消谓词及其关联的快捷菜单项。 有关可能的策略 ID 值,请参阅 RESTRICTIONS 枚举。

使用动词选择模型

必须为谓词设置注册表值,以处理用户可以从项中选择单个项、多个项或选择的情况。 谓词需要针对谓词支持的这三种情况中的每一个单独注册表值。 谓词选择模型的可能值如下所示:

  • 为所有谓词指定 MultiSelectModel 值。 如果未指定 MultiSelectModel 值,则会根据所选谓词实现的类型推断出该值。 对于基于 COM 的方法(如 DropTarget 和 ExecuteCommand), 假定使用其他 方法 Document
  • 为仅支持单个选择的谓词指定 Single
  • 为支持任意数量的项的谓词指定 Player
  • 为为每个项目创建顶级窗口的谓词指定 文档 。 这样做会限制激活的项数,并帮助避免在用户打开过多窗口时耗尽系统资源。

当所选项数与谓词选择模型不匹配或大于下表中概述的默认限制时,该谓词将无法显示。

谓词实现的类型 Document 玩家
旧的 15 个项目 100 个项目
COM 15 个项目 无限制

 

下面是使用 MultiSelectModel 值的示例注册表项。

HKEY_CLASSES_ROOT
   Folder
      shell
         open
             = MultiSelectModel = Document
HKEY_CLASSES_ROOT
   ProgID
      shell
         verb
             = MultiSelectModel = Single | Document | Player

使用项属性

可以测试项目的 Shell 属性的 SFGAO 标志值,以确定是否应启用或禁用谓词。

若要使用此属性功能,请在谓词下添加以下 REG_DWORD 值:

在以下示例注册表项中,AttributeMask 设置为 SFGAO_READONLY (0x40000)。

HKEY_CLASSES_ROOT
   txtfile
      Shell
         test.verb2
            AttributeMask = 0x40000
            AttributeValue = 0x0
            ImpliedSelectionModel = 0x0
            command
               (Default) = %SystemRoot%\system32\notepad.exe %1

通过Desktop.ini实现文件夹的自定义谓词

在 Windows 7 及更高版本中,可以通过Desktop.ini向文件夹添加谓词。 有关Desktop.ini文件的详细信息,请参阅 如何使用Desktop.ini自定义文件夹。

注意

Desktop.ini文件应始终标记为系统 + 隐藏,以便不会向用户显示它们。

 

若要通过Desktop.ini文件为文件夹添加自定义谓词,请执行以下步骤:

  1. 创建标记为 只读系统的文件夹。

  2. 创建包含 [的Desktop.ini文件。ShellClassInfo] DirectoryClass=Folder ProgID。

  3. 在注册表中创建具有\CanUseForDirectory 值的HKEY_CLASSES_ROOT Folder ProgID。 CanUseForDirectory 值可避免滥用设置为不参与通过Desktop.ini实现文件夹的自定义谓词的 ProgID。

  4. FolderProgID 子项下添加谓词,例如:

    HKEY_CLASSES_ROOT
       CustomFolderType
          Shell
             MyVerb
                command
                   (Default) = %SystemRoot%\system32\notepad.exe %1\desktop.ini
    

注意

这些谓词可以是默认谓词,在这种情况下,双击该文件夹会激活谓词。

 

快捷菜单处理程序和多个谓词的最佳做法

为快捷菜单选择静态或动态谓词

使用动态谓词自定义快捷菜单

快捷(上下文)菜单和快捷菜单处理程序

谓词和文件关联

快捷菜单参考