代码之家  ›  专栏  ›  技术社区  ›  Mike Rosenblum

如果“Process.HasExited”抛出异常,我是否可以假定该进程已消失?

  •  5
  • Mike Rosenblum  · 技术社区  · 16 年前

    Func<int> OpenExcelProcessesCount = 
        () => System.Diagnostics.Process.GetProcessesByName("Excel")
                  .Where(p => !p.HasExited)
                  .Count();
    

    然后,我用如下代码检索各个点的计数:

    int excelAppCount = OpenExcelProcessesCount();
    

    这段代码已经100%正常运行了几个月。突然,今天,它不断地给我一个例外,如下所示:

    Exception: ApplicationThreadException
    
    Message: Access is denied
    
    Stack Trace:
    
       at System.Diagnostics.ProcessManager.OpenProcess(Int32
    

    processId,Int32访问,布尔值 throwIfExited)

       at System.Diagnostics.Process.GetProcessHandle(Int32
    

    访问,布尔throwIfExited)

       at System.Diagnostics.Process.get_HasExited()
    
       etc...
    

    基本上,呼吁 Process.HasExited System.Diagnostics.Process.get_HasExited() 在堆栈跟踪中,如上所示)正在失败。错误消息“访问被拒绝”听起来好像我没有该进程的管理权限,但只有存在的Excel进程将在当前用户登录下创建,并且用户始终可以访问自己的进程。我的.NET代码也在完全信任的情况下运行。

    最终失败的路线是 System.Diagnostics.ProcessManager.OpenProcess(Int32 processId, Int32 access, Boolean throwIfExited) . 我想知道对于'throwIfExited'参数,它是否以'true'的值传递。如果是这样的话,我想我可以保护你的电话 进程已退出 HasExited 事实上,这是“真实的”。但这是一个安全的假设吗??

    我不太愿意做出这样的假设,特别是因为错误消息是“访问被拒绝”。有人知道我如何解决这个问题,或者我可能测试什么来找出发生了什么吗?

    我在堆栈溢出上能找到的唯一类似线程如下: Why did hasExited throw ‘System.ComponentModel.Win32Exception’?

    “既然你在做runas,你只需要 不处理查询信息访问, 因此GetExitCodeProcess失败,这 结果在hasEnded抛出了一个Win32 例外。”

    我真的不明白这个答案,也不知道这是否适用于我的情况,但我想我应该提一下。如果有人认为这可能是我面临的情况,那么如果有人能为我澄清这个答案,我将不胜感激(我是一名Excel程序员,没有太多处理流程的经验。)

    提前非常感谢。。。

    更新:

    据我所知,这是某种一次性的腐败。我所面临的问题开始变得越来越奇怪,因为一组功能完美的单元测试开始在其他“不可能”的地方出现故障。一次简单的重启就解决了这个问题以及我所面临的所有其他问题。

    我最好的猜测是我有某种奇怪的腐败。也许是腐败被摧毁了,或者我有一个挂起的Excel实例,它非常腐败,甚至“流程”操作也不一定稳定。没有结论,但这是我现在能想到的。

    对于那些花时间回答并帮助我的回复者,我感谢你们。

    3 回复  |  直到 9 年前
        1
  •  4
  •   itowlson    16 年前

    您所引用的答案可能适用于您的情况。据我所知,它基本上是说,如果您正在查看的进程是在不同的用户帐户下运行的,那么 HasExited

    现在您会说“现有的唯一Excel进程将在当前用户登录下创建。”但假设情况并非如此。假设有另一个Excel进程运行在同一个框中,在另一个用户帐户下(可能有一个进程是由其他人使用OLE Automation启动的,没有得到正确清理或挂起。)然后GetProcessByName将拾取它,但HasExit将失败。

    因此,在调用OpenExcelProcessCount()方法之前,请添加一点日志记录,以转储从GetProcessByName(“Excel”)返回的所有进程的进程ID。然后根据任务管理器或您希望在您的帐户下运行的Excel进程数检查这些。如果有一个ID与“预期的”Excel流程不对应,则可能是罪魁祸首。

        2
  •  8
  •   Cody Gray Felix    6 年前

    Process.HasExited 如果目标进程正在提升而您的进程没有提升,则可以引发拒绝访问异常。同样的情况也发生在 StartTime 财产也是。

    Bugs in System.Diagnostics.Process Class

        3
  •  4
  •   user11913024 user11913024    7 年前

    8年后,.NET Process类中仍然存在此问题,这迫使您使用非托管代码检查受保护的进程。Giorgio的回答和博客帖子都非常好,尽管测试一个过程是否已经退出比他说的稍微复杂一些:)以下是对我有效的方法:

        hProcess = OpenProcess(ProcessAccessFlags.PROCESS_QUERY_LIMITED_INFORMATION, false, processId);
    
        GetExitCodeProcess(hProcess, out uint ExitCode);
        if (ExitCode != 259) // ExitCode of 259 is STILL_ACTIVE
        {
            CloseHandle(hProcess);
            return false;
        }
    
        // do your thing, this process is alive and you have a handle now
    
        CloseHandle(hProcess)
    

        [DllImport("kernel32.dll")]
        static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode);
    
        [DllImport("kernel32.dll")]
        private static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool CloseHandle(IntPtr handle);
    
        [Flags]
        public enum ProcessAccessFlags : uint
        {
            PROCESS_QUERY_LIMITED_INFORMATION = 0x00001000,
        }
    
        4
  •  1
  •   jasonh    16 年前

    读后 the documentation :

    使用此方法创建一个 新流程组件和关联 他们拥有所有的流程资源 本地计算机上的文件。

    HasExited

        5
  •  0
  •   Niklas Peter    5 年前
    return process.WaitForExit(0);
    

    看起来问题少了。