应用程序用户模型 ID (AppUserModelIDs)

Windows 7 及更高版本中的任务栏广泛使用应用程序用户模型 ID (AppUserModelIDs) ,以将进程、文件和窗口与特定应用程序相关联。 在某些情况下,依赖于系统分配给进程的内部 AppUserModelID 就足够了。 但是,拥有多个进程的应用程序或主机进程中运行的应用程序可能需要显式标识自身,以便它可以在单个任务栏按钮下对其其他不同窗口进行分组,并控制该应用程序的跳转列表的内容。

Application-Defined 和 System-Defined AppUserModelIDs

某些应用程序不声明显式 AppUserModelID。 它们是可选的。 在这种情况下,系统使用一系列启发法来分配内部 AppUserModelID。 但是,避免这些计算具有性能优势,而显式 AppUserModelID 是保证确切用户体验的唯一方法。 因此,强烈建议设置显式 ID。 应用程序无法检索系统分配的 AppUserModelID。

如果应用程序使用显式 AppUserModelID,则它还必须将相同的 AppUserModelID 分配给所有正在运行的窗口或进程、快捷方式和文件关联。 它还必须在通过 ICustomDestinationList 自定义其跳转列表时以及在任何调用 SHAddToRecentDocs 时使用该 AppUserModelID。

注意

如果应用程序没有显式的 AppUserModelID,则必须从应用程序中调用 IApplicationDestinationsIApplicationDocumentListsICustomDestinationList 方法以及 SHAddToRecentDocs 。 如果从另一个进程(如安装程序或卸载程序)调用这些方法,则系统无法生成正确的 AppUserModelID,并且这些调用将不起作用。

 

以下各项描述了需要显式 AppUserModelID 的常见方案。 它们还指出了应使用多个显式 AppUserModelID 的情况。

  • 具有多个模式的 UI 的单个可执行文件应将不同的 AppUserModelID 分配给每个模式。 例如,用户将其视为独立体验的应用程序的一部分应具有独立于main体验的 AppUserModelID,用户可以将其固定到任务栏并从任务栏单独启动。

  • 具有不同参数的多个快捷方式会导致用户视为同一应用程序的内容,应对所有快捷方式使用一个 AppUserModelID。 例如,Windows Internet Explorer 具有不同模式的快捷方式 (例如在没有加载项) 启动,但它们都应作为单个 Internet Explorer 实例显示给用户。

  • 充当主机进程并作为应用程序运行目标内容的可执行文件必须 注册为主机应用程序,然后它可以为其托管的每个感知体验分配不同的 AppUserModelID。 或者,主机进程可以允许托管程序设置其 AppUserModelID。 在任一情况下,主机进程都必须保留 AppUserModelID 的源记录,无论是自身还是托管的应用程序。 在这种情况下,主机进程没有目标内容的主要用户体验。 示例包括本地集成的 Windows 远程应用程序 (RAIL) 应用程序、Java 运行时、RunDLL32.exe或DLLHost.exe。

    对于现有的托管应用程序,系统会尝试识别单个体验,但新应用程序应使用显式 AppUserModelID 来保证预期的用户体验。

  • 与用户属于同一应用程序的一部分的合作或链接进程应将相同的 AppUserModelID 应用于每个进程。 示例包括具有 (链接) 的启动器进程的游戏和 Microsoft Windows 媒体播放器(在一个进程中运行首次运行/设置体验),main应用程序在另一个进程中运行 (协作) 。

  • 在 Windows 资源管理器中充当用于浏览和管理内容的单独应用程序的 Shell 命名空间扩展应在其文件夹属性中分配 AppUserModelID。 例如,控制面板。

  • 在虚拟化环境(如部署框架)中,虚拟化环境应为其管理的每个应用程序分配不同的 AppUserModelID。 在这些情况下,应用程序启动器使用中间进程来设置环境,然后将操作移交给其他进程来运行应用程序。 请注意,这会导致系统无法将正在运行的目标进程关联回快捷方式,因为快捷方式指向中间进程。

    如果任何应用程序有多个窗口、快捷方式或进程,则该应用程序分配的 AppUserModelID 也应由虚拟化环境应用于其中每个部分。

    这种情况的一个示例是 ClickOnce 框架,它代表它管理的应用程序正确分配 AppUserModelID。 与在所有此类环境中一样,由 ClickOnce 部署和管理的应用程序不应自行分配显式 AppUserModelID,因为这样做将与 ClickOnce 分配的 AppUserModelID 发生冲突,并导致意外结果。

