如何實現僅啓動一個 WPF 進程實例,並在打開第二個時,自動喚起以前打開的進程。html
在 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); } }
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);
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); } } } }