/// <summary>
        /// Executes a command-line program, specifying a maximum time to wait
        /// for it to complete.
        /// </summary>
        /// <param name="command">
        /// The path to the program executable.
        /// </param>
        /// <param name="workingDirectory">
        /// The path of the working directory for the process executing the program executable.
        /// </param>
        /// <param name="args">
        /// The command-line arguments for the program.
        /// </param>
        /// <param name="timeout">
        /// The maximum time to wait for the subprocess to complete, in milliseconds.
        /// </param>
        /// <returns>
        /// A <see cref="CommandLineProgramProcessResult"/> containing the results of
        /// running the program.
        /// </returns>
        public static CommandLineProgramProcessResult RunProgram(string command, string workingDirectory, string args, int timeout)
        {
            bool             timedOut = false;
            ProcessStartInfo pinfo    = new ProcessStartInfo(command);

            pinfo.Arguments              = args;
            pinfo.UseShellExecute        = false;
            pinfo.CreateNoWindow         = true;
            pinfo.WorkingDirectory       = workingDirectory;
            pinfo.RedirectStandardOutput = true;
            pinfo.RedirectStandardError  = true;
            Process       process       = Process.Start(pinfo);
            ProcessStream processStream = new ProcessStream();

            try
            {
                processStream.Read(process);
                process.WaitForExit(timeout);
                processStream.Stop();

                if (!process.HasExited)
                {
                    // OK, we waited until the timeout but it still didn't exit; just kill the process now
                    timedOut = true;

                    try
                    {
                        process.Kill();
                        processStream.Stop();
                    }
                    catch { }

                    process.WaitForExit();
                }
            }
            catch (Exception ex)
            {
                process.Kill();
                throw;
            }
            finally
            {
                processStream.Stop();
            }

            TimeSpan duration      = process.ExitTime - process.StartTime;
            float    executionTime = (float)duration.TotalSeconds;

            CommandLineProgramProcessResult result = new CommandLineProgramProcessResult(
                executionTime,
                processStream.StandardOutput.Trim(),
                processStream.StandardError.Trim(),
                process.ExitCode,
                timedOut);

            return(result);
        }
        /// <summary>
        /// Executes a command-line program, specifying a maximum time to wait
        /// for it to complete.
        /// </summary>
        /// <param name="command">
        /// The path to the program executable.
        /// </param>
        /// <param name="workingDirectory">
        /// The path of the working directory for the process executing the program executable.
        /// </param>
        /// <param name="args">
        /// The command-line arguments for the program.
        /// </param>
        /// <param name="timeout">
        /// The maximum time to wait for the subprocess to complete, in milliseconds.
        /// </param>
        /// <param name="input">
        /// Input to be sent via standard input.
        /// </param>
        /// <returns>
        /// A <see cref="CommandLineProgramProcessResult"/> containing the results of
        /// running the program.
        /// </returns>
        public static CommandLineProgramProcessResult RunProgram(
            string command,
            string workingDirectory,
            string args,
            int timeout,
            string input,
            Encoding inputEncoding = null)
        {
            bool timedOut = false;
            ProcessStartInfo pinfo = new ProcessStartInfo(command);
            pinfo.Arguments = args;
            pinfo.UseShellExecute = false;
            pinfo.CreateNoWindow = true;
            pinfo.WorkingDirectory = workingDirectory;
            pinfo.RedirectStandardInput = true;
            pinfo.RedirectStandardOutput = true;
            pinfo.RedirectStandardError = true;
            Process process = Process.Start(pinfo);
            ProcessStream processStream = new ProcessStream();

            StreamWriter inputStreamWriter;

            if (inputEncoding == null)
            {
                inputStreamWriter = process.StandardInput;
            }
            else
            {
                inputStreamWriter = new StreamWriter(process.StandardInput.BaseStream, inputEncoding);
            }

            Encoding standardInputEncoding = inputStreamWriter.Encoding;

            try
            {
                if (!String.IsNullOrEmpty(input))
                    inputStreamWriter.Write(input);

                inputStreamWriter.Close();
                processStream.Read(process);
                process.WaitForExit(timeout);
                processStream.Stop();

                if (!process.HasExited)
                {
                    // OK, we waited until the timeout but it still didn't exit; just kill the process now
                    timedOut = true;

                    try
                    {
                        process.Kill();
                        processStream.Stop();
                    }
                    catch { }

                    process.WaitForExit();
                }
            }
            catch (Exception ex)
            {
                process.Kill();
                processStream.Stop();
                throw ex;
            }
            finally
            {
                processStream.Stop();
            }

            TimeSpan duration = process.ExitTime - process.StartTime;
            float executionTime = (float)duration.TotalSeconds;

            CommandLineProgramProcessResult result = new CommandLineProgramProcessResult(
                executionTime,
                processStream.StandardOutput.Trim(),
                processStream.StandardError.Trim(),
                process.ExitCode,
                timedOut,
                standardInputEncoding);

            return result;
        }