【问题标题】:How can I know if a process is running?我怎么知道一个进程是否正在运行?
【发布时间】:2010-09-20 17:00:36
【问题描述】:

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

【问题讨论】:

    标签: c# .net process


    【解决方案1】:
    string process = "notepad";
    if (Process.GetProcessesByName(process).Length > 0)
    {
        MessageBox.Show("Working");
    }
    else
    {
        MessageBox.Show("Not Working");
    }
    

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

    【讨论】:

    • 不会反过来吧?如果长度 == 0 表示不工作?
    • 答案与 Patrick Desjardins 相同:stackoverflow.com/a/262291/7713750
    • 长度 > 0 表示找到进程。
    • 这可能有错误,(length == 0 应该显示 Not Working)但仍然可以完成工作。
    • 已编辑以解决有关长度 == 0 的 cmets。
    【解决方案2】:

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

    • 不保证任何实例成员都是线程安全的。这意味着在尝试评估对象的属性时,快照的生命周期可能会出现竞争条件。
    • 如果不允许评估此属性和其他此类属性的权限,进程句柄将抛出 Win32Exception for ACCESS DENIED。
    • 对于 ISN'T RUNNING 状态,在尝试评估其某些属性时也会引发 ArgumentException。

    不管别人提到的属性是不是内部的,如果权限允许,你仍然可以通过反射从他们那里获取信息。

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

    您可以为 Snapshot 绑定 Win32 代码,也可以使用速度较慢的 WMI

    HANDLE CreateToolhelp32Snapshot(
      DWORD dwFlags,
      DWORD th32ProcessID
    );
    

    另一个选项是OpenProcess / CloseProcess,但您仍然会遇到与以前相同的异常抛出的相同问题。

    对于 WMI - OnNewEvent.Properties["?"]:

    • “父进程 ID”
    • “进程 ID”
    • “进程名称”
    • “SECURITY_DESCRIPTOR”
    • “会话 ID”
    • “席德”
    • “TIME_CREATED”

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

        这应该是一个单行:

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

        【讨论】:

          【解决方案5】:

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

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

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

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

          【讨论】:

            【解决方案6】:

            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 更明确地说明了问题所在。
            • @Sean 我通常会同意你的观点,但这是一种扩展方法。鉴于语法,我认为抛出空指针异常更合适,只是感觉更符合调用空对象的方法。
            • 这将每次触发 FirstHandledException 事件处理程序。哥们,如何向您的日志发送垃圾邮件。
            【解决方案7】:

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

            【讨论】:

            • 如果把这个方法放在一个循环中,会消耗很多CPU周期。我建议使用 GetProcessByName() 或 GetProcessByID()。
            【解决方案8】:

            我尝试了 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 );
            

            它有效(到目前为止)

            【讨论】:

            • openApplication.HasExited(),HasExited 不是函数。正确的方法是openApplication.HasExited
            【解决方案9】:

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

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

            当关联的进程退出时(即,当它被 操作系统通过正常或异常终止),系统 存储有关进程的管理信息并返回到 调用了 WaitForExit 的组件。然后 Process 组件可以 通过使用 处理退出的进程。

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

            【讨论】:

              【解决方案10】:

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

              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 异常(因为无论如何都会抛出空引用异常,并且您没有对该异常执行任何操作。此外,如果您没有调用 Start(),您将收到 InvalidOperationException方法或者您调用了 close() 方法。我发布了另一个答案来解释这两种情况。
              • 如果另一个进程获取了不再运行的原始进程的 id 怎么办?有可能吗?
              【解决方案11】:

              同步解:

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

              【讨论】:

              • 对于第一个选项:我如何知道进程是否首先启动?
              【解决方案12】:

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

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

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

              【讨论】:

                【解决方案13】:

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

                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#。我并不怀疑,我认为它有效,但我从未见过没有 { } 的 if else。
                • @MatthewD: C# if/else 只有一行长度的语句不需要用花括号来指示块语句。这也适用于foreachfor 语句。它归结为编码风格。
                • 我也对此进行了一些研究,找到了该信息,但我没有看到for 信息。多年的 c# .net 开发,我从未见过这种风格。就像他们说的,“你每天都会学到新东西”。谢谢你的帖子和回复..
                • @MatthewD 是的,这实际上适用于大多数语言(如 Java)。避免这样的单行语句并始终放置花括号通常是一种好习惯,因为将来您可能必须在其中添加更多语句,在这种情况下,当您需要它们时,大括号已经存在了。但是对于这样的事情,如果你 100% 确定你只需要一个语句,那么可以这样做并且在语法上是有效的。
                • 如果找不到进程,请尝试删除扩展。 (例如:.exe)
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2011-04-11
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-08-29
                相关资源
                最近更新 更多