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


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

1 代碼入口

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

/// <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 參考鏈接


原文鏈接:
https://www.cnblogs.com/jasongrass/p/11761153.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM