开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