Как правильно создать приложение WPF с одним экземпляром? - PullRequest
607 голосов
/ 21 августа 2008

Используя C # и WPF под .NET (а не Windows Forms или консоль), как правильно создать приложение, которое можно запустить только как один экземпляр?

Я знаю, что это как-то связано с какой-то мифической штукой, называемой мьютексом, редко я могу найти кого-то, кто мешает остановиться и объяснить, что из этого есть.

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

Ответы [ 35 ]

0 голосов
/ 26 августа 2016

Вот мои 2 цента

 static class Program
    {
        [STAThread]
        static void Main()
        {
            bool createdNew;
            using (new Mutex(true, "MyApp", out createdNew))
            {
                if (createdNew) {
                    Application.EnableVisualStyles();
                    Application.SetCompatibleTextRenderingDefault(false);
                    var mainClass = new SynGesturesLogic();
                    Application.ApplicationExit += mainClass.tray_exit;
                    Application.Run();
                }
                else
                {
                    var current = Process.GetCurrentProcess();
                    foreach (var process in Process.GetProcessesByName(current.ProcessName).Where(process => process.Id != current.Id))
                    {
                        NativeMethods.SetForegroundWindow(process.MainWindowHandle);
                        break;
                    }
                }
            }
        }
    }
0 голосов
/ 09 августа 2016

Вот так я и решил эту проблему. Обратите внимание, что отладочный код все еще там для тестирования. Этот код находится в OnStartup в файле App.xaml.cs. (WPF)

        // Process already running ? 
        if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
        {

            // Show your error message
            MessageBox.Show("xxx is already running.  \r\n\r\nIf the original process is hung up you may need to restart your computer, or kill the current xxx process using the task manager.", "xxx is already running!", MessageBoxButton.OK, MessageBoxImage.Exclamation);

            // This process 
            Process currentProcess = Process.GetCurrentProcess();

            // Get all processes running on the local computer.
            Process[] localAll = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName);

            // ID of this process... 
            int temp = currentProcess.Id;
            MessageBox.Show("This Process ID:  " + temp.ToString());

            for (int i = 0; i < localAll.Length; i++)
            {
                // Find the other process 
                if (localAll[i].Id != currentProcess.Id)
                {
                    MessageBox.Show("Original Process ID (Switching to):  " + localAll[i].Id.ToString());

                    // Switch to it... 
                    SetForegroundWindow(localAll[i].MainWindowHandle);

                }
            }

            Application.Current.Shutdown();

        }

Это может иметь проблемы, которые я еще не обнаружил. Если я столкнусь с чем-нибудь, я обновлю свой ответ.

0 голосов
/ 05 июля 2016

Вот решение:

Protected Overrides Sub OnStartup(e As StartupEventArgs)
    Const appName As String = "TestApp"
    Dim createdNew As Boolean
    _mutex = New Mutex(True, appName, createdNew)
    If Not createdNew Then
        'app is already running! Exiting the application
        MessageBox.Show("Application is already running.")
        Application.Current.Shutdown()
    End If
    MyBase.OnStartup(e)
End Sub
0 голосов
/ 04 августа 2015

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

Более того, если мы хотим вывести приложение поверх, мы можем сделать это, используя

 [DllImport("user32")]
 static extern IntPtr SetForegroundWindow(IntPtr hWnd);
0 голосов
/ 26 января 2015

Я добавил метод sendMessage в класс NativeMethods.

Очевидно, что метод postmessage не работает, если приложение не отображается на панели задач, однако использование метода sendmessage решает это.

class NativeMethods
{
    public const int HWND_BROADCAST = 0xffff;
    public static readonly int WM_SHOWME = RegisterWindowMessage("WM_SHOWME");
    [DllImport("user32")]
    public static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    public static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
    [DllImport("user32")]
    public static extern int RegisterWindowMessage(string message);
}
...