如何实现仅启动一个 WPF 进程实例,并在打开第二个时,自动唤起之前打开的进程。1 代码入口在 App.xaml.cs 文件中,重写 OnStartup 方法,并添加 Mutex 进程锁。/// summary/// 只打开一个进程/// /summary...
如何实现仅启动一个 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);
}
}
唤起已经启动的进程
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);
}
}
}
}
参考链接
- 博客后台管理 - 博客园
- Win32 程序在启动时激活前一个启动程序的窗口 - walterlv - 吕毅 - CSDN博客
沃梦达教程
本文标题为:C#/WPF 仅启动一个进程实例
基础教程推荐
猜你喜欢
- c# – 在Amazon Web Services上扩展SQL Server 2023-11-23
- C#设计模式之Singleton模式 2023-02-25
- C#多线程之线程绑定ThreadLocal类 2023-06-15
- C#去除字符串中的反斜杠实例(推荐) 2022-11-28
- C# 多线程中经常访问同一资源可能造成哪些问题 2023-05-31
- 浅谈C# async await 死锁问题总结 2023-03-14
- C#中foreach循环对比for循环的优势和劣势 2022-11-11
- c#中多线程间的同步示例详解 2023-05-06
- WPF如何自定义TabControl控件样式示例详解 2022-12-11
- C#排序算法之堆排序 2023-02-07