• C#如何限制程序只能同时运行一个实例
  • 发布于 1周前
  • 36 热度
    0 评论
在开发桌面应用程序时,可能会遇到这样一种需求:限制程序只能同时运行一个实例。如果用户试图再次启动同一个程序,应该将已经运行的程序窗口置于前台而不是启动一个新实例。这篇文章提供了一种通过检测当前程序实例并激活已运行实例的方法。

核心思路
检查是否已有程序实例运行
使用 System.Diagnostics.Process 获取当前程序进程,并与系统中所有同名的程序进程进行比较。如果发现另一个同名进程,则认为程序已经运行。

激活已运行的程序窗口
如果发现已有实例运行,使用 Win32 API 操作将其窗口置于前台,避免用户启动多个实例。

运行主程序逻辑
如果没有其他实例运行,正常启动主程序。

代码解析
1. 检查是否已有程序运行
以下代码通过进程名称筛选当前运行的程序进程列表,返回除当前进程外的其他同名进程(如果存在):
public static Process GetExistProcess()
{
    Process currentProcess = Process.GetCurrentProcess(); // 当前程序
    foreach (Process process in Process.GetProcessesByName(currentProcess.ProcessName))
    {
        if (process.Id != currentProcess.Id) // 找到其他同名进程
        {
            return process; // 返回已运行的进程
        }
    }
    return null; // 没有其他实例
}
2. 主程序入口
在 Main 方法中调用 GetExistProcess 检查程序实例:
static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        // 堆代码 duidaima.com
        var runningProcess = GetExistProcess();
        if (runningProcess != null) // 如果有实例运行
        {
            IntPtr mainWindowHandle = runningProcess.MainWindowHandle;
            if (mainWindowHandle == IntPtr.Zero) // 窗口被隐藏
            {
                mainWindowHandle = FindWindow(null, "唯一程序");
            }
            ShowWindowAsync(mainWindowHandle, 1); // 显示窗口
            SetForegroundWindow(mainWindowHandle); // 置于前台
        }
        else
        {
            Application.Run(new MainForm()); // 启动新实例
        }
    }
}
3. Win32 API 调用
以下是关键的 Win32 API 函数,用于操作窗口显示和前台设置:
[DllImport("User32.dll", EntryPoint = "FindWindow")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);

[DllImport("user32.dll ")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
FindWindow: 根据窗口名称查找窗口句柄。
ShowWindowAsync: 显示或隐藏窗口。

SetForegroundWindow: 将窗口设置为前台窗口。


注意事项
1.窗口名称匹配问题
如果窗口标题动态变化,FindWindow 的效果可能不佳,需保证窗口标题唯一或改用其他识别方法。

2.权限问题
如果以管理员权限运行程序,SetForegroundWindow 操作可能会被限制。需要确保权限一致。

3.多线程问题
如果程序使用了多线程,需注意线程间的窗口操作同步。

优化建议
1.使用互斥量
利用 Mutex 可以更简洁地实现程序唯一性。例如:
static Mutex mutex = new Mutex(true, "UniqueAppName", out bool createdNew);
if (!createdNew)
{
    // 已经有实例运行
    return;
}
2.窗口句柄缓存
可以在程序启动时缓存主窗口句柄,避免频繁调用 FindWindow。

3.日志记录
在实际应用中建议记录重复启动的尝试,以便后续调试和优化。

总结
这是一种基于进程和 Win32 API 的方法来保持程序唯一性的解决方案。代码逻辑清晰,适用于大多数桌面应用场景。如果你有更复杂的需求或更高的性能要求,建议结合互斥量或现代框架特性来实现更可靠的方案。
用户评论