C#/WPF 僅啓動一個進程實例

如何實現僅啓動一個 WPF 進程實例,並在打開第二個時,自動喚起以前打開的進程。html

1 代碼入口

App.xaml.cs 文件中,重寫 OnStartup 方法,並添加 Mutex 進程鎖。ide

/// <summary>
/// 只打開一個進程
/// </summary>
/// <param name="e"></param>
protected override void OnStartup(StartupEventArgs e)
{
    string mutexName = "32283F61-EC4D-43B1-9C44-40280D5854DD";

    ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, mutexName, out var createNew);

    if (!createNew)
    {
        // 喚起已經啓動的進程

        App.Current.Shutdown();
        Environment.Exit(-1);
    }
    else
    {
        // 正常啓動
        base.OnStartup(e);
    }
}

2 喚起已經啓動的進程

try
{
    var processes = Process.GetProcessesByName("進程名");
    if (!processes.Any())
    {
        // 沒有找到進程名,多是啓動文件被更名了,但仍是啓動了的。
        MessageBox.Show("已經啓動了XXX", "錯誤提示", MessageBoxButton.OK, MessageBoxImage.Error);
    }
    else
    {
        // 其實這裏應該只有一個
        foreach (Process process in processes)
        {
            ShowWindowAsync(process.MainWindowHandle, SW_SHOWNOMAL);
            SetForegroundWindow(process.MainWindowHandle);
            SwitchToThisWindow(process.MainWindowHandle, true);
        }
    }
}
catch (Exception exception)
{
    // Logger.Error(exception, "喚起已啓動進程時出錯");
}

Win32 函數引入:函數

private const int SW_SHOWNOMAL = 1;

///<summary>
/// 該函數設置由不一樣線程產生的窗口的顯示狀態
/// </summary>
/// <param name="hWnd">窗口句柄</param>
/// <param name="cmdShow">指定窗口如何顯示。查看容許值列表,請查閱ShowWindow函數的說明部分</param>
/// <returns>若是函數原來可見,返回值爲非零;若是函數原來被隱藏,返回值爲零</returns>
[DllImport("User32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);

/// <summary>
///  該函數將建立指定窗口的線程設置到前臺,而且激活該窗口。鍵盤輸入轉向該窗口,併爲用戶改各類可視的記號。
///  系統給建立前臺窗口的線程分配的權限稍高於其餘線程。 
/// </summary>
/// <param name="hWnd">將被激活並被調入前臺的窗口句柄</param>
/// <returns>若是窗口設入了前臺,返回值爲非零;若是窗口未被設入前臺,返回值爲零</returns>
[DllImport("User32.dll", EntryPoint = "SetForegroundWindow")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);

3 完整代碼

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace Test
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        public EventWaitHandle ProgramStarted { get; set; }

        private const int SW_SHOWNOMAL = 1;

        ///<summary>
        /// 該函數設置由不一樣線程產生的窗口的顯示狀態
        /// </summary>
        /// <param name="hWnd">窗口句柄</param>
        /// <param name="cmdShow">指定窗口如何顯示。查看容許值列表,請查閱ShowWindow函數的說明部分</param>
        /// <returns>若是函數原來可見,返回值爲非零;若是函數原來被隱藏,返回值爲零</returns>
        [DllImport("User32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);

        /// <summary>
        ///  該函數將建立指定窗口的線程設置到前臺,而且激活該窗口。鍵盤輸入轉向該窗口,併爲用戶改各類可視的記號。
        ///  系統給建立前臺窗口的線程分配的權限稍高於其餘線程。 
        /// </summary>
        /// <param name="hWnd">將被激活並被調入前臺的窗口句柄</param>
        /// <returns>若是窗口設入了前臺,返回值爲非零;若是窗口未被設入前臺,返回值爲零</returns>
        [DllImport("User32.dll", EntryPoint = "SetForegroundWindow")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        public static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);

        /// <summary>
        /// 只打開一個進程
        /// </summary>
        /// <param name="e"></param>
        protected override void OnStartup(StartupEventArgs e)
        {
            string mutexName = "32283F61-EC4D-43B1-9C44-40280D5854DD";

            ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, mutexName, out var createNew);

            if (!createNew)
            {
                try
                {
                    var processes = Process.GetProcessesByName("進程名");
                    if (!processes.Any())
                    {
                        MessageBox.Show("已經啓動了XXX", "錯誤提示", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    else
                    {
                        foreach (Process process in processes)
                        {
                            ShowWindowAsync(process.MainWindowHandle, SW_SHOWNOMAL);
                            SetForegroundWindow(process.MainWindowHandle);
                            SwitchToThisWindow(process.MainWindowHandle, true);
                        }
                    }
                }
                catch (Exception exception)
                {
                    // Logger.Error(exception, "喚起已啓動進程時出錯");
                }

                App.Current.Shutdown();
                Environment.Exit(-1);
            }
            else
            {
                base.OnStartup(e);
            }
        }

    }

}

4 參考連接


原文連接:
http://www.javashuo.com/article/p-rtygxthv-hg.htmlspa

相關文章
相關標籤/搜索