180

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

4

13 回答 13

285

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

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);
}
于 2008-11-04T16:14:32.080 回答
32

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

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课程是内部的...

于 2008-11-06T11:47:28.717 回答
19

同步解决方案:

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.");
}
于 2008-11-04T16:57:33.897 回答
11

这应该是一个单行:

public static class ProcessHelpers {
    public static bool IsRunning (string name) => Process.GetProcessesByName(name).Length > 0;
}
于 2016-07-06T22:05:46.780 回答
10

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() 方法关闭的情况过程。

于 2014-01-31T14:51:18.197 回答
3

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

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

第二项是进程句柄。虽然它与 Id 有相同的问题,但使用起来更尴尬。

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

于 2008-11-04T16:35:08.997 回答
1

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

于 2008-11-04T16:24:39.690 回答
0

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

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

您还可以设置 EnableRaisingEvents 并处理 Exited 事件(异步发送)或调用 WaitForExit() 如果您想阻止。

于 2008-11-04T16:41:16.880 回答
0

您可以为您想要的进程实例化一次 Process 实例,并继续使用该 .NET Process 对象跟踪该进程(它将继续跟踪,直到您明确调用该 .NET 对象上的 Close,即使它正在跟踪的进程已经死亡[这是为了能够给你进程关闭的时间,也就是 ExitTime 等])

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

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

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

于 2011-09-24T19:48:10.787 回答
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 );

它有效(到目前为止)

于 2012-12-17T17:15:40.757 回答
0
string process = "notepad";
if (Process.GetProcessesByName(process).Length > 0)
{
    MessageBox.Show("Working");
}
else
{
    MessageBox.Show("Not Working");
}

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

于 2013-07-11T21:07:10.900 回答
0

尽管 .Net 框架支持通过进程 ID 检查现有进程的 API,但这些功能非常慢。运行 Process.GetProcesses() 或 Process.GetProcessById/Name() 会消耗大量 CPU 周期。

通过 ID 检查正在运行的进程的一种更快的方法是使用本机 API OpenProcess()。如果返回句柄为 0,则该进程不存在。如果句柄不为 0,则进程正在运行。由于获得许可,无法保证此方法始终 100% 有效。

于 2017-08-09T03:09:40.813 回答
0

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

  • 不保证任何实例成员都是线程安全的。这意味着在尝试评估对象的属性时,快照的生命周期可能会出现竞争条件。
  • 在不允许评估此属性和其他此类属性的权限的情况下,进程句柄将为 ACCESS DENIED 抛出 Win32Exception。
  • 对于 ISN'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["?"]:

  • “父进程 ID”
  • “进程 ID”
  • “进程名称”
  • “SECURITY_DESCRIPTOR”
  • “会话 ID”
  • “席德”
  • “TIME_CREATED”
于 2019-04-17T06:45:16.757 回答