创建多实例通用 Windows 应用Create a multi-instance Universal Windows App

本主题介绍如何创建多实例通用 Windows 平台 (UWP) 应用。This topic describes how to create multi-instance Universal Windows Platform (UWP) apps.

从 Windows 10 版本1803(10.0;版本17134),UWP 应用可以选择支持多个实例。From Windows 10, version 1803 (10.0; Build 17134) onward, your UWP app can opt in to support multiple instances. 如果多实例 UWP 应用的一个实例正在运行,并发生后续的激活请求,平台将不会激活现有实例。If an instance of an multi-instance UWP app is running, and a subsequent activation request comes through, the platform will not activate the existing instance. 然而,它会创建一个新实例,而且在单独的进程中运行。Instead, it will create a new instance, running in a separate process.

重要

JavaScript 应用程序支持多实例,但不支持多实例重定向。Multi-instancing is supported for JavaScript applications, but multi-instancing redirection is not. 由于 JavaScript 应用程序不支持多实例重定向,因此对于此类应用程序, AppInstance类不起作用。Since multi-instancing redirection is not supported for JavaScript applications, the AppInstance class is not useful for such applications.

选择启用多实例行为Opt in to multi-instance behavior

如果要创建新的多实例应用程序,可以安装 Visual Studio Marketplace 中提供的多实例应用项目模板.VSIXIf you are creating a new multi-instance application, you can install the Multi-Instance App Project Templates.VSIX, available from the Visual Studio Marketplace. 一旦安装该模板,可通过 Visual C# > Windows 通用(或其他语言 > Visual C++ > Windows 通用)下的新建项目对话框获取。Once you install the templates, they will be available in the New Project dialog under Visual C# > Windows Universal (or Other Languages > Visual C++ > Windows Universal).

已安装两个模板:多实例 UWP 应用模板,提供用于创建多实例应用的模板,以及多实例重定向 UWP 应用模板,它提供用于构建的其他逻辑,可基于这些逻辑启动新实例或选择性地激活已启动的实例。Two templates are installed: Multi-Instance UWP app, which provides the template for creating a multi-instance app, and Multi-Instance Redirection UWP app, which provides additional logic that you can build on to either launch a new instance or selectively activate an instance that has already been launched. 例如,你可能只需要一次编辑相同文档的一个实例,因此你会将该文件的实例打开到前台,而不是启动一个新的实例。For example, perhaps you only want one instance at a time editing the same document, so you bring the instance that has that file open to the foreground rather than launching a new instance.

这两个模板都将 SupportsMultipleInstances 添加到 package.appxmanifest 文件中。Both templates add SupportsMultipleInstances to the package.appxmanifest file. 请注意命名空间前缀 desktop4iot2:只有面向桌面的项目或物联网(IoT)项目才支持多实例。Note the namespace prefix desktop4 and iot2: only projects that target the desktop, or Internet of Things (IoT) projects, support multi-instancing.

<Package
  ...
  xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
  xmlns:iot2="http://schemas.microsoft.com/appx/manifest/iot/windows10/2"  
  IgnorableNamespaces="uap mp desktop4 iot2">
  ...
  <Applications>
    <Application Id="App"
      ...
      desktop4:SupportsMultipleInstances="true"
      iot2:SupportsMultipleInstances="true">
      ...
    </Application>
  </Applications>
   ...
</Package>

多实例激活重定向Multi-instance activation redirection

对 UWP 应用的多实例支持不仅仅能够启动应用的多个实例。Multi-instancing support for UWP apps goes beyond simply making it possible to launch multiple instances of the app. 当你考虑是启动应用的新实例还是激活已经运行的实例时,可以进行自定义。It allows for customization in cases where you want to select whether a new instance of your app is launched or an instance that is already running is activated. 例如,如果启动应用以编辑另一实例中已在编辑的文件,你可能会想要将激活操作重定向到该实例,而不是打开另一个已在编辑该文件的实例。For example, if the app is launched to edit a file that is already being edited in another instance, you may want to redirect the activation to that instance instead of opening up another instance that that is already editing the file.

若要查看其工作原理,请观看此视频,了解如何创建多实例 UWP 应用。To see it in action, watch this video about Creating multi-instance UWP apps.

