Sometimes it is necessary for a main program to invoke other executables during runtime. This can be achieved via the Process and ProcessStartInfo class in .Net. It is also desirable at times to redirect the calling process’s output to the caller’s space so that caller can either display this information back to the user or use such information for other purposes like giving real time feedbacks.
In .Net 2.0 and above, this is almost trivial as the Process class exposes an event called OutputDataReceived. This event is activated whenever the redirected output stream receives output data. Prior to .Net 2.0 however, it was a little bit more complex to implement such feedback mechanism as no events were exposed from the Process class. To receive the output information from the invoked process in real time under Framework 1.1 for example, can only be achieved via some pretty intensive asynchronous programming. Mike Mayer has a wonderful article on this issue. This article utilizes some techniques found in an MSDN article on multithreading.
Here, I will illustrate a simpler approach which can achieve similar results under .Net 1.1. Let’s suppose that we have a long running batch file test.bat that outputs information to console periodically and we want to redirect the output to our .Net program. The code snippet below shows how this can be done:
Process proc = new Process(); ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = true; startInfo.UseShellExecute = false; startInfo.FileName = "test.bat"; startInfo.RedirectStandardOutput = true; proc.StartInfo = startInfo; proc.Start();
StreamReader outputReader = proc.StandardOutput;
string s = null;
do { s = outputReader.ReadLine(); Console.WriteLine(s); } while (s != null);
proc.WaitForExit();
The difference between this code and other stock code readily available is the do while loop, in most code samples you find on the internet, a single ReadToEnd() is used instead of the ReadLine used in the loop. And if ReadToEnd() method is used, the output will only become available to the caller program till the calling program exits.
The trick here is that outputReader will actually block when the console is writing information to the buffer so that whenever the buffer is flushed, the read will continue and thus we will receive the output information almost in real time. The catch is that since the standard output is buffered, the output stream reader will receive data in chunks instead of line by line. This should be fine for long running programs that generate lots of output information. But for programs that need more granular information, the other methods discussed above should be used instead.