Ejemplo n.º 1
0
        /// <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);
        }