Example #1
0
        /// <summary>
        /// Instructs the Process component to wait the specified number of milliseconds for the associated process to exit.
        /// </summary>
        private bool WaitForExitCore(int milliseconds)
        {
            SafeProcessHandle handle = null;

            try
            {
                handle = GetProcessHandle(Interop.Advapi32.ProcessOptions.SYNCHRONIZE, false);
                if (handle.IsInvalid)
                {
                    return(true);
                }

                using (Interop.Kernel32.ProcessWaitHandle processWaitHandle = new Interop.Kernel32.ProcessWaitHandle(handle))
                {
                    return(_signaled = processWaitHandle.WaitOne(milliseconds));
                }
            }
            finally
            {
                // If we have a hard timeout, we cannot wait for the streams
                if (_output != null && milliseconds == Timeout.Infinite)
                {
                    _output.WaitUtilEOF();
                }

                if (_error != null && milliseconds == Timeout.Infinite)
                {
                    _error.WaitUtilEOF();
                }

                handle?.Dispose();
            }
        }
Example #2
0
 /// <devdoc>
 ///     Make sure we are watching for a process exit.
 /// </devdoc>
 /// <internalonly/>
 private void EnsureWatchingForExit()
 {
     if (!_watchingForExit)
     {
         lock (this)
         {
             if (!_watchingForExit)
             {
                 Debug.Assert(_haveProcessHandle, "Process.EnsureWatchingForExit called with no process handle");
                 Debug.Assert(Associated, "Process.EnsureWatchingForExit called with no associated process");
                 _watchingForExit = true;
                 try
                 {
                     _waitHandle           = new Interop.Kernel32.ProcessWaitHandle(_processHandle);
                     _registeredWaitHandle = ThreadPool.RegisterWaitForSingleObject(_waitHandle,
                                                                                    new WaitOrTimerCallback(CompletionCallback), _waitHandle, -1, true);
                 }
                 catch
                 {
                     _watchingForExit = false;
                     throw;
                 }
             }
         }
     }
 }
Example #3
0
        /// <devdoc>
        ///     Gets a short-term handle to the process, with the given access.
        ///     If a handle is stored in current process object, then use it.
        ///     Note that the handle we stored in current process object will have all access we need.
        /// </devdoc>
        /// <internalonly/>
        private SafeProcessHandle GetProcessHandle(int access, bool throwIfExited)
        {
#if FEATURE_TRACESWITCH
            Debug.WriteLineIf(_processTracing.TraceVerbose, "GetProcessHandle(access = 0x" + access.ToString("X8", CultureInfo.InvariantCulture) + ", throwIfExited = " + throwIfExited + ")");
#if DEBUG
            if (_processTracing.TraceVerbose)
            {
                StackFrame calledFrom = new StackTrace(true).GetFrame(0);
                Debug.WriteLine("   called from " + calledFrom.GetFileName() + ", line " + calledFrom.GetFileLineNumber());
            }
#endif
#endif
            if (_haveProcessHandle)
            {
                if (throwIfExited)
                {
                    // Since haveProcessHandle is true, we know we have the process handle
                    // open with at least SYNCHRONIZE access, so we can wait on it with
                    // zero timeout to see if the process has exited.
                    using (Interop.Kernel32.ProcessWaitHandle waitHandle = new Interop.Kernel32.ProcessWaitHandle(_processHandle))
                    {
                        if (waitHandle.WaitOne(0))
                        {
                            if (_haveProcessId)
                            {
                                throw new InvalidOperationException(SR.Format(SR.ProcessHasExited, _processId.ToString(CultureInfo.CurrentCulture)));
                            }
                            else
                            {
                                throw new InvalidOperationException(SR.ProcessHasExitedNoId);
                            }
                        }
                    }
                }

                // If we dispose of our contained handle we'll be in a bad state. NetFX dealt with this
                // by doing a try..finally around every usage of GetProcessHandle and only disposed if
                // it wasn't our handle.
                return(new SafeProcessHandle(_processHandle.DangerousGetHandle(), ownsHandle: false));
            }
            else
            {
                EnsureState(State.HaveId | State.IsLocal);
                SafeProcessHandle handle = SafeProcessHandle.InvalidHandle;
                handle = ProcessManager.OpenProcess(_processId, access, throwIfExited);
                if (throwIfExited && (access & Interop.Advapi32.ProcessOptions.PROCESS_QUERY_INFORMATION) != 0)
                {
                    if (Interop.Kernel32.GetExitCodeProcess(handle, out _exitCode) && _exitCode != Interop.Kernel32.HandleOptions.STILL_ACTIVE)
                    {
                        throw new InvalidOperationException(SR.Format(SR.ProcessHasExited, _processId.ToString(CultureInfo.CurrentCulture)));
                    }
                }
                return(handle);
            }
        }
