During last month
I was working on a project built on top of the Console-windows. An interesting
problem I was facing is the read of redirected output (asyncronous) from
that process. It seems to be quite easy to handle such a task, and it is, unless
you need to read "all the output".
Well, the
simple approach of handling such a task is like the following:
1. Define a
ProcessStartInfo with redirected output:
ProcessStartInfo tmpStartInfo = new
ProcessStartInfo()
{
FileName = "consoleApp.exe",
UseShellExecute = false,
RedirectStandardOutput = true
FileName = "consoleApp.exe",
UseShellExecute = false,
RedirectStandardOutput = true
}
2. Create a
process and set the start info to alrelady defined one:
ProcessStartInfo tmpProcess = new
Process()
tmpProcess.StartInfo
= tmpStartInfo;
3. Define and
register a handler for the OutputDataReceived event:
private static void Process_OutputDataReceived(object sendingProcess, DataReceivedEventArgs outLine)
{
Console.WriteLine(outLine);
{
Console.WriteLine(outLine);
}
tmpProcess.OutputDataReceived += new
DataReceivedEventHandler (Process_OutputDataReceived);
4. Start the
process.
tmpProcess.Start();
Yes, it's simple,
but there is an open issue left in here. The process won't redirect the output,
until there is a new-line character in the stream, which means, that the
Process will fire the OutputDataReceived event only as soon as a new line is
available on the stream. So for me this was a big limitation, because if the
process is writing something on a line and still waits for some input from the
user on the same line, we will never receive that line, and won't even know
that the process is waiting for user input there.
To fix this we
need to observe the stream on our own, not awaiting the event to fire. So, here
is the algorithm I came up with, to handle the behavior described:
private void
ObserveStreamInBackground()
{
try
{
char? tmpStreamChar = null;
do
{
int tmpStatus = this.Stream.Peek();
if (tmpStatus ==
-1)
{
if (this.messageBuffer.Length > 0)
{
this.InformMessage();
}
tmpStreamChar = (char)this.Stream.Read();
}
char tmpCurrentChar =
tmpStreamChar ?? (char)this.Stream.Read();
if
(tmpStreamChar.HasValue)
{
tmpStreamChar = null;
}
this.messageBuffer.Append(tmpCurrentChar);
if (tmpCurrentChar
== '\n')
{
this.InformMessage();
}
} while (true);
}
catch (ThreadAbortException ex)
{
}
}
private void
InformMessage()
{
string tmpMessage = this.messageBuffer.ToString();
this.messageBuffer.Clear();
this.lastMessage =
tmpMessage;
this.lastMessageReceivedAt
= DateTime.Now;
this.OnMessageReceived(tmpMessage);
}
The
InformMessage() method is there to just clear the current message buffer and
fire the event with the message data in it.
That's all. Experiment with it and
give me your feedback. Good Luck !
1 comment:
Your place is valuable for me. Thanks!…
Post a Comment