Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2008/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 检测应用程序的另一个实例是否已在运行_C#_Visual Studio 2008_Mutex_Multiple Instances - Fatal编程技术网

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

C# 检测应用程序的另一个实例是否已在运行,c#,visual-studio-2008,mutex,multiple-instances,C#,Visual Studio 2008,Mutex,Multiple Instances,如果已经有一个实例在运行,则我的应用程序在加载时的行为需要稍有不同 我知道如何使用互斥来防止额外的实例加载,但这并不能完全解决我的问题 例如: 实例1加载并获取互斥锁。 实例2加载,无法获取互斥,知道还有另一个实例。到目前为止,一切顺利。 实例1关闭,释放互斥锁。 实例3加载、获取互斥锁,但不知道实例2仍在运行。 有什么想法吗?谢天谢地,它不需要处理多个用户帐户或类似的事情 C、 桌面应用程序 编辑:为了澄清这一点,应用程序不需要局限于一个实例,如果已经有另一个实例在运行,只需执行稍微不同的启动

如果已经有一个实例在运行,则我的应用程序在加载时的行为需要稍有不同

我知道如何使用互斥来防止额外的实例加载,但这并不能完全解决我的问题

例如:

实例1加载并获取互斥锁。 实例2加载,无法获取互斥,知道还有另一个实例。到目前为止,一切顺利。 实例1关闭,释放互斥锁。 实例3加载、获取互斥锁,但不知道实例2仍在运行。 有什么想法吗?谢天谢地,它不需要处理多个用户帐户或类似的事情

C、 桌面应用程序


编辑:为了澄清这一点,应用程序不需要局限于一个实例,如果已经有另一个实例在运行,只需执行稍微不同的启动操作即可。可以使用多个实例。

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

另一种方法是检测正在运行的实例,如中所述

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


但是,如果您希望第二个实例停止运行,这并不难。

这可能正是您想要的。它还有一个很好的附加特性,就是将已经运行的实例向前推进

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

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;
在使用CreateMutex创建互斥体之后,您能简单地检查GetLastError吗?如果返回的错误为“已存在”,则存在另一个正在运行的应用程序实例

根据,

如果互斥体是命名互斥体,则 对象在此函数之前存在 调用时,返回值是 现有对象GetLastError 返回错误\u已\u存在, 忽略bInitialOwner,并且 调用线程未被授权 所有权但是,如果调用方 有限访问权限,功能 将失败,错误为访问被拒绝,并且 调用者应使用OpenMutex 功能

编辑:刚刚意识到这是一个C/.Net问题,对不起

在.Net中,使用返回createdNew标志的互斥构造函数:


一个很好的方法是使用Sandor解决方案,但使用WMI获取进程列表,如下所述: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;
        }
    }

如果我没记错的话,我想加上APPLICATION-TITLE是不带扩展名的可执行文件名。@sztomi:谢谢你激发了我的记忆,让代码自动确定。哈哈,很好。我想当我遇到这个问题时,我硬编码了它。这要好得多:是的,做得很好。完美。在你提到的场景中,想要的行为是什么?实例3是否应该做实例1正在做的事情,而实例2是否应该继续像以前那样?假设您不想确保单个实例,因为这是由互斥体解决的。实例2最终将以任何方式退出在该场景中,实例1的行为是单向的,实例2和3需要使用替代行为。如果有一个实例已经在运行,无论它是什么时候启动的,或者从那以后发生了什么,一个新实例的行为都会略有不同(虽然不是很明显)。不同之处只是加载时的一次性操作。为什么没有人使用现有的机制?只是因为它的名称空间包含VisualBasic!如果作者将它放在一个名称空间Foo中,它将被更多的人使用。
    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;
        }
    }