Process.WaitForExit在不同的机器上不一致

此代码在大量计算机上按预期运行。 但是在一台特定的机器上,对WaitForExit()的调用似乎被忽略了,实际上将该进程标记为已退出。

 static void Main(string[] args) { Process proc = Process.Start("notepad.exe"); Console.WriteLine(proc.HasExited); //Always False proc.WaitForExit(); //Blocks on all but one machines Console.WriteLine(proc.HasExited); //**See comment below Console.ReadLine(); } 

请注意,与SO上的类似问题不同,被调用的进程是notepad.exe (出于测试原因),因此不太可能出现错误 – 即它不会产生第二个子进程并关闭。 即便如此,它也无法解释为什么它适用于所有其他机器。

在问题机器上,第二次调用Console.WriteLine(proc.HasExited))返回true即使在屏幕和任务管理器中记事本仍然清晰打开。

该机器运行的是Windows 7和.NET 4.0。

我的问题是; 该特定机器上的条件可能导致这种情况? 我应该检查什么?

编辑 – 到目前为止我尝试过的事情/更新/可能相关的信息:

  • 重新安装.NET。
  • 关闭任务管理器中我不知道的任何进程。
  • Windows尚未在此计算机上激活。
  • 根据评论中的建议,我尝试使用GetProcessesByName获取“现有”进程ID,但这只是在问题机器上返回一个空数组。 因此,很难说即使使用WaitForExit也存在问题,因为即使在调用WaitForExit之前调用GetProcessesByName也不会返回该进程。
  • 在问题机器上,生成的记事本进程的ParentID是代码手动启动的记事本进程的ID,换句话说,记事本正在生成子进程并终止自身。

问题是默认情况下Process.StartInfo.UseShellExecute设置为true。 将此变量设置为true,而不是自己启动进程,您要求shell为您启动它。 这可能非常有用 – 它允许您执行诸如“执行”HTML文件之类的操作(shell将使用适当的默认应用程序)。

当您想要在执行应用程序后跟踪应用程序(如您所发现的)时,它不太好,因为启动应用程序有时会混淆它应该跟踪哪个实例。

这里发生的原因可能超出了我的回答能力 – 我知道当UseShellExecute == true时,框架使用ShellExecuteEx Windows API,当它使用UseShellExecute == false时,它使用CreateProcessWithLogonW,但为什么一个引导跟踪进程和另一个我不知道,因为他们似乎都返回进程ID。

编辑:经过一番挖掘:

这个问题向我指出了SEE_MASK_NOCLOSEPROCESS标志,它确实在使用ShellExecute时确实设置了。 掩码值的文档说明:

在某些情况下,例如通过DDE对话满足执行时,将不返回句柄。 调用应用程序负责在不再需要时关闭句柄。

所以它确实表明返回进程句柄是不可靠的。 我仍然没有深入了解你可能在这里遇到的特殊边缘情况。

原因可能是病毒替换了notepad.exe以隐藏自身。 如果执行,它会产生记事本并退出(只是一个猜测)。

试试这段代码:

  var process = Process.Start("notepad.exe"); var process2 = Process.GetProcessById(process.Id); while (!process2.HasExited) { Thread.Sleep(1000); try { process2 = Process.GetProcessById(process.Id); } catch (ArgumentException) { break; } } MessageBox.Show("done"); 

在Process.Start()之后,使用taskmanager检查notepad.exe的进程ID,并validation它是否与process.Id相同;

哦,你真的应该使用notepad.exe的完整路径

  var notepad = Path.Combine(Environment.GetFolderPath( Environment.SpecialFolder.Windows), "notepad.exe"); Process.Start(notepad);