/// <summary> /// Starts a process with the given startinfo /// </summary> /// <param name="startInfo">the startinfo of the process</param> /// <param name="timeout"></param> /// <param name="std"></param> /// <returns>the result of the run</returns> public static ProcessResult Run(ProcessStartInfo startInfo, int timeout = 15000, Action <string> std = null) { if (startInfo is null) { throw new ArgumentNullException(nameof(startInfo)); } StringBuilder output = new StringBuilder(); StringBuilder error = new StringBuilder(); ProcessResult Result = new ProcessResult(); startInfo.RedirectStandardError = true; startInfo.RedirectStandardOutput = true; using (Process process = new Process()) { process.StartInfo = startInfo; TaskCompletionSource <bool> StreamDone = new TaskCompletionSource <bool>(); bool outputDone = false; bool errorDone = false; void HandleData(StringBuilder sb, DataReceivedEventArgs e, ref bool done) { if (e.Data is null) { done = true; if (errorDone && outputDone && !StreamDone.Task.IsCompleted) { StreamDone.SetResult(true); } } else { std?.Invoke(e.Data + System.Environment.NewLine); sb.Append(e.Data); } sb.Append(System.Environment.NewLine); } process.OutputDataReceived += (sender, e) => HandleData(output, e, ref outputDone); process.ErrorDataReceived += (sender, e) => HandleData(error, e, ref errorDone); //Task<string> stdOutTask = process.StandardOutput.ReadToEndAsync(); //Task<string> stdErrTask = process.StandardError.ReadToEndAsync(); Task WaitShort = new Task(() => { while (!process.WaitForExit(5000) && !process.HasExited) { } }); Task WaitLong = new Task(() => process.WaitForExit()); Task TryFinish = new Task(() => { WaitLong.Start(); Task Timeout = Task.Delay(timeout); Task.WaitAny(WaitLong, Timeout); }); WaitShort.ContinueWith((a) => TryFinish.Start()); process.Start(); WaitShort.Start(); process.BeginOutputReadLine(); process.BeginErrorReadLine(); Task.WaitAny(TryFinish, StreamDone.Task); Result.ExitCode = process.ExitCode; process.Close(); Result.Output = output.ToString(); Result.Error = error.ToString(); } return(Result); }
public static async Task <ProcessResult> RunProcessAsync(ProcessStartInfo pstartInfo, int timeout) { ProcessResult result = new ProcessResult(); using (Process process = new Process()) { process.StartInfo = pstartInfo; StringBuilder outputBuilder = new StringBuilder(); TaskCompletionSource <bool> outputCloseEvent = new TaskCompletionSource <bool>(); process.OutputDataReceived += (s, e) => { if (e.Data == null) { outputCloseEvent.SetResult(true); } else { outputBuilder.Append(e.Data); } }; StringBuilder errorBuilder = new StringBuilder(); TaskCompletionSource <bool> errorCloseEvent = new TaskCompletionSource <bool>(); process.ErrorDataReceived += (s, e) => { if (e.Data == null) { errorCloseEvent.SetResult(true); } else { errorBuilder.Append(e.Data); } }; bool isStarted = process.Start(); if (!isStarted) { result.ExitCode = process.ExitCode; return(result); } // Reads the output stream first and then waits because deadlocks are possible process.BeginOutputReadLine(); process.BeginErrorReadLine(); // Creates task to wait for process exit using timeout Task <bool> waitForExit = WaitForExitAsync(process, timeout); // Create task to wait for process exit and closing all output streams Task <bool[]> processTask = Task.WhenAll(waitForExit, outputCloseEvent.Task, errorCloseEvent.Task); // Waits process completion and then checks it was not completed by timeout if (await Task.WhenAny(Task.Delay(timeout), processTask) == processTask && waitForExit.Result) { result.ExitCode = process.ExitCode; result.Output = outputBuilder.ToString(); result.Error = errorBuilder.ToString(); } else { try { // Kill hung process process.Kill(); } catch { // ignored } } } return(result); }