// ************************************************************************ /// <summary> /// Only support existing exectuable (no association or dos command which have no executable like 'dir'). /// But accept full path, partial path or no path where it will use regular system/user path. /// </summary> /// <param name="executablePath"></param> /// <param name="arguments"></param> /// <param name="timeout"></param> /// <returns></returns> private ProcessWithOutputCaptureResult ExecuteInternal(string executablePath, string arguments, int timeout = Timeout.Infinite, ProcessWindowStyle processWindowStyle = ProcessWindowStyle.Hidden) { ProcessWithOutputCaptureResult processWithOutputCaptureResult = null; using (Process process = new Process()) { process.StartInfo.FileName = executablePath; process.StartInfo.Arguments = arguments; process.StartInfo.UseShellExecute = false; process.StartInfo.WindowStyle = processWindowStyle; if (processWindowStyle == ProcessWindowStyle.Hidden) { process.StartInfo.CreateNoWindow = true; } process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; _outputWaitHandle = new AutoResetEvent(false); _errorWaitHandle = new AutoResetEvent(false); try { process.OutputDataReceived += ProcessOnOutputDataReceived; process.ErrorDataReceived += ProcessOnErrorDataReceived; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); _sbOutput.AppendLine(process.StandardOutput.ReadToEnd()); _sbError.AppendLine(process.StandardError.ReadToEnd()); if (process.WaitForExit(timeout) && _outputWaitHandle.WaitOne(timeout) && _errorWaitHandle.WaitOne(timeout)) { processWithOutputCaptureResult = ProcessWithOutputCaptureResult.CreateOne(process.ExitCode, _sbOutput.ToString(), _sbError.ToString()); } else { processWithOutputCaptureResult = ProcessWithOutputCaptureResult.CreateExpiredOne(); } } finally { process.OutputDataReceived -= ProcessOnOutputDataReceived; process.ErrorDataReceived -= ProcessOnOutputDataReceived; _outputWaitHandle.Close(); _outputWaitHandle.Dispose(); _errorWaitHandle.Close(); _errorWaitHandle.Dispose(); } } return(processWithOutputCaptureResult); }
// ************************************************************************ /// <summary> /// Only support existing exectuable (no association or dos command which have no executable like 'dir'). /// But accept full path, partial path or no path where it will use regular system/user path. /// </summary> /// <param name="executablePath"></param> /// <param name="arguments"></param> /// <param name="timeout"></param> /// <returns></returns> private ProcessWithOutputCaptureResult ExecuteInternal(string executablePath, string arguments, int timeout = Timeout.Infinite, ProcessWindowStyle processWindowStyle = ProcessWindowStyle.Hidden) { ProcessWithOutputCaptureResult processWithOutputCaptureResult = null; using (Process process = new Process()) { process.StartInfo.FileName = executablePath; process.StartInfo.Arguments = arguments; process.StartInfo.UseShellExecute = false; // required to redirect output to appropriate (output or error) process stream process.StartInfo.WindowStyle = processWindowStyle; if (processWindowStyle == ProcessWindowStyle.Hidden) { process.StartInfo.CreateNoWindow = true; } process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; try { process.Start(); bool hasSucceeded = process.WaitForExit(timeout); processWithOutputCaptureResult = ProcessWithOutputCaptureResult.CreateOne(process.ExitCode, process.StandardOutput.ReadToEnd(), process.StandardError.ReadToEnd()); processWithOutputCaptureResult = ProcessWithOutputCaptureResult.CreateExpiredOne(); processWithOutputCaptureResult = new ProcessWithOutputCaptureResult(); processWithOutputCaptureResult.ExitCode = process.ExitCode; processWithOutputCaptureResult.Output = process.StandardOutput.ReadToEnd(); processWithOutputCaptureResult.Error = process.StandardError.ReadToEnd(); processWithOutputCaptureResult.HasTimeout = !hasSucceeded; } catch (Exception ex) { if (ex.HResult == -2147467259) { ProcessWithOutputCaptureResult.CreateOneWithException(new FileNotFoundException("File not found: " + executablePath, ex)); } else { ProcessWithOutputCaptureResult.CreateOneWithException(ex); } } } return(processWithOutputCaptureResult); }
// ************************************************************************ /// <summary> /// Only support existing exectuable (no association or dos command which have no executable like 'dir'). /// But accept full path, partial path or no path where it will use regular system/user path. /// </summary> /// <param name="executablePath"></param> /// <param name="arguments"></param> /// <param name="timeout"></param> /// <returns></returns> private ProcessWithOutputCaptureResult ExecuteInternal(string executablePath, string arguments, int timeout = Timeout.Infinite, ProcessWindowStyle processWindowStyle = ProcessWindowStyle.Hidden) { ProcessWithOutputCaptureResult processWithOutputCaptureResult = null; using (Process process = new Process()) { process.StartInfo.FileName = executablePath; process.StartInfo.Arguments = arguments; process.StartInfo.UseShellExecute = false; // required to redirect output to appropriate (output or error) process stream process.StartInfo.WindowStyle = processWindowStyle; if (processWindowStyle == ProcessWindowStyle.Hidden) { process.StartInfo.CreateNoWindow = true; } process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; _outputWaitHandle = new AutoResetEvent(false); _errorWaitHandle = new AutoResetEvent(false); try { process.OutputDataReceived += ProcessOnOutputDataReceived; process.ErrorDataReceived += ProcessOnErrorDataReceived; process.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); // See: ProcessStartInfo.RedirectStandardOutput Property: // https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Diagnostics.ProcessStartInfo.RedirectStandardOutput);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5.2);k(DevLang-csharp)&rd=true // All 4 next lines should only be called when not using asynchronous read (process.BeginOutputReadLine() and process.BeginErrorReadLine()) //_sbOutput.AppendLine(process.StandardOutput.ReadToEnd()); //_sbError.AppendLine(process.StandardError.ReadToEnd()); //_sbOutput.AppendLine(process.StandardOutput.ReadToEnd()); //_sbError.AppendLine(process.StandardError.ReadToEnd()); if (process.WaitForExit(timeout) && _outputWaitHandle.WaitOne(timeout) && _errorWaitHandle.WaitOne(timeout)) { processWithOutputCaptureResult = ProcessWithOutputCaptureResult.CreateOne(process.ExitCode, _sbOutput.ToString(), _sbError.ToString()); } else { processWithOutputCaptureResult = ProcessWithOutputCaptureResult.CreateExpiredOne(); } } catch (Exception ex) { if (ex.HResult == -2147467259) { ProcessWithOutputCaptureResult.CreateOneWithException(new FileNotFoundException("File not found: " + executablePath, ex)); } else { ProcessWithOutputCaptureResult.CreateOneWithException(ex); } } finally { process.CancelOutputRead(); process.CancelErrorRead(); process.OutputDataReceived -= ProcessOnOutputDataReceived; process.ErrorDataReceived -= ProcessOnOutputDataReceived; _outputWaitHandle.Close(); _outputWaitHandle.Dispose(); _errorWaitHandle.Close(); _errorWaitHandle.Dispose(); } } return(processWithOutputCaptureResult); }
// ************************************************************************ /// <summary> /// Only support existing exectuable (no association or dos command which have no executable like 'dir'). /// But accept full path, partial path or no path where it will use regular system/user path. /// </summary> /// <param name="executablePath"></param> /// <param name="arguments"></param> /// <param name="timeout"></param> /// <returns></returns> private ProcessWithOutputCaptureResult Execute(string executablePath, string arguments = null, int timeout = Timeout.Infinite) { ProcessWithOutputCaptureResult processWithOutputCaptureResult = null; using (Process process = new Process()) { process.StartInfo.FileName = executablePath; process.StartInfo.Arguments = arguments; process.StartInfo.UseShellExecute = false; // required to redirect output to appropriate (output or error) process stream process.StartInfo.WindowStyle = ProcessWindowStyle; process.StartInfo.CreateNoWindow = CreateWindow; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; _outputWaitHandle = new AutoResetEvent(false); _errorWaitHandle = new AutoResetEvent(false); bool asyncReadStarted = false; try { process.OutputDataReceived += ProcessOnOutputDataReceived; process.ErrorDataReceived += ProcessOnErrorDataReceived; process.Start(); // Here there is a race condition. See: https://connect.microsoft.com/VisualStudio/feedback/details/3119134/race-condition-in-process-asynchronous-output-stream-read process.BeginOutputReadLine(); process.BeginErrorReadLine(); asyncReadStarted = true; // See: ProcessStartInfo.RedirectStandardOutput Property: // https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(System.Diagnostics.ProcessStartInfo.RedirectStandardOutput);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.5.2);k(DevLang-csharp)&rd=true // All 4 next lines should only be called when not using asynchronous read (process.BeginOutputReadLine() and process.BeginErrorReadLine()) //_sbOutput.AppendLine(process.StandardOutput.ReadToEnd()); //_sbError.AppendLine(process.StandardError.ReadToEnd()); //_sbOutput.AppendLine(process.StandardOutput.ReadToEnd()); //_sbError.AppendLine(process.StandardError.ReadToEnd()); var waitHandles = new WaitHandle[1 + (AdditionalConditionToStopWaitingProcess == null ? 0 : 1)]; waitHandles[0] = new ProcessWaitHandle(process); if (AdditionalConditionToStopWaitingProcess != null) { waitHandles[1] = AdditionalConditionToStopWaitingProcess; } bool hasSucceded = false; int waitResult = WaitHandle.WaitAny(waitHandles, timeout); if (waitResult == 1) // The wait has been interrrupted by an external event { if (IsAdditionalConditionToStopWaitingProcessShouldAlsoKill) { process.Kill(); } } else if (waitResult == 0) // Process has completed normally, no timeout or external event { // Ensure internal process code has completed like ensure to wait until stdout et stderr had been fully completed hasSucceded = process.WaitForExit(timeout); if (_outputWaitHandle.WaitOne(timeout) && _errorWaitHandle.WaitOne(timeout)) { processWithOutputCaptureResult = new ProcessWithOutputCaptureResult(); processWithOutputCaptureResult.ExitCode = process.ExitCode; processWithOutputCaptureResult.Output = _sbOutput.ToString(); processWithOutputCaptureResult.Error = _sbError.ToString(); } } else // Process timeout { processWithOutputCaptureResult = new ProcessWithOutputCaptureResult(); processWithOutputCaptureResult.HasTimeout = true; } } catch (Exception ex) { if (ex.HResult == -2147467259) { processWithOutputCaptureResult = new ProcessWithOutputCaptureResult(); processWithOutputCaptureResult.Exception = new FileNotFoundException("File not found: " + executablePath, ex); } else { processWithOutputCaptureResult = new ProcessWithOutputCaptureResult(); processWithOutputCaptureResult.Exception = ex; } } finally { if (asyncReadStarted) { process.CancelOutputRead(); process.CancelErrorRead(); } process.OutputDataReceived -= ProcessOnOutputDataReceived; process.ErrorDataReceived -= ProcessOnOutputDataReceived; _outputWaitHandle.Close(); _outputWaitHandle.Dispose(); _errorWaitHandle.Close(); _errorWaitHandle.Dispose(); } } return(processWithOutputCaptureResult); }