此代码在大量计算机上按预期运行。但是在一台特定的机器上,对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上的similar question不同,被调用的进程是notepad.exe
(出于测试原因),因此不太可能出现错误 - 即它不会产生第二个子 - 处理和关闭。即便如此,也无法解释为什么它适用于所有其他机器。
在问题机器上,对Console.WriteLine(proc.HasExited))
的第二次调用会返回true
,即使记事本仍然在屏幕上和任务管理器中都是明显打开的。
该计算机正在运行Windows 7和.NET 4.0。
我的问题是;该特定机器上的条件可能导致这种情况?我应该检查什么?
编辑 - 到目前为止我尝试过的事情/更新/可能相关的信息:
GetProcessesByName
获取“现有”流程ID,但这只是在问题机器上返回一个空数组。因此,很难说问题与WaitForExit
一致,因为即使在调用GetProcessesByName
之前调用WaitForExit
也不会返回此过程。答案 0 :(得分:7)
问题是默认情况下Process.StartInfo.UseShellExecute设置为true。将此变量设置为true,而不是自己启动该过程,您要求shell为您启动它。这可能非常有用 - 它允许您执行诸如“执行”HTML文件之类的操作(shell将使用适当的默认应用程序)。
当您想要在执行应用程序后跟踪应用程序(如您所发现的)时,它不太好,因为启动应用程序有时会对应该跟踪的实例感到困惑。
这里发生这种情况的内在细节可能超出了我的回答能力 - 我知道当UseShellExecute == true时,框架使用ShellExecuteEx Windows API,当它使用UseShellExecute == false时,它使用CreateProcessWithLogonW,但是为什么一个导致可跟踪的进程而另一个不是我不知道,因为他们似乎都返回进程ID。
编辑:经过一番挖掘:This question向我指出SEE_MASK_NOCLOSEPROCESS标志,在使用ShellExecute时确实似乎设置了。掩码值的文档说明:
在某些情况下,例如通过DDE满足执行时 对话,将不会返回句柄。调用应用程序是 负责在不再需要时关闭手柄。
所以它确实表明返回进程句柄是不可靠的。我仍然没有深入了解你可能在这里遇到的特殊边缘情况。
答案 1 :(得分:1)
原因可能是病毒替换了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,并验证它与process.Id相同;
哦,你真的应该使用notepad.exe的完整路径
var notepad = Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.Windows), "notepad.exe");
Process.Start(notepad);