private void UpdateHasExited()
{
SafeProcessHandle handle = null;
try
{
handle = GetProcessHandle(Interop.Advapi32.ProcessOptions.PROCESS_QUERY_LIMITED_INFORMATION | Interop.Advapi32.ProcessOptions.SYNCHRONIZE, false);
if (handle.IsInvalid)
{
_exited = true;
}
else
{
int localExitCode;
// Although this is the wrong way to check whether the process has exited,
// it was historically the way we checked for it, and a lot of code then took a dependency on
// the fact that this would always be set before the pipes were closed, so they would read
// the exit code out after calling ReadToEnd() or standard output or standard error. In order
// to allow 259 to function as a valid exit code and to break as few people as possible that
// took the ReadToEnd dependency, we check for an exit code before doing the more correct
// check to see if we have been signaled.
if (Interop.Kernel32.GetExitCodeProcess(handle, out localExitCode) && localExitCode != Interop.Kernel32.HandleOptions.STILL_ACTIVE)
{
_exitCode = localExitCode;
_exited = true;
}
else
{
// The best check for exit is that the kernel process object handle is invalid,
// or that it is valid and signaled. Checking if the exit code != STILL_ACTIVE
// does not guarantee the process is closed,
// since some process could return an actual STILL_ACTIVE exit code (259).
if (!_signaled) // if we just came from WaitForExit, don't repeat
{
using (var wh = new ProcessWaitHandle(handle))
{
_signaled = wh.WaitOne(0);
}
}
if (_signaled)
{
if (!Interop.Kernel32.GetExitCodeProcess(handle, out localExitCode))
throw new Win32Exception();
_exitCode = localExitCode;
_exited = true;
}
}
}
}
finally
{
ReleaseProcessHandle(handle);
}
}