如何使用 C# 查明进程是否已在运行?
-
09-06-2019 - |
题
我有一个 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();
}
解决方案
这应该适合你。
//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;
}
其他提示
您也可以使用 LINQ,
var processExists = Process.GetProcesses().Any(p => p.ProcessName.Contains("<your process name>"));
我在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);
}
}
}
您可以简单地使用枚举进程 进程.GetProcesses 方法。
我发现互斥体不像在控制台应用程序中那样工作。因此,使用 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”以启用类型智能感知。
我认为要完整回答您的问题,需要了解当您的应用程序确定 foo.exe 的实例已经在运行时会发生什么,即 '//TODO:切换到foo.exe进程'到底是什么意思?
在过去的项目中,我需要防止进程的多次执行,因此我在该进程的 init 部分添加了一些代码,用于创建一个命名互斥体。在继续该过程的其余部分之前创建并获取该互斥体。如果进程可以创建互斥锁并获取它,那么它就是第一个运行的进程。如果另一个进程已经控制了互斥体,那么失败的进程不是第一个,因此它会立即退出。
由于对特定硬件接口的依赖,我只是想阻止第二个实例运行。根据“切换到”行的需要,您可能需要更具体的解决方案,例如进程 ID 或句柄。
此外,我还可以访问我试图启动的进程的源代码。如果无法修改代码,添加互斥锁显然不是一个选择。
需要记住两个问题:
您的示例涉及将密码放在命令行上。秘密的清晰文本表示可能是安全漏洞。
列举过程时,请问自己真的想枚举哪种过程。所有用户,还是当前用户?如果当前用户以两次(两个台式机)登录(两个台式机)怎么办?
姆内布尔科写道:
另外,我还可以访问试图启动的过程。如果您无法修改代码,则添加MUTEX显然不是一个选项。
我无权访问我想要运行的进程的源代码。
一旦我发现它已经在运行,我最终使用进程 MainWindowHandle 切换到该进程:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool SetForegroundWindow(IntPtr hWnd);