WPF: Запускать только один экземпляр приложения

Ранее я уже писал заметку «WPF: Запускать только одну копию приложения«. Было это, как оказалось, довольно «давно». Хоть и прошло всего полтора года, а часть ссылок уже недоступна и некоторые пункты контекстного меню изменились. Попробуем сделать аналогичное приложение немного другим способом.

Подключение пакета SingleInstanceCore

0. У нас уже должен быть открыт пустой проект WPF и здесь я не расписываю пошагово, как именно его нужно создавать.
1. Для начала нам нужно добавить в проект пакет «SingleInstanceCore» (этот пакет из состава NuGet, поэтому на этот раз нам пригодится пункт главного меню Visual Studio Community: NuGet Package Manager).

Хотя, данный пакет можно поставить и через NuGet Package Manager Console

PowerShell
Install-Package SingleInstanceCore -Version 2.2.0

 

2. Убедимся, что пакет был добавлен в проект, для чего раскроем дерево проекта на пункте DependenciesPackages:
WPF:  Запускать только один экземпляр приложения
3. Если приложение вызывается с аргументами, то мы их должны обрабатывать при каждом вызове (файл App.xaml.cs):

App.xaml.cs
  public partial class App : Application, ISingleInstance
  {
    public void OnInstanceInvoked(string[] args)
    {
      //Здесь обрабатываются аргументы, которые передали приложению
      // Например так:
      // https://docs.microsoft.com/ru-ru/dotnet/api/system.windows.application.startup?view=net-5.0
    }
    // Что-то ещё
}

Чтобы не было ошибок, нужно добавить в начало файла строку:

App.xaml.cs
using SingleInstanceCore;

 

4. В тот же файл добавим строчки для инициализации данного экземпляра приложения:

App.xaml.cs
    private void Application_Startup(object sender, StartupEventArgs e)
    {
      bool isFirstInstance = this.InitializeAsFirstInstance("soheilkd_ExampleIPC");
      if (!isFirstInstance)
      {
        //If it's not the first instance, arguments are automatically passed to the first instance
        //OnInstanceInvoked will be raised on the first instance
        //You may shut down the current instance
        Current.Shutdown();
      }
    }

5. Чуть ниже не забудем добавить метод для очистки памяти при выходе из приложения:

App.xaml.cs
    private void Application_Exit(object sender, ExitEventArgs e)
    {
      //Do not forget to cleanup
      SingleInstance.Cleanup();
    }

6. Далее нам нужно обратить внимание на файл App.xaml, здесь свойство StartupUri замещается подпиской на событие Startup, т.о. полный код этого файла теперь будет такой:

App.xaml
<Application x:Class="SingleInstanceApp.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:SingleInstanceApp"
             Startup="Application_Startup">
    <Application.Resources>
         
    </Application.Resources>
</Application>
Мы просто заменили дефолтовую строчку StartupUri="MainWindow.xaml" на Startup="Application_Startup"

 

Теперь при запуске приложения будет произведена проверка и, если это приложение уже было запущено ранее, то новое окно не будет открыто (процесс будет убит).

В данном примере рассмотрен способ запуска только одного экземпляра приложения, но при этом здесь не реализован вывод окна на передний план или восстановление его из свёрнутого состояния! Из-за простоты данного пакета, тут нет возможности обратиться к основному процессу.
Другой метод, в котором мы восстанавливаем состояние окна, если запущено новый процесс, описан тут.

 

Другой вариант

Этот вариант более простой в реализации, т.к. требует изменения только файла App.xaml.cs.

App.xaml.cs
using System.Threading;
using System.Windows;

namespace SingleInstanceAppDemo
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        private static Mutex? _mutex;

        // Allow only one instance at a time
        protected override void OnStartup(StartupEventArgs e)
        {
            const string appName = "SingleInstanceAppDemo";

            _mutex = new Mutex(true, appName, out bool createdNew);

            if (!createdNew)
            {
                //app is already running! Exiting the application  
                Application.Current.Shutdown();
            }

            base.OnStartup(e);
        }
    }
}


Подписаться
Уведомление о
guest
0 Комментарий
Inline Feedbacks
View all comments