28

我有 C# winforms 应用程序需要不时启动一个外部 exe,但如果一个进程已经在运行,我不希望启动另一个进程,而是切换到它。

那么在下面的示例中,我将如何在 C# 中这样做呢?

using System.Diagnostics;

...

Process foo = new Process();

foo.StartInfo.FileName = @"C:\bar\foo.exe";
foo.StartInfo.Arguments = "Username Password";

bool isRunning = //TODO: Check to see if process foo.exe is already running


if (isRunning)
{
   //TODO: Switch to foo.exe process
}
else
{
   foo.Start(); 
}
4

9 回答 9

37

这应该为你做。

检查流程

//Namespaces we need to use
using System.Diagnostics;

public bool IsProcessOpen(string name)
{
    //here we're going to get a list of all running processes on
    //the computer
    foreach (Process clsProcess in Process.GetProcesses()) {
        //now we're going to see if any of the running processes
        //match the currently running processes. Be sure to not
        //add the .exe to the name you provide, i.e: NOTEPAD,
        //not NOTEPAD.EXE or false is always returned even if
        //notepad is running.
        //Remember, if you have the process running more than once, 
        //say IE open 4 times the loop thr way it is now will close all 4,
        //if you want it to just close the first one it finds
        //then add a return; after the Kill
        if (clsProcess.ProcessName.Contains(name))
        {
            //if the process is found to be running then we
            //return a true
            return true;
        }
    }
    //otherwise we return a false
    return false;
}


于 2008-09-09T02:58:09.653 回答
24

您也可以使用 LINQ,

var processExists = Process.GetProcesses().Any(p => p.ProcessName.Contains("<your process name>"));
于 2008-09-09T03:35:58.780 回答
6

我在 VB 运行时中使用了 AppActivate 函数来激活现有进程。您必须将 Microsoft.VisualBasic dll 导入 C# 项目。

using System;
using System.Diagnostics;
using Microsoft.VisualBasic;

namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            Process[] proc = Process.GetProcessesByName("notepad");
            Interaction.AppActivate(proc[0].MainWindowTitle);
        }
    }
}
于 2008-09-09T03:09:34.710 回答
4

您可以使用Process.GetProcesses方法简单地枚举进程。

于 2008-09-09T03:01:27.693 回答
2

我发现 Mutex 不像在控制台应用程序中那样工作。因此,使用 WMI 查询可以使用任务管理器窗口看到的进程将解决您的问题。

使用这样的东西:

static bool isStillRunning() {
   string processName = Process.GetCurrentProcess().MainModule.ModuleName;
   ManagementObjectSearcher mos = new ManagementObjectSearcher();
   mos.Query.QueryString = @"SELECT * FROM Win32_Process WHERE Name = '" + processName + @"'";
   if (mos.Get().Count > 1)
   {
        return true;
    }
    else
        return false;
}

注意:添加程序集引用“System.Management”以启用智能感知类型。

于 2014-05-23T08:26:41.043 回答
1

我认为您的问题的完整答案需要了解当您的应用程序确定 foo.exe 的实例已经在运行时会发生什么,即“//TODO:切换到 foo.exe 进程”实际上是什么意思?

于 2008-09-09T03:07:23.483 回答
1

在过去的项目中,我需要防止进程多次执行,因此我在该进程的 init 部分添加了一些代码,该代码创建了一个命名互斥锁。在继续该过程的其余部分之前,已创建并获取了该 mutext。如果进程可以创建互斥体并获取它,那么它是第一个运行的。如果另一个进程已经控制了互斥锁,那么失败的不是第一个,所以它立即退出。

由于对特定硬件接口的依赖,我只是试图阻止第二个实例运行。根据您对“切换到”行的需求,您可能需要更具体的解决方案,例如进程 ID 或句柄。

此外,我可以访问我试图启动的进程的源代码。如果不能修改代码,添加互斥锁显然不是一种选择。

于 2008-09-09T03:43:28.687 回答
1

要记住两个问题:

  1. 您的示例涉及在命令行上放置密码。秘密的明文表示可能是一个安全漏洞。

  2. 枚举进程时,问问自己真正想枚举哪些进程。所有用户,还是只是当前用户?如果当前用户登录了两次(两个桌面)怎么办?

于 2008-09-09T04:29:19.153 回答
0

Mnebuerquo 写道:

此外,我可以访问我试图启动的进程的源代码。如果不能修改代码,添加互斥锁显然不是一种选择。

我没有对我要运行的进程的源代码访问权限。

一旦我发现它已经在运行,我最终使用进程 MainWindowHandle 切换到进程:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
 public static extern bool SetForegroundWindow(IntPtr hWnd);
于 2008-09-09T03:50:13.427 回答