首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >C#/WPF 仅启动一个进程实例

C#/WPF 仅启动一个进程实例

作者头像
jgrass
发布2024-12-25 16:19:17
发布2024-12-25 16:19:17
4190
举报
文章被收录于专栏:蔻丁杂记蔻丁杂记

如何实现仅启动一个 WPF 进程实例,并在打开第二个时,自动唤起之前打开的进程。

1 代码入口

App.xaml.cs 文件中,重写 OnStartup 方法,并添加 Mutex 进程锁。

代码语言:javascript
复制
/// <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 唤起已经启动的进程

代码语言:javascript
复制
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 函数引入:

代码语言:javascript
复制
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 完整代码

代码语言:javascript
复制
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://cloud.tencent.com/developer/article/2481471

本作品采用 「署名 4.0 国际」 许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年10月29日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 代码入口
  • 2 唤起已经启动的进程
  • 3 完整代码
  • 4 参考链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档