/// <summary>
        /// Runs the provided command with args with optional message callbacks.
        /// </summary>
        /// <param name="command"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static int Run(string command, string args,
                              EventHandler <EventArgs <string> > stdOutCallback,
                              EventHandler <EventArgs <string> > stdErrCallback,
                              EventHandler <EventArgs <string> > debugCallback
                              )
        {
            EmbeddedProcessExecutor proc = new EmbeddedProcessExecutor();
            var startInfo = new EmbeddedProcessStartInfo();

            startInfo.FileName  = command;
            startInfo.Arguments = args;
            if (stdOutCallback != null)
            {
                proc.StandardOutputMessageReceived += stdOutCallback;
            }
            if (debugCallback != null)
            {
                proc.DebugMessage += debugCallback;
            }
            if (stdErrCallback != null)
            {
                proc.StandardErrorMessageReceived += stdErrCallback;
            }
            proc.Run(startInfo);
            return(proc.ExitCode);
        }
        public string Run(EmbeddedProcessStartInfo startInfo)
        {
            _standardOutput = new StringBuilder();
            _standardError  = new StringBuilder();
            _startInfo      = startInfo;

            Thread           thdOutput    = null;
            Thread           thdError     = null;
            ProcessStartInfo objStartInfo = new ProcessStartInfo()
            {
                FileName               = _startInfo.FileName,
                WorkingDirectory       = _startInfo.WorkingDirectory,
                Arguments              = _startInfo.Arguments,
                UseShellExecute        = false,
                RedirectStandardOutput = true,
                RedirectStandardError  = true,
            };

            _process           = new Process();
            _process.StartInfo = objStartInfo;

            _log.Trace(DoDebugMessage("embedded process file name: {0}", objStartInfo.FileName));
            _log.Trace(DoDebugMessage("embedded process command line: {0}", objStartInfo.Arguments));
            _log.Trace(DoDebugMessage("embedded process working dir: {0}", objStartInfo.WorkingDirectory));

            var result = new EmbeddedProcessResult();

            try
            {
                thdOutput = new Thread(new ParameterizedThreadStart(ReadStream));
                thdError  = new Thread(new ParameterizedThreadStart(ReadStream));

                _log.Trace(DoDebugMessage("calling process start"));
                _process.Start();

                _log.Trace(DoDebugMessage("starting stream reader threads"));
                thdOutput.Start(new StreamReaderThreadStart(_process.StandardOutput, false, startInfo.StandardOutFile));
                thdError.Start(new StreamReaderThreadStart(_process.StandardError, true));

                //wait for process to finish
                _log.Trace(DoDebugMessage("waiting for external process to exit"));
                _process.WaitForExit();

                //join the stream reader threads to ensure we capture everything
                _log.Trace(DoDebugMessage("joining stream reader threads"));
                thdError.Join(2000);
                thdOutput.Join(2000);

                _log.Trace(DoDebugMessage("process call exited with code {0}", _process.ExitCode));
                ExitCode = _process.ExitCode;

                if (!_process.HasExited)
                {
                    try
                    {
                        _process.Kill();
                    }
                    catch { /* swallow kill exceptions */ }

                    throw new Exception(string.Format(
                                            "External process for file '{0}' in directory '{1} failed to complete within the specified timeout.",
                                            _startInfo.FileName,
                                            _startInfo.WorkingDirectory));
                }
            }
            catch (Exception ex)
            {
                _log.Error(ex, "unexpected exception occurred during external process");
                throw;
            }
            finally
            {
                _log.Trace(DoDebugMessage("closing and disposing process"));
                _process.Close();
                _process.Dispose();
            }



            return(_standardOutput.ToString());
        }