我如何知道某个进程正在运行?


155

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

Answers:


252

这是使用名称的一种方法:

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);
}

这正是我在寻找的东西。即使这是一篇非常老的文章,您也可以向我解释一下这是如何有效的C#。我对此并不怀疑,我认为它有效,但是我从未见过如果没有{}的话。
MatthewD

4
@MatthewD:if/else长度只有一行的C#语句不需要大括号来表示block语句。这也适用于foreachfor声明。归结为编码风格。
Hallmanac

我也对此进行了一些研究,找到了该信息,但没有看到该for信息。多年的C#.net开发人员和我从未见过这种风格。就像他们说的那样:“您每天都会学到新东西”。谢谢你的职位和答复..
MatthewD

3
@MatthewD是的,这实际上适用于大多数语言(例如Java)。避免这样的单线并总是使用花括号通常是一个好习惯,因为将来总有机会您可能需要在其中添加更多语句,在这种情况下,当您需要它们时,花括号就已经存在。但是对于像这样的事情,如果您100%确定只需要一个语句,就可以这样做并且在语法上是有效的。
David Mordigal '16

1
如果找不到该进程,请尝试删除该扩展名。(例如:.exe)
DxTx

28

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

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班级是内部的...


这是一个很好的答案。但是,您不应该通过参数null异常进行处理(因为无论如何都会引发null引用异常,并且您对该异常不做任何事情。此外,如果不调用Start(),则会收到InvalidOperationException。方法,或者您调用了close()方法。我发布了另一个答案来说明这两种情况:
Aelphaeis 2014年

16

同步解决方案:

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.");
}

6
对于第一种选择:我如何知道该过程是否首先开始?
reshefm

8

reshefm的回答很不错;但是,这并不能说明从未开始过该过程的情况。

这是他发布内容的修改版本。

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

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


就个人而言,我更希望在查看记录的异常时看到ArgumentNullException而不是NullReferenceException,因为ArgumentNullException更清楚地指出了出了什么问题。
肖恩

1
@Sean我通常会同意您的意见,但这是一种扩展方法。我认为在给定语法的情况下抛出空指针异常更合适,它与空对象的调用方法更加一致。
Aelphaeis 2016年

这将每次触发FirstHandledException事件处理程序。向伙伴发送垃圾邮件的方法。
延迟

6

这应该是单线的:

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

3

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

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

第二项是过程句柄。尽管它与Id有相同的问题,但使用起来比较麻烦。

如果您正在寻找中等级别的可靠性,那么只需在当前进程列表中查找具有相同ID的进程即可。


1

Process.GetProcesses()是要走的路。但是,您可能需要使用一个或多个不同的条件来查找您的进程,具体取决于进程的运行方式(即,作为服务还是普通应用程序,无论它是否具有标题栏)。


如果将此方法放在一个循环中,则将花费大量CPU周期。我建议使用GetProcessByName()或GetProcessByID()。

0

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

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

您也可以设置EnableRaisingEvents并处理Exited事件(异步发送),如果要阻止,则调用WaitForExit()。


0

您可以为所需的流程实例化一次Process实例,并继续使用该.NET Process对象跟踪该流程实例(它将一直跟踪直到您明确对该.NET对象调用Close为止,即使它正在跟踪的流程已终止也是如此) [这是为了让您有时间关闭进程,也称为ExitTime等。]

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

当关联的进程退出时(也就是说,当操作系统通过正常或异常终止将其关闭时),系统将存储有关该进程的管理信息,并返回到名为WaitForExit的组件。然后,通过使用已退出进程的句柄,Process组件可以访问包括ExitTime的信息。

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


0

我尝试了Coincoin的解决方案:
在处理某些文件之前,我将其复制为临时文件并打开。
完成后,如果应用程序仍处于打开状态,则将其关闭,然后删除该临时文件:
我只使用一个Process变量,然后对其进行检查:

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 );

它有效(到目前为止)


3
在处openApplication.HasExited(),HasExited不是函数。正确的方法是openApplication.HasExited
caiosm1005

0

尽管.Net框架支持使用API​​来按进程ID检查现有进程,但这些功能非常慢。运行Process.GetProcesses()或Process.GetProcessById / Name()会花费大量的CPU周期。

通过ID检查运行进程的更快方法是使用本机API OpenProcess()。如果返回句柄为0,则表明该进程不存在。如果handle不同于0,则说明该进程正在运行。由于获得许可,无法保证此方法在任何时候都可以100%工作。


0

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

  • 不保证任何实例成员都是线程安全的。这意味着在尝试评估对象的属性时,快照的生存期可能会出现竞争条件。
  • 进程句柄将为ACCESS DENIED抛出Win32Exception,其中不允许评估该属性和其他此类属性的权限。
  • 对于IS N'T RUNNING状态,在尝试评估其某些属性时也会引发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”
  • “ SECURITY_DESCRIPTOR”
  • “ SessionID”
  • “ Sid”
  • “ TIME_CREATED”

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

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


3
不会相反吗?如果长度== 0意味着不工作?
杰伊·雅各布斯

答案与Patrick Desjardins的答案相同:stackoverflow.com/a/262291/7713750
Rekshino

关于长度> 0的另一种方式表示找到了进程。
HaseeB Mir

这可能有错误,(length == 0应该显示Not Working),但仍然可以完成工作。
Momoro
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.