.NET进程存活检测异常:Notepad与Calc运行时仍触发退出报错
解决Process.Responding和HasExited检测运行状态异常的问题
我一眼就瞅到你代码里的坑了!你写的这个看门狗程序,明明记事本和计算器都在运行,但调用Process.Responding或者HasExited时却抛出异常,核心问题出在重复复用同一个ProcessStartInfo对象上。
问题根源
ProcessStartInfo是引用类型,不是值类型。你在Main方法里只创建了一个startInfo对象,先设置成记事本的路径传给第一个AppRunner,然后又把同一个对象的FileName改成计算器路径传给第二个AppRunner。这就导致两个AppRunner里的Process.StartInfo指向的是同一个内存对象——第一个启动的记事本进程,后续检测状态时,它关联的StartInfo已经被改成计算器的路径了!当你调用Program.Refresh()时,.NET会尝试根据当前的StartInfo去匹配系统中的进程,自然找不到原来的记事本进程,于是就抛出了“进程已退出”的异常,哪怕记事本其实还好好跑着。
修复方案
有两种简单的修复方式,选哪种都行:
方案1:给每个应用创建独立的ProcessStartInfo实例
不要复用同一个对象,给记事本和计算器分别创建自己的ProcessStartInfo:
static void Main(string[] args) { List<AppRunner> programs = new List<AppRunner>(); // 单独创建记事本的启动信息 ProcessStartInfo notepadInfo = new ProcessStartInfo(); notepadInfo.FileName = @"C:\Windows\system32\Notepad.exe"; programs.Add(new AppRunner(notepadInfo)); // 单独创建计算器的启动信息 ProcessStartInfo calcInfo = new ProcessStartInfo(); calcInfo.FileName = @"C:\Windows\system32\Calc.exe"; programs.Add(new AppRunner(calcInfo)); // 后续代码不变... }
方案2:在AppRunner内部复制ProcessStartInfo
如果想保留外部传参的方式,可以在AppRunner的构造函数里创建传入对象的副本,这样外部修改不会影响内部的Process实例:
public AppRunner(ProcessStartInfo processrunner) { this.Program = new Process(); // 创建传入对象的副本,切断引用关联 this.Program.StartInfo = new ProcessStartInfo(processrunner); StartExecute(); }
额外优化建议
你的checkAlive方法还有点小问题:直接访问Responding可能会在进程无UI或者状态异常时抛异常。可以先检查HasExited,再安全地判断Responding:
public bool checkAlive() { this.Program.Refresh(); if (this.Program.HasExited) { return false; } // 对无UI进程,Responding会抛出异常,这里加个try-catch兜底 try { return this.Program.Responding; } catch (InvalidOperationException) { // 兜底判断:只要进程没退出,就认为是存活的 return !this.Program.HasExited; } }
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

