zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Excel VBA 根据下拉框单元格的值来改变另一个下拉框单元格的值
    HTML Encode 和Decode
    端口号8080和8181被占用的解决方法!
    Eclipse中全局搜索和更替
    HTTP协议详解
    SQL server 常用语句
    50道 Sql语句题
    JAVA过滤器与SpringMVC拦截器之间的区别
    javaWeb中 servlet 、request 、response
    Java 中的 request 和response 区别
  • 原文地址:https://www.cnblogs.com/jasongrass/p/11761153.html
Copyright © 2011-2022 走看看