如何形成 Application-Defined AppUserModelID

应用程序必须以以下形式提供其 AppUserModelID。 它不能包含超过 128 个字符,并且不能包含空格。 每个部分都应采用 pascal 大小写。

CompanyName.ProductName.SubProduct.VersionInformation

CompanyName 应始终使用 和 ProductName ,而 SubProductVersionInformation 部分是可选的,具体取决于应用程序的要求。 SubProduct允许由多个子应用程序组成的main应用程序为每个子应用及其关联的窗口提供单独的任务栏按钮。 VersionInformation 允许两个版本的应用程序共存,同时被视为离散实体。 如果应用程序不打算以这种方式使用, VersionInformation 则应省略 ,以便升级的版本可以使用与它替换的版本相同的 AppUserModelID。

分配 AppUserModelID 的位置

当应用程序使用一个或多个显式 AppUserModelID 时,它应在以下位置和情况下应用这些 AppUserModelID:

  • 在应用程序的快捷方式文件的 System.AppUserModel.ID 属性中。 快捷方式 (为 IShellLink、CLSID_ShellLink 或 .lnk 文件,) 通过 IPropertyStore 和整个 Shell 中使用的其他属性设置机制支持属性。 这样,任务栏就可以确定固定的正确快捷方式,并确保属于进程的窗口与该任务栏按钮正确关联。

    注意

    创建 快捷方式 时,应将 System.AppUserModel.ID 属性应用于快捷方式。 使用 Microsoft Windows Installer (MSI) 安装应用程序时, MsiShortcutProperty 表允许在安装过程中创建 AppUserModelID 时将其应用于快捷方式。

     

  • 作为应用程序运行的任何窗口的属性。 可以通过以下两种方式之一来设置:

    1. 如果一个进程拥有的不同窗口需要不同的 AppUserModelID 来控制任务栏分组,请使用 SHGetPropertyStoreForWindow) 检索窗口的属性存储,并将 AppUserModelID 设置为窗口属性。
    2. 如果进程中的所有窗口都使用相同的 AppUserModelID,请通过 SetCurrentProcessExplicitAppUserModelID 在进程上设置 AppUserModelID。 应用程序必须调用 SetCurrentProcessExplicitAppUserModelID ,以在应用程序的初始启动例程期间设置其 AppUserModelID,然后应用程序才会显示任何 UI、对其跳转列表进行任何操作或 (或导致系统) 对 SHAddToRecentDocs 的任何调用。

    窗口级 AppUserModelID 替代进程级 AppUserModelID。

    当应用程序在窗口级别设置显式 AppUserModelID 时,应用程序可以为任务栏按钮提供其重新启动命令的具体内容。 若要提供该信息,请使用以下属性:

    注意

    如果存在用于启动应用程序的快捷方式,则应用程序应应用 AppUserModelID 作为快捷方式的属性,而不是使用重新启动属性。 在这种情况下,快捷方式的命令行、图标和文本用于提供与重新启动属性相同的信息。

     

    窗口级显式 AppUserModelID 还可以使用 System.AppUserModel.PreventPinning 属性来指定它不应用于固定或重新启动。

  • 在调用以自定义或更新 ICustomDestinationList) (中,检索 (IApplicationDocumentLists) ,或清除 (IApplicationDestinations) 应用程序的跳转列表。

  • 在文件关联注册 (通过其 ProgID) 如果应用程序使用系统自动生成的 “最近” 或“ 频繁 ”目标列表。 SHAddToRecentDocs 引用此关联信息。 通过 ICustomDestinationList::AppendCategoryIShellItem 目标添加到自定义跳转列表时,也会使用此信息。

  • 在任何调用中,应用程序都直接调用 SHAddToRecentDocs。 如果应用程序依赖于公共文件对话框来代表它调用 SHAddToRecentDocs ,则仅当为整个过程设置了 AppUserModelID 时,这些调用才能推导显式 AppUserModelID。 如果应用程序在其窗口而不是进程上设置 AppUserModelID,则应用程序必须使用其显式 AppUserModelID 对 SHAddToRecentDocs 本身进行所有调用,并阻止公共文件对话框进行自己的调用。 必须在项目打开时执行此操作,以确保应用程序的跳转列表的 “最近” 或“ 频繁 ”部分准确。

以下各项介绍了常见方案,以及在这些方案中应用显式 AppUserModelID 的位置。

  • 当单个进程包含多个应用程序时,请使用 SHGetPropertyStoreForWindow 检索窗口的属性存储,并将 AppUserModelID 设置为窗口属性。
  • 当应用程序使用多个进程时,将 AppUserModelID 应用于每个进程。 是否对每个进程使用相同的 AppUserModelID 取决于你希望每个进程显示为main应用程序的一部分,还是作为单个实体显示。
  • 若要将某些窗口与同一进程中的集分开,请使用窗口的属性存储将单个 AppUserModelID 应用于要分隔的窗口,然后将不同的 AppUserModelID 应用于进程。 该进程中未使用窗口级 AppUserModelID 显式标记的任何窗口将继承进程的 AppUserModelID。
  • 如果文件类型与应用程序关联,请在文件类型的 ProgID 注册中分配 AppUserModelID。 如果单个可执行文件以不同的模式启动,这些模式向用户显示为不同的应用程序,则每个模式都需要单独的 AppUserModelID。 在这种情况下,文件类型必须有多个 ProgID 注册,每个注册都有不同的 AppUserModelID。
  • 如果用户可以从多个快捷方式位置启动应用程序, (在 “开始 ”菜单、桌面或其他位置) 检索快捷方式的属性存储,以将单个 AppUserModelID 作为快捷方式属性应用于所有快捷方式。
  • 当应用程序显式调用 SHAddToRecentDocs 时,请在调用中使用 AppUserModelID。 使用通用文件对话框打开或保存文件时,对话框将代表应用程序调用 SHAddToRecentDocs 。 该调用可以从进程推断出显式 AppUserModelID。 但是,如果显式 AppUserModelID 作为窗口属性应用,则公共文件对话框无法确定正确的 AppUserModelID。 在这种情况下,应用程序本身必须显式调用 SHAddToRecentDocs ,并为其提供正确的 AppUserModelID。 此外,应用程序必须通过在 IFileOpenDialog 或 IFileSaveDialogGetOptions 方法中设置FOS_DONTADDTORECENT标志来阻止公共文件对话框代表其调用 SHAddToRecentDocs

将应用程序注册为主机进程

应用程序可以设置 IsHostApp 注册表项,使任务栏将可执行文件的进程视为主机进程。 这会影响其分组和默认跳转列表条目。

以下示例显示了所需的注册表项。 请注意,未为条目分配值;其存在就是所需的全部内容。 它是一个REG_NULL值。

HKEY_CLASSES_ROOT
   Applications
      example.exe
         IsHostApp

如果进程本身或用于启动进程的快捷方式文件具有显式 AppUserModelID,则会忽略主机进程列表,并且任务栏会将该应用程序视为普通应用程序。 应用程序的运行窗口组合在单个任务栏按钮下,应用程序可以固定到任务栏。

如果只知道正在运行的进程的可执行文件名称,没有显式的 AppUserModelID,并且该可执行文件位于主机进程列表中,则进程的每个实例被视为任务栏分组的单独实体。 与进程的任何特定实例关联的任务栏按钮不显示进程新实例的固定/取消固定选项或启动图标。 此过程也不符合包含在 “开始” 菜单的“最常用的 (MFU) 列表中的条件。 但是,如果进程是通过包含启动参数 (通常作为“应用程序”) 托管的目标内容的快捷方式启动的,则系统可以确定标识,并且可以固定和重新启动应用程序。

任务栏固定和最近/频繁列表的排除列表

应用程序、进程和窗口可以选择使其无法固定到任务栏或包含在 “开始” 菜单的 MFU 列表中。 可通过三种机制来实现此目的:

  1. 将 NoStartPage 条目添加到应用程序的注册中,如下所示:

    HKEY_CLASSES_ROOT
       Applications
          Example.exe
             NoStartPage
    

    与 NoStartPage 条目关联的数据将被忽略。 只有条目的存在是必需的。 因此,NoStartPage 的理想类型是REG_NONE。

    请注意,任何使用显式 AppUserModelID 会替代 NoStartPage 条目。 如果将显式 AppUserModelID 应用于快捷方式、进程或窗口,它将变为可固定并符合 “开始” 菜单 MFU 列表的条件。

  2. 在窗口和快捷方式上设置 System.AppUserModel.PreventPinning 属性。 必须在 PKEY_AppUserModel_ID 属性之前 在窗口上设置此属性。

  3. 将显式 AppUserModelID 添加为以下注册表子项下的值,如下所示:

    HKEY_LOCAL_MACHINE
       Software
          Microsoft
             Windows
                CurrentVersion
                   Explorer
                      FileAssociation
                         NoStartPageAppUserModelIDs
                            AppUserModelID1
                            AppUserModelID2
                            AppUserModelID3
    

    每个条目都是一个REG_NULL值,名称为 AppUserModelID。 在此列表中找到的任何 AppUserModelID 都是不可固定的,也不符合包含在 “开始 ”菜单 MFU 列表中的条件。

请注意,某些可执行文件以及名称中包含某些字符串的快捷方式会自动从固定和包含在 MFU 列表中。

注意

可以通过应用显式 AppUserModelID 来重写此自动排除。

 

如果以下任一字符串(无论大小写)包含在快捷方式名称中,则程序不可固定且不显示在最常用的列表中, (不适用于Windows 10) :

  • 文档
  • 帮助
  • 安装
  • 更多信息
  • 阅读我
  • 首先读取
  • 自述文件
  • 删除
  • 安装
  • 支持
  • 新增功能

以下程序列表不可固定,并且已从最常用的列表中排除。

  • Applaunch.exe
  • Control.exe
  • Dfsvc.exe
  • Dllhost.exe
  • Guestmodemsg.exe
  • Hh.exe
  • Install.exe
  • Isuninst.exe
  • Lnkstub.exe
  • Mmc.exe
  • Mshta.exe
  • Msiexec.exe
  • Msoobe.exe
  • Rundll32.exe
  • Setup.exe
  • St5unst.exe
  • Unwise.exe
  • Unwise32.exe
  • Werfault.exe
  • Winhlp32.exe
  • Wlrmdr.exe
  • Wuapp.exe

上述列表存储在以下注册表值中。

注意

应用程序不应修改这些列表。 对于相同的体验,请使用前面列出的排除列表方法之一。

 

HKEY_LOCAL_MACHINE
   Software
      Microsoft
         Windows
            CurrentVersion
               Explorer
                  FileAssociation
                     AddRemoveApps
                     HostApps

SetCurrentProcessExplicitAppUserModelID

GetCurrentProcessExplicitAppUserModelID

任务栏扩展

ICustomDestinationList::SetAppID

IApplicationDocumentLists::SetAppID

IApplicationDestinations::SetAppID

SHGetPropertyStoreForWindow