Example #4
0
        /// <summary>Checks whether the process has exited and updates state accordingly.</summary>
        private void UpdateHasExited()
        {
            using (SafeProcessHandle 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 Interop.Kernel32.ProcessWaitHandle(handle))
                            {
                                _signaled = wh.WaitOne(0);
                            }
                        }
                        if (_signaled)
                        {
                            if (!Interop.Kernel32.GetExitCodeProcess(handle, out localExitCode))
                            {
                                throw new Win32Exception();
                            }

                            _exitCode = localExitCode;
                            _exited   = true;
                        }
                    }
                }
            }
        }
Example #5
0
        /// <devdoc>
        ///     Gets a short-term handle to the process, with the given access.
        ///     If a handle is stored in current process object, then use it.
        ///     Note that the handle we stored in current process object will have all access we need.
        /// </devdoc>
        /// <internalonly/>
        private SafeProcessHandle GetProcessHandle(int access, bool throwIfExited)
        {
            if (_haveProcessHandle)
            {
                if (throwIfExited)
                {
                    // Since haveProcessHandle is true, we know we have the process handle
                    // open with at least SYNCHRONIZE access, so we can wait on it with
                    // zero timeout to see if the process has exited.
                    using (Interop.Kernel32.ProcessWaitHandle waitHandle = new Interop.Kernel32.ProcessWaitHandle(_processHandle))
                    {
                        if (waitHandle.WaitOne(0))
                        {
                            if (_haveProcessId)
                            {
                                throw new InvalidOperationException(SR.Format(SR.ProcessHasExited, _processId.ToString(CultureInfo.CurrentCulture)));
                            }
                            else
                            {
                                throw new InvalidOperationException(SR.ProcessHasExitedNoId);
                            }
                        }
                    }
                }

                // If we dispose of our contained handle we'll be in a bad state. NetFX dealt with this
                // by doing a try..finally around every usage of GetProcessHandle and only disposed if
                // it wasn't our handle.
                return(new SafeProcessHandle(_processHandle.DangerousGetHandle(), ownsHandle: false));
            }
            else
            {
                EnsureState(State.HaveId | State.IsLocal);
                SafeProcessHandle handle = SafeProcessHandle.InvalidHandle;
                handle = ProcessManager.OpenProcess(_processId, access, throwIfExited);
                if (throwIfExited && (access & Interop.Advapi32.ProcessOptions.PROCESS_QUERY_INFORMATION) != 0)
                {
                    if (Interop.Kernel32.GetExitCodeProcess(handle, out _exitCode) && _exitCode != Interop.Kernel32.HandleOptions.STILL_ACTIVE)
                    {
                        throw new InvalidOperationException(SR.Format(SR.ProcessHasExited, _processId.ToString(CultureInfo.CurrentCulture)));
                    }
                }
                return(handle);
            }
        }
Example #6
0
        // Handle should be valid and have PROCESS_QUERY_LIMITED_INFORMATION | SYNCHRONIZE access
        public static bool HasExited(SafeProcessHandle handle, ref bool signaled, out int exitCode)
        {
            // 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 exitCode) && exitCode != Interop.Kernel32.HandleOptions.STILL_ACTIVE)
            {
                return(true);
            }

            // 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 Process.WaitForExit, don't repeat
            {
                using (var wh = new Interop.Kernel32.ProcessWaitHandle(handle))
                {
                    signaled = wh.WaitOne(0);
                }
            }
            if (signaled)
            {
                if (!Interop.Kernel32.GetExitCodeProcess(handle, out exitCode))
                {
                    throw new Win32Exception();
                }

                return(true);
            }

            return(false);
        }