Process Wrapping, Some output not displaying
I have a small wrapping application to give a GUI to an existing console application. I'm using the ProcessStartInfo
and Process
class to bind to the .exe, and then using BeginErrorReadLine()
and BeginOutputReadLine()
to redirect any messages into the new GUI. Everything works fine except for when the console calls Console.Write()
instead Console.WriteLine()
, in which case the text passed to Write
is not displayed at all. I would think that the problem is because the WriteLine
function inserts a line break after the text, and the Write
method does not. Is there any way to circumvent this? I can't change it from Write
to WriteLine
in the original command line program as Write
is used to prompt for input.
Relevant Code:
var startInfo = new ProcessStartInfo(ServerFile);
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardOutput = true;
ServerProc = new Process();
ServerProc.StartInfo 开发者_Python百科= startInfo;
ServerProc.EnableRaisingEvents = true;
ServerProc.ErrorDataReceived += new DataReceivedEventHandler(ServerProc_ErrorDataReceived);
ServerProc.OutputDataReceived += new DataReceivedEventHandler(ServerProc_OutputDataReceived);
private void ServerProc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
Dispatcher.Invoke(new Action(() =>
{
ConsoleTextBlock.Text += e.Data + "\r\n";
ConsoleScroll.ScrollToEnd();
}));
}
private void ServerProc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
Dispatcher.Invoke(new Action(() =>
{
ConsoleTextBlock.Text += e.Data + "\r\n";
ConsoleScroll.ScrollToEnd();
}));
}
The problem you are experiencing is that the Process
class is set up for convenient line-oriented event-based processing of the output of the process. You cannot use this functionality if you need to read partial lines as they are being output.
Nevertheless, the Process
class does give you the tools you need if you need finer-grained control over the output than the line-oriented facilities. If you redirect the output, then Process.StandardOutput
is a StreamReader
and you have the whole StreamReader
API that you can use instead of being forced to read entire lines.
For example, here is a character-by-character read of the standard output:
var start = DateTime.Now;
int n;
while ((n = ServerProc.StandardOutput.Read()) != -1)
{
var c = (char)n;
var delta = (DateTime.Now - start).TotalMilliseconds;
Console.WriteLine("c = {0} (0x{1:X}) delta = {2}",
char.IsWhiteSpace(c) ? '*' : c, n, delta);
}
If we run it on another console program that produces this output:
Console.Write("abc");
Thread.Sleep(1000);
Console.WriteLine("def");
It produces this output:
c = a (0x61) delta = 44.0025
c = b (0x62) delta = 44.0025
c = c (0x63) delta = 44.0025
c = d (0x64) delta = 1109.0634
c = e (0x65) delta = 1110.0635
c = f (0x66) delta = 1110.0635
c = * (0xD) delta = 1110.0635
c = * (0xA) delta = 1110.0635
which shows that the "abc"
was read one second before the rest of the line.
However, this is not convenient if you like the event-oriented I/O already provided by Process
. You can either:
- use the async
Stream
API - use threads that do blocking reads
and perhaps even roll your own event-based I/O that meets your needs.
You are writing a program that is parsing another program's character-oriented output and so without full lines you will need some sort of timeout to indicate "I now satisfied that the program is done producing output for the time being." This can be easy or hard depending on how predictable the output is. For example, you might be able to recognize a prompt that ends with a "?"
. It depends on your situation.
The point is that you'll have to use the StandardOutput
and StandardError
StreamReader
properties if you want something other than line-oriented I/O.
精彩评论