检测应用程序的另一个实例是否已在运行

时间:2010-07-06 21:01:08

标签: c# visual-studio-2008 mutex multiple-instances

如果已经有实例运行,我的应用程序在加载时需要略微不同。

我理解如何使用互斥锁来阻止其他实例加载,但这并不能完全解决我的问题。

例如:

  • 实例1加载,获取互斥锁。
  • 实例2加载,无法获取互斥锁,知道还有另一个实例。到目前为止,这么好。
  • 实例1关闭,释放互斥锁。
  • 实例3加载,获取互斥锁,不知道实例2仍在运行。

有什么想法吗?值得庆幸的是,它不需要处理多个用户帐户或类似的东西。

(C#,桌面应用程序)

编辑:为了澄清,应用程序不需要限制在单个实例上,只要执行另一个已经运行的实例,就执行稍微不同的启动操作。多个实例都很好(并且是预期的)。

5 个答案:

答案 0 :(得分:12)

这可能会做你想要的。它具有很好的附加功能,可以使已经运行的实例前进。

编辑:更新了代码以自动确定应用程序标题。

using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;

static void Main()
{
    if (!EnsureSingleInstance())
    {
        return;
    }

    //...
}

static bool EnsureSingleInstance()
{
    Process currentProcess = Process.GetCurrentProcess();

    var runningProcess = (from process in Process.GetProcesses()
                          where
                            process.Id != currentProcess.Id &&
                            process.ProcessName.Equals(
                              currentProcess.ProcessName,
                              StringComparison.Ordinal)
                          select process).FirstOrDefault();

    if (runningProcess != null)
    {
        ShowWindow(runningProcess.MainWindowHandle, SW_SHOWMAXIMIZED);
        SetForegroundWindow(runningProcess.MainWindowHandle);

        return false;
    }

    return true;
}

[DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

[DllImport("user32.dll")]
private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow);

private const int SW_SHOWMAXIMIZED = 3;

答案 1 :(得分:2)

另一种方法是检测正在运行的实例,如Scott Hanselman's blog

中所述

他的例子在第二次尝试时激活第一个实例。

然而,如果那是你想要的,那么让第二个实例停下来就不难了。

答案 2 :(得分:1)

尝试使用信号量而不是互斥锁

答案 3 :(得分:0)

您是否可以在使用GetLastError()创建互斥锁后查看CreateMutex()?如果它返回ERROR_ALREADY_EXISTS,则表示您的应用程序正在运行另一个实例。

根据http://msdn.microsoft.com/en-us/library/ms682411%28VS.85%29.aspx

  

如果互斥锁是一个命名的互斥锁,那么   对象在此函数之前存在   调用,返回值是句柄   现有对象GetLastError   返回ERROR_ALREADY_EXISTS,   bInitialOwner被忽略了   调用线程未被授予   所有权。但是,如果来电者有   有限的访问权限,功能   将失败,ERROR_ACCESS_DENIED和   调用者应该使用OpenMutex   功能

编辑:刚刚意识到这是一个C#/ .Net问题,抱歉。

在.Net中,使用返回createdNew标志的Mutex构造函数http://msdn.microsoft.com/en-us/library/bwe34f1k%28VS.80%29.aspx

public Mutex (
    bool initiallyOwned,
    string name,
    out bool createdNew
)

答案 4 :(得分:0)

一个好方法是使用Sandor解决方案,但使用WMI获取进程列表,如下所述:C#: How to get the full path of running process?(Jeff的解决方案)。这样,您还可以检查其他正在运行的实例是否与路径和远程终端会话ID匹配:

    static bool EnsureSingleInstance()
    {
        Process currentProcess = Process.GetCurrentProcess();

        var wmiQueryString = "SELECT ProcessId, ExecutablePath, CommandLine FROM Win32_Process";
        using (var searcher = new ManagementObjectSearcher(wmiQueryString))
        using (var results = searcher.Get())
        {
            var query = from p in Process.GetProcesses()
                        join mo in results.Cast<ManagementObject>()
                        on p.Id equals (int)(uint)mo["ProcessId"]
                        select new
                        {
                            Process = p,
                            Path = (string)mo["ExecutablePath"],
                            CommandLine = (string)mo["CommandLine"],
                        };

            var runningProcess = (from process in query
                                  where
                                    process.Process.Id != currentProcess.Id &&
                                    process.Process.ProcessName.Equals(
                                      currentProcess.ProcessName,
                                      StringComparison.Ordinal) &&
                                      process.Path == currentProcess.MainModule.FileName &&
                                      process.Process.SessionId == currentProcess.SessionId
                                  select process).FirstOrDefault();

            return runningProcess == null;
        }
    }