// Create a process object which will allow us to run the Process and control it for the duration of the test
this.Process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = ExeFile,
WindowStyle = ProcessWindowStyle.Normal,
RedirectStandardOutput = true, // So that we can redirect and interpret the console output
RedirectStandardInput = true,
RedirectStandardError = true,
UseShellExecute = false,
ErrorDialog = false,
}
};
// Initialize the value of the text string that collects the
// console output which will be updated by the asynchronous tasks below
this.OutputText = string.Empty;
// Launch the process
this.Process.Start();
Console.WriteLine("Launched Process at: " + ExeFile);
// Note: Cannot use this traditional method of asynchronous reads for this exe,
// because it misses the first burst of output from the exe, causing test to fail:
// this.Process.OutputDataReceived += new DataReceivedEventHandler(ConsoleOutputReceived);
// See this web page for details why: http://alabaxblog.info/2013/06/redirectstandardoutput-beginoutputreadline-pattern-broken/
// Can read from stderr text asynchronously though, since we are not waiting and depending upon its contents
this.Process.ErrorDataReceived += new DataReceivedEventHandler(ErrorOutputReceived);
this.Process.BeginErrorReadLine();
Console.WriteLine("Console stderr output has been redirected.");
// Create a cancelable, asynchronous task to read from the normal stdout stream using
// the synchronous call, to work around the issue of missing the first burst of output
// when using the traditional method of redirecting .OutputDataReceived
var taskCanceler = new CancellationTokenSource();
CancellationToken cancellationToken = taskCanceler.Token;
Task outputReader = Task.Factory.StartNew
(() =>
{
// Keep track of the current line of output so that we can echo it to the console line-by-line
string currentLine = string.Empty;
// Infinitely loop while inside this special outputReader task
while (true)
{
// Drop out of the task if the task has been canceled
cancellationToken.ThrowIfCancellationRequested();
// Sleep a tiny amount while inside the loop, to prevent this task from churning the CPU
Thread.Sleep(1);
// Read from the stdout of the retdirected process output, in synchronous mode,
// to work around the issue where using the .OutputDataReceived feature misses
// the start of the output of fast-starting tasks; note that we cannot use
// "ReadToEnd()" or some such, because that would hang this thread, so we want
// to keep reading without stopping
int oneChar = this.Process.StandardOutput.Read();
// Process the character we read
if (-1 != oneChar)
{
currentLine += string.Format("{0}", (char)oneChar);
this.OutputText += string.Format("{0}", (char)oneChar);
// If we get a linefeed, echo the buffered line to the console
if (10 == oneChar)
{
Console.Write("StdOut: " + currentLine);
currentLine = string.Empty;
}
}
}
}
, cancellationToken
);
// ************* Now down here you can do a nice leisurely loop where you look at the contents of
// this.OutputText and act upon it as needed.
// Now we're done with the output reading thread, we can cancel it now
taskCanceler.Cancel();