如何知道进程是否正在运行?

当我获得对 System.Diagnostics.Process的引用时,如何知道一个进程当前是否正在运行?

284988 次浏览

这是一种用这个名字来做的方法:

Process[] pname = Process.GetProcessesByName("notepad");
if (pname.Length == 0)
MessageBox.Show("nothing");
else
MessageBox.Show("run");

您可以循环所有进程以获取 ID,以便以后进行操作:

Process[] processlist = Process.GetProcesses();
foreach(Process theprocess in processlist){
Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
}

Process.GetProcesses()是正确的选择。但是您可能需要使用一个或多个不同的标准来找到您的进程,这取决于它是如何运行的(例如,作为一个服务还是一个普通的应用程序,是否有标题栏)。

这取决于您希望这个函数的可靠程度。如果您想知道您所拥有的特定流程实例是否仍在运行并且可以100% 准确地使用,那么您就不走运了。原因是从托管流程对象只有两种方法来标识流程。

第一个是 Process Id。不幸的是,进程 id 并不唯一,可以回收。在进程列表中搜索匹配的 Id 只会告诉您有一个具有相同 Id 的进程正在运行,但它不一定是您的进程。

第二项是 Process Handle。但是它和 Id 有相同的问题,而且使用起来更加尴尬。

如果您正在寻找中级可靠性,那么检查当前进程列表中具有相同 ID 的进程就足够了。

也许(可能)我读错了这个问题,但是您是否正在寻找 HasExted 属性,该属性将告诉您由 Process 对象表示的进程已经退出(正常或不退出)。

如果您所引用的流程具有 UI,您可以使用 Responding 属性来确定 UI 当前是否响应用户输入。

您还可以设置 EnableRaisingEvents 并处理 Exted 事件(异步发送)或者调用 WaitForExit () ,如果您希望阻止。

同步解决方案:

void DisplayProcessStatus(Process process)
{
process.Refresh();  // Important




if(process.HasExited)
{
Console.WriteLine("Exited.");
}
else
{
Console.WriteLine("Running.");
}
}

异步解决方案:

void RegisterProcessExit(Process process)
{
// NOTE there will be a race condition with the caller here
//   how to fix it is left as an exercise
process.Exited += process_Exited;
}


static void process_Exited(object sender, EventArgs e)
{
Console.WriteLine("Process has exited.");
}

这是我使用反射镜后发现的最简单的方法。 我为此创建了一个扩展方法:

public static class ProcessExtensions
{
public static bool IsRunning(this Process process)
{
if (process == null)
throw new ArgumentNullException("process");


try
{
Process.GetProcessById(process.Id);
}
catch (ArgumentException)
{
return false;
}
return true;
}
}

如果进程不存在,则 Process.GetProcessById(processId)方法调用 ProcessManager.IsProcessRunning(processId)方法并抛出 ArgumentException。由于某种原因,ProcessManager类是内部的..。

您可以为所需的流程实例化一次流程实例,并继续使用该实例跟踪流程。NET 进程对象(它将继续跟踪,直到您对其调用 Close。NET 对象,即使它所跟踪的进程已经死亡(这是为了能够给你进程关闭的时间,又名 ExitTime 等)

引用 http://msdn.microsoft.com/en-us/library/fb4aw7b8.aspx:

关联进程退出时(即,当它被 操作系统通过正常或异常终止) ,系统 存储有关进程的管理信息,并返回到 组件调用了 WaitForExit。然后,Process 组件可以 方法访问包括 ExitTime 在内的信息 退出进程的句柄。

因为关联进程已退出,所以 组件不再指向现有的进程资源, 该句柄只能用于访问操作系统的 有关进程资源的信息。系统知道句柄 到流程组件尚未释放的已退出流程, 所以它将 ExitTime 和 Handle 信息保存在内存中,直到 流程组件专门释放资源, 任何时候为 Process 实例调用 Start 时,在 相关进程已终止,您不再需要任何 管理信息。关闭将释放分配的内存 退出程序。

我尝试了 Coincoin 的解决方案:
在处理某个文件之前,我将其作为临时文件复制并打开。
完成后,如果应用程序仍处于打开状态,我将关闭它并删除它 临时档案:
我只是用一个程序变数,然后检查一下:

private Process openApplication;
private void btnOpenFile_Click(object sender, EventArgs e) {
...
// copy current file to fileCache
...
// open fileCache with proper application
openApplication = System.Diagnostics.Process.Start( fileCache );
}

后来我关闭了这个应用程序:

 ...
openApplication.Refresh();


// close application if it is still open
if ( !openApplication.HasExited() ) {
openApplication.Kill();
}


// delete temporary file
System.IO.File.Delete( fileCache );

它(到目前为止)是有效的

string process = "notepad";
if (Process.GetProcessesByName(process).Length > 0)
{
MessageBox.Show("Working");
}
else
{
MessageBox.Show("Not Working");
}

也可以使用计时器每次检查进程

Reshefm 给出了一个很好的答案; 但是,它没有考虑流程从未开始的情况。

这是他发表的文章的修改版本。

    public static bool IsRunning(this Process process)
{
try  {Process.GetProcessById(process.Id);}
catch (InvalidOperationException) { return false; }
catch (ArgumentException){return false;}
return true;
}

我删除了他的 ArgumentNullException,因为它实际上应该是一个 null 引用异常,它无论如何都会被系统抛出,我还考虑了进程从未开始或者使用 close ()方法关闭进程的情况。

这应该是一句俏皮话:

public static class ProcessHelpers {
public static bool IsRunning (string name) => Process.GetProcessesByName(name).Length > 0;
}

尽管支持来自。关于通过进程 ID 检查现有进程的网络框架,这些函数非常慢。运行 Process 需要消耗大量的 CPU 周期。进程()或进程。GetProcessById/Name ().

通过 ID 检查正在运行的进程的一种更快的方法是使用本机 API OpenProcess ()。如果返回句柄为0,则该进程不存在。如果句柄不同于0,则进程正在运行。不能保证这种方法在任何时候都能100% 地工作。

与此相关的问题有很多,其他问题似乎部分解决了:

  • 不能保证任何实例成员都是线程安全的。这意味着在尝试计算对象的属性时,在快照的生存期内可能会出现竞态条件。
  • 进程句柄将引发 ACCESSDENIED 的 Win32Exception,其中不允许计算此属性和其他此类属性的权限。
  • 对于正在运行的状态,当尝试计算其某些属性时,也会引发 ArgumentException。

无论其他人提到的属性是否为内部属性,如果允许,您仍然可以通过反射从它们获得信息。

var x = obj.GetType().GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance);

您可以为 快照调用 Win32代码,也可以使用速度较慢的 WMI

HANDLE CreateToolhelp32Snapshot(
DWORD dwFlags,
DWORD th32ProcessID
);

另一种选择是 OpenProcess/CloseProcess,但是仍然会遇到与之前相同的抛出异常的问题。

对于 WMI-OnNewEvent. Properties [“ ?”] :

  • “ ParentProcessID”
  • “ ProcessID”
  • “ ProcessName”
  • “安全 _ 描述符”
  • “ SessionID”
  • “希德”
  • “ TIME _ Created”