Problem with System.Diagnostics.Process RedirectStandardOutput to appear in Winforms Textbox in real
- by Jonathan Websdale
I'm having problems with the redirected output from a console application being presented in a Winforms textbox in real-time. The messages are being produced line by line however as soon as interaction with the Form is called for, nothing appears to be displayed.
Following the many examples on both Stackoverflow and other forums, I can't seem to get the redirected output from the process to display in the textbox on the form until the process completes.
By adding debug lines to the 'stringWriter_StringWritten' method and writing the redirected messages to the debug window I can see the messages arriving during the running of the process but these messages will not appear on the form's textbox until the process completes.
Grateful for any advice on this.
Here's an extract of the code
public partial class RunExternalProcess : Form
{
private static int numberOutputLines = 0;
private static MyStringWriter stringWriter;
public RunExternalProcess()
{
InitializeComponent();
// Create the output message writter
RunExternalProcess.stringWriter = new MyStringWriter();
stringWriter.StringWritten += new EventHandler(stringWriter_StringWritten);
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.FileName = "myCommandLineApp.exe";
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.CreateNoWindow = true;
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
using (var pProcess = new System.Diagnostics.Process())
{
pProcess.StartInfo = startInfo;
pProcess.OutputDataReceived += new System.Diagnostics.DataReceivedEventHandler(RunExternalProcess.Process_OutputDataReceived);
pProcess.EnableRaisingEvents = true;
try
{
pProcess.Start();
pProcess.BeginOutputReadLine();
pProcess.BeginErrorReadLine();
pProcess.WaitForExit();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
finally
{
pProcess.OutputDataReceived -= new System.Diagnostics.DataReceivedEventHandler(RunExternalProcess.Process_OutputDataReceived);
}
}
}
private static void Process_OutputDataReceived(object sender, System.Diagnostics.DataReceivedEventArgs e)
{
if (!string.IsNullOrEmpty(e.Data))
{
RunExternalProcess.OutputMessage(e.Data);
}
}
private static void OutputMessage(string message)
{
RunExternalProcess.stringWriter.WriteLine("[" + RunExternalProcess.numberOutputLines++.ToString() + "] - " + message);
}
private void stringWriter_StringWritten(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine(((MyStringWriter)sender).GetStringBuilder().ToString());
SetProgressTextBox(((MyStringWriter)sender).GetStringBuilder().ToString());
}
private delegate void SetProgressTextBoxCallback(string text);
private void SetProgressTextBox(string text)
{
if (this.ProgressTextBox.InvokeRequired)
{
SetProgressTextBoxCallback callback = new SetProgressTextBoxCallback(SetProgressTextBox);
this.BeginInvoke(callback, new object[] { text });
}
else
{
this.ProgressTextBox.Text = text;
this.ProgressTextBox.Select(this.ProgressTextBox.Text.Length, 0);
this.ProgressTextBox.ScrollToCaret();
}
}
}
public class MyStringWriter : System.IO.StringWriter
{
// Define the event.
public event EventHandler StringWritten;
public MyStringWriter()
: base()
{
}
public MyStringWriter(StringBuilder sb)
: base(sb)
{
}
public MyStringWriter(StringBuilder sb, IFormatProvider formatProvider)
: base(sb, formatProvider)
{
}
public MyStringWriter(IFormatProvider formatProvider)
: base(formatProvider)
{
}
protected virtual void OnStringWritten()
{
if (StringWritten != null)
{
StringWritten(this, EventArgs.Empty);
}
}
public override void Write(char value)
{
base.Write(value);
this.OnStringWritten();
}
public override void Write(char[] buffer, int index, int count)
{
base.Write(buffer, index, count);
this.OnStringWritten();
}
public override void Write(string value)
{
base.Write(value);
this.OnStringWritten();
}
}