Создание универсального приложения Для Windows с несколькими экземплярами

В этом разделе описывается создание приложений с несколькими экземплярами универсальная платформа Windows (UWP).

Из Windows 10 версии 1803 (10.0; Сборка 17134) — приложение UWP может принять участие в поддержке нескольких экземпляров. Если запущен экземпляр приложения UWP с несколькими экземплярами, при последующих запросах на активацию платформа не будет активировать существующий экземпляр. Вместо этого будет создан новый экземпляр, выполняемый в отдельном процессе.

Внимание

Мультистантирование поддерживается для приложений JavaScript, но перенаправление с несколькими запросами не поддерживается. Так как перенаправление с несколькими запросами не поддерживается для приложений JavaScript, класс AppInstance не полезен для таких приложений.

Отказ в поведении нескольких экземпляров

Если вы создаете новое приложение с несколькими экземплярами, можно установить шаблоны проектов много экземпляров.VSIX, доступные в Visual Studio Marketplace. После установки шаблонов они будут доступны в диалоговом окне "Новый проект" в универсальной версии Visual C# > Для Windows (или других языков > Visual C++ > Для Windows Universal).

Примечание.

Шаблон проекта приложения с несколькими экземплярами больше недоступен. Шаблон VSIX был удобством, поэтому вместо этого необходимо изменить существующий проект, как описано ниже. Обязательно добавьте константу DISABLE_XAML_GENERATED_MAIN в символы сборки проекта, так как это предотвращает создание сборки по умолчанию Main(). Это позволяет использовать специально написанную версию Main().

Установлены два шаблона: приложение UWP с несколькими экземплярами, которое предоставляет шаблон для создания приложения с несколькими экземплярами и приложения UWP с несколькими экземплярами, которое обеспечивает дополнительную логику, которая позволяет запускать новый экземпляр или выборочно активировать уже запущенный экземпляр. Например, возможно, требуется только один экземпляр во время редактирования одного документа, поэтому экземпляр, имеющий этот файл, открыт на переднем плане, а не запуск нового экземпляра.

Оба шаблона добавляются SupportsMultipleInstances в package.appxmanifest файл. Обратите внимание на префикс desktop4 пространства имен и iot2: только проекты, предназначенные для настольных компьютеров или проектов Интернета вещей (IoT), поддерживают многоуровневую проверку.

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

Перенаправление активации с несколькими экземплярами

Поддержка нескольких приложений UWP выходит за рамки простого запуска нескольких экземпляров приложения. Он позволяет настраивать в случаях, когда требуется выбрать, запускается ли новый экземпляр приложения или уже запущенный экземпляр. Например, если приложение запускается для изменения файла, который уже редактируется в другом экземпляре, может потребоваться перенаправить активацию в этот экземпляр вместо открытия другого экземпляра, который уже редактирует файл.

Чтобы увидеть его в действии, просмотрите это видео о создании приложений UWP с несколькими экземплярами.

Шаблон приложения UWP с несколькими экземплярами добавляется в файл package.appxmanifest, как показано выше, а также добавляет SupportsMultipleInstances Program.cs (или Program.cpp, если вы используете версию шаблона C++) в проект, содержащий Main() функцию. Логика перенаправления активации переходит в функцию Main . Ниже показан шаблон для Program.cs .

Свойство AppInstance.RecommendedInstance представляет предпочтительный экземпляр оболочки для этого запроса активации, если есть один (или null если его нет). Если оболочка предоставляет предпочтения, вы можете перенаправить активацию в этот экземпляр или игнорировать ее при выборе.

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() — это первое, что выполняется. Он выполняется до OnLaunched и OnActivated. Это позволяет определить, следует ли активировать этот или другой экземпляр перед выполнением любого другого кода инициализации в приложении.

Приведенный выше код определяет, активируется ли существующий или новый экземпляр приложения. Ключ используется для определения наличия существующего экземпляра, который требуется активировать. Например, если приложение можно запустить для обработки активации файла, можно использовать имя файла в качестве ключа. Затем можно проверка, зарегистрирован ли экземпляр приложения с помощью этого ключа и активировать его вместо открытия нового экземпляра. Это идея кода: var instance = AppInstance.FindOrRegisterInstanceForKey(key);

Если обнаружен экземпляр, зарегистрированный с помощью ключа, активируется этот экземпляр. Если ключ не найден, текущий экземпляр (в данный момент запущенный Mainэкземпляр) создает объект приложения и запускается.

Фоновые задачи и многоуровневая настройка

  • Внепространивые фоновые задачи поддерживают многоуровневую настройку. Как правило, каждый новый триггер приводит к новому экземпляру фоновой задачи (хотя технически говоря несколько фоновых задач может выполняться в одном и том же процессе узла). Тем не менее создается другой экземпляр фоновой задачи.
  • Фоновые задачи в proc не поддерживают многоуровневую настройку.
  • Фоновые звуковые задачи не поддерживают многоуровневую настройку.
  • Когда приложение регистрирует фоновую задачу, обычно сначала проверка, чтобы узнать, зарегистрирована ли задача, а затем удаляет и повторно регистрирует ее, или ничего не делает, чтобы сохранить существующую регистрацию. Это по-прежнему типичное поведение с приложениями с несколькими экземплярами. Однако приложение с несколькими ограничениями может зарегистрировать другое фоновое имя задачи на основе каждого экземпляра. Это приведет к тому, что при срабатывании триггера будет активировано несколько регистраций для одного триггера, а при срабатывании триггера будет активировано несколько экземпляров фоновых задач.
  • Службы приложений запускают отдельный экземпляр фоновой задачи службы приложений для каждого подключения. Это остается неизменным для приложений с несколькими экземплярами, то есть каждый экземпляр приложения с несколькими экземплярами получит собственный экземпляр фоновой задачи службы приложений.

Дополнительные рекомендации

  • Многофакторная поддержка поддерживается приложениями UWP, предназначенными для проектов настольных компьютеров и Интернета вещей ..
  • Чтобы избежать проблем с состоянием гонки и конфликтами, приложения с несколькими экземплярами должны выполнить шаги по секционированием и синхронизации доступа к параметрам, локальному хранилищу приложений и любому другому ресурсу (например, файлам пользователей, хранилищу данных и т. д.), которые могут быть общими для нескольких экземпляров. Доступны стандартные механизмы синхронизации, такие как мьютексы, семафоры, события и т. д.
  • Если приложение содержит SupportsMultipleInstances файл Package.appxmanifest, его расширения не должны объявляться SupportsMultipleInstances.
  • Если добавить SupportsMultipleInstances к любому другому расширению, помимо фоновых задач или служб приложений, а приложение, на котором размещено расширение, также не объявляется SupportsMultipleInstances в файле Package.appxmanifest, создается ошибка схемы.
  • Приложения могут использовать объявление ResourceGroup в манифесте для группировки нескольких фоновых задач в один узел. Это конфликтует с несколькими строками, где каждая активация переходит в отдельный узел. Поэтому приложение не может объявлять оба SupportsMultipleInstances и ResourceGroup в манифесте.

Пример

Пример перенаправления активации с несколькими экземплярами см . в примере с несколькими экземплярами.

См. также

AppInstance.FindOrRegisterInstanceForKeyAppInstance.GetActivatedEventArgsAppInstance.RedirectActivationToHandle app activation