创建快捷菜单处理程序

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

注意

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

本主题的组织方式如下:

规范谓词

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

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

注意

Printtoverb 也是标准的,但它从不显示。 其包含使用户能够通过将其拖动到打印机对象来打印文件。

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

扩展谓词

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

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

仅编程访问谓词

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

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

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

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

默认值 verb 首先显示在快捷菜单上。 其用途是在调用函数 ShellExecuteEx 时提供一个 Shellverb,以便在未指定 verb 时可以使用。 使用此方式调用 ShellExecuteEx 时,Shell 不一定会选择verb作为默认选项。

按下列顺序,Shell 使用第一个可用 verb。

  1. 默认值 verb
  2. 注册表中的第一个 verb ,如果 verb 指定了订单
  3. Openverb
  4. Open Withverb

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

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

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

  • 由于Doit不是标准化的verb,它会被分配一个显示名称,按下D键即可选择显示名称。
  • Printtoverb 不会显示在快捷菜单上。 但是,它包含在注册表中后,用户可以通过在打印机图标上删除文件来打印文件。
  • 为每个 verb 显示一个子项。 %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"

下图根据上面的注册表项说明了快捷菜单的扩展。 此快捷菜单具有OpenDo ItPrint谓词,并且Do It为默认谓词verb。

默认操作快捷菜单的屏幕截图

使用 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

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

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

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. 对于自定义谓词,请使用任意一种静态 verb 实现方法实现它们,并在 CommandStore 子键下列出它们,如本示例中虚构的 verbVerbName 所示。

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

注意

此方法的优点是,可以通过在 SubCommands 条目下列出 verb 名称来注册自定义谓词一次并重复使用。 但是,它要求应用程序有权在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. 使用以下任何静态 verb 实现填充子项。 请注意,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 相同的verb实现。

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

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

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

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

注意

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

 

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

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

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

System.StructuredQueryType.Boolean#True

在以下示例注册表项中:

  • AppliesTo 值控制verb的显示或隐藏状态。
  • DefaultAppliesTo 值控制哪个 verb 是默认设置。
  • HasLUAShield 值控制是否显示用户帐户控制(UAC)防护。

在此示例中, DefaultAppliesTo 值使其成为 verb 任何文件名中带有单词“exampleText1”的文件的默认值。 AppliesTo 值为名称中包含“exampleText1”的任何文件启用verb。 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 对文件关联属性的查询的详细信息,请参阅 感知类型和应用程序注册

完成 Verb 实施任务

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

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

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

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

扩展新子菜单

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

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

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

ShellNew 子项值 说明
命令 执行应用程序。 此 REG_SZ 值指定要执行的应用程序的路径。 例如,可以将它设置为启动向导。
数据 创建包含指定数据的文件。 此 REG_BINARY 值指定文件的数据。 如果指定了 NullFileFileName,则忽略数据
文件名 创建一个文件,该文件是指定文件的副本。 此 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 策略设置来控制 verb 可见性。 通过在verb注册表子项中添加SuppressionPolicy值或SuppressionPolicyEx GUID值,可以通过策略配置抑制谓词。 将 SuppressionPolicy 子项的值设置为策略 ID。 如果策略已打开,则 verb 和其关联的快捷菜单项将被隐藏。 有关可能的策略 ID 值,请参阅 RESTRICTIONS 枚举。

Verb使用选择模型

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

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

如果所选项数与选择模型不匹配 verb 或大于下表中概述的默认限制,则 verb 无法显示。

实现类型verb 文档 玩家
旧的 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标志值,以确定verb应被启用还是禁用。

若要使用此属性,请在以下位置的 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
    

注意

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

 

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

为快捷菜单选择静态或动态Verb

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

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

谓词和文件关联

快捷菜单参考