如上所示,多实例重定向 UWP 应用模板将 SupportsMultipleInstances 添加到 package.appxmanifest 文件,并且还将 Program.cs(或 Program.cpp,如果使用的是模板的 C++ 版本)添加到包含 Main() 函数的项目中。The Multi-Instance Redirection UWP app template adds SupportsMultipleInstances to the package.appxmanifest file as shown above, and also adds a Program.cs (or Program.cpp, if you are using the C++ version of the template) to your project that contains a Main() function. 用于重定向激活操作的逻辑包含在 Main 函数中。The logic for redirecting activation goes in the Main function. Program.cs的模板如下所示。The template for Program.cs is shown below.

AppInstance. RecommendedInstance属性表示此激活请求的 shell 提供的首选实例(如果有)(如果没有,则为 null)。The AppInstance.RecommendedInstance property represents the shell-provided preferred instance for this activation request, if there is one (or null if there isn't one). 如果 shell 提供了一个首选项,则可以将激活重定向到该实例,也可以在选择时将其忽略。If the shell provides a preference, then you can redirect activation to that instance, or you can ignore it if you choose.

public static class Program
{
    // This example code shows how you could implement the required Main method to
    // support multi-instance redirection. The minimum requirement is to call
    // Application.Start with a new App object. Beyond that, you may delete the
    // rest of the example code and replace it with your custom code if you wish.

    static void Main(string[] args)
    {
        // First, we'll get our activation event args, which are typically richer
        // than the incoming command-line args. We can use these in our app-defined
        // logic for generating the key for this instance.
        IActivatedEventArgs activatedArgs = AppInstance.GetActivatedEventArgs();

        // If the Windows shell indicates a recommended instance, then
        // the app can choose to redirect this activation to that instance instead.
        if (AppInstance.RecommendedInstance != null)
        {
            AppInstance.RecommendedInstance.RedirectActivationTo();
        }
        else
        {
            // Define a key for this instance, based on some app-specific logic.
            // If the key is always unique, then the app will never redirect.
            // If the key is always non-unique, then the app will always redirect
            // to the first instance. In practice, the app should produce a key
            // that is sometimes unique and sometimes not, depending on its own needs.
            string key = Guid.NewGuid().ToString(); // always unique.
                                                    //string key = "Some-App-Defined-Key"; // never unique.
            var instance = AppInstance.FindOrRegisterInstanceForKey(key);
            if (instance.IsCurrentInstance)
            {
                // If we successfully registered this instance, we can now just
                // go ahead and do normal XAML initialization.
                global::Windows.UI.Xaml.Application.Start((p) => new App());
            }
            else
            {
                // Some other instance has registered for this key, so we'll 
                // redirect this activation to that instance instead.
                instance.RedirectActivationTo();
            }
        }
    }
}

Main() 是要运行的第一件事。Main() is the first thing that runs. 它在OnLaunchedOnActivated之前运行。It runs before OnLaunched and OnActivated. 这样便能够确定在应用中的任何其他初始化代码运行之前,是激活此实例还是其他实例。This allows you to determine whether to activate this, or another instance, before any other initialization code in your app runs.

以上代码决定是激活应用程序的现有实例还是新实例。The code above determines whether an existing, or new, instance of your application is activated. 使用一个密钥来确定是否存在要激活的现有实例。A key is used to determine whether there is an existing instance that you want to activate. 例如,如果可启动应用来处理文件激活,则可能将文件名作为密钥。For example, if your app can be launched to Handle file activation, you might use the file name as a key. 然后,可检查是否已使用该密钥注册了应用的一个实例,然后激活它,而不是打开一个新实例。Then you can check whether an instance of your app is already registered with that key and activate it instead of opening a new instance. 这是代码背后的理念: var instance = AppInstance.FindOrRegisterInstanceForKey(key);This is the idea behind the code: var instance = AppInstance.FindOrRegisterInstanceForKey(key);

如果找到使用该密钥注册的实例,表示该实例已激活。If an instance registered with the key is found, then that instance is activated. 如果未找到密钥,则当前实例(当前正在运行 Main 的实例)将创建其应用程序对象并开始运行。If the key is not found, then the current instance (the instance that is currently running Main) creates its application object and starts running.

后台任务和多实例Background tasks and multi-instancing

  • 进程外后台任务支持多实例。Out-of-proc background tasks support multi-instancing. 通常情况下,每个新的触发器都会产生后台任务的新实例(尽管从技术角度来讲,多个后台任务可能在同一个主机进程中运行)。Typically, each new trigger results in a new instance of the background task (although technically speaking multiple background tasks may run in same host process). 尽管如此,仍会创建后台任务的另一个实例。Nevertheless, a different instance of the background task is created.
  • 进程内后台任务不支持多实例。In-proc background tasks do not support multi-instancing.
  • 后台音频任务不支持多实例。Background audio tasks do not support multi-instancing.
  • 当应用注册后台任务时,通常首先会检查该任务是否已经注册,然后删除并重新注册它,或者不执行任何操作以保留现有的注册。When an app registers a background task, it usually first checks to see if the task is already registered and then either deletes and re-registers it, or does nothing in order to keep the existing registration. 这仍是多实例应用的典型行为。This is still the typical behavior with multi-instance apps. 但是,多实例应用可能会选择在每个实例的基础上注册另一个后台任务名称。However, a multi-instancing app may choose to register a different background task name on a per-instance basis. 这将导致多次注册相同的触发器,并且触发器触发时将激活多个后台任务实例。This will result in multiple registrations for the same trigger, and multiple background task instances will be activated when the trigger fires.
  • 应用服务为每个连接启动单独的应用服务后台任务实例。App-services launch a separate instance of the app-service background task for every connection. 这对多实例应用保持不变,即多实例应用的每个实例都将获得自己的应用服务后台任务实例。This remains unchanged for multi-instance apps, that is each instance of a multi-instance app will get its own instance of the app-service background task.

其他注意事项Additional considerations

  • 面向桌面和物联网 (IoT) 项目的 UWP 应用支持多实例。Multi-instancing is supported by UWP apps that target desktop and Internet of Things (IoT) projects.
  • 若要避免发生争用和争用导致的问题,多实例应用需要采取措施对访问设置、应用本地存储以及能在多个实例之间共享的任何其他资源(例如用户文件、数据存储等)进行分区/同步。To avoid race-conditions and contention issues, multi-instance apps need to take steps to partition/synchronize access to settings, app-local storage, and any other resource (such as user files, a data store, and so on) that can be shared among multiple instances. 提供了标准同步机制,如互斥体、信号量、事件等。Standard synchronization mechanisms such as mutexes, semaphores, events, and so on, are available.
  • 如果应用的 Package.appxmanifest 文件中有 SupportsMultipleInstances,则其扩展无需声明 SupportsMultipleInstancesIf the app has SupportsMultipleInstances in its Package.appxmanifest file, then its extensions do not need to declare SupportsMultipleInstances.
  • 如果将 SupportsMultipleInstances 添加到除后台任务或应用服务之外的任何其他扩展,并且托管该扩展的应用也不在其 Package.appxmanifest 文件中声明 SupportsMultipleInstances,则会发生架构错误。If you add SupportsMultipleInstances to any other extension, apart from background tasks or app-services, and the app that hosts the extension doesn't also declare SupportsMultipleInstances in its Package.appxmanifest file, then a schema error is generated.
  • 应用可以使用清单中的资源组声明将多个后台任务分为同一主机。Apps can use the ResourceGroup declaration in their manifest to group multiple background tasks into the same host. 这与多实例相冲突,在多实例中,每个激活操作会进入单独的主机。This conflicts with multi-instancing, where each activation goes into a separate host. 因此,应用无法在其清单中同时声明 SupportsMultipleInstancesResourceGroupTherefore an app cannot declare both SupportsMultipleInstances and ResourceGroup in their manifest.

示例Sample

有关多实例激活重定向的示例,请参阅多实例示例See Multi-Instance sample for an example of multi-instance activation redirection.

另请参阅See also

AppInstance.FindOrRegisterInstanceForKey AppInstance.GetActivatedEventArgs AppInstance.RedirectActivationTo 处理应用激活AppInstance.FindOrRegisterInstanceForKey AppInstance.GetActivatedEventArgs AppInstance.RedirectActivationTo Handle app activation