title: How do I redirect a console program's output to a text box in a thread safe way?
body: <p>I am having trouble redirecting console output to a windows forms text box. The problem is thread related. I am running a console app in the following way,</p>
  
  <pre><code>private void RunConsoleApp()
  {
      Process proc = new Process();
      proc.StartInfo.FileName = "app.exe";
      proc.StartInfo.Arguments = "-a -b -c";
      proc.StartInfo.UseShellExecute = false;
  
      // set up output redirection
      proc.StartInfo.RedirectStandardOutput = true;
      proc.StartInfo.RedirectStandardError = true;    
      proc.EnableRaisingEvents = true;
      proc.StartInfo.CreateNoWindow = true;
  
      // Set the data received handlers
      proc.ErrorDataReceived += proc_DataReceived;
      proc.OutputDataReceived += proc_DataReceived;
  
      proc.Start();
      proc.BeginErrorReadLine();
      proc.BeginOutputReadLine();
      proc.WaitForExit();
  
      if (proc.ExitCode == 0)
      {
          out_txtbx.AppendText("Success." + Environment.NewLine);
      }
      else
      {
          out_txtbx.AppendText("Failed." + Environment.NewLine);
      }
  }
  </code></pre>
  
  <p>and then capture and process the data with this output handler,</p>
  
  <pre><code>// Handle the date received by the console process
  void proc_DataReceived(object sender, DataReceivedEventArgs e)
  {
      if (e.Data != null)
      {
          if ((e.Data.EndsWith("DONE.")) || (e.Data.EndsWith("FAILED.")) ||
              (e.Data.StartsWith("RESET")))
          {
              // This crashes the application, but is supposedly the correct method
              this.AppendText(e.Data + Environment.NewLine);
  
              // This works, but the debugger keeps warning me that the call
              // is not thread safe
              //out_txtbx.AppendText(e.Data + Environment.NewLine);
          }
      }
  }
  </code></pre>
  
  <p>The console text is then appended like this,</p>
  
  <pre><code>delegate void AppendTextDelegate(string text);
  
  // Thread-safe method of appending text to the console box
  private void AppendText(string text)
  {
      // Use a delegate if called from a different thread,
      // else just append the text directly
      if (this.out_txtbx.InvokeRequired)
      {
          // Application crashes when this line is executed
          out_txtbx.Invoke(new AppendTextDelegate(this.AppendText), new object[] { text });
      }
      else
      {
          this.out_txtbx.AppendText(text);
      }
  }
  </code></pre>
  
  <p>From all the documentation and examples I have seen this appears to be the correct method, except that it is crashing the application when out_txtbx.Invoke is called.</p>
  
  <p>What could be broken and what alternative ways are there to do this?</p>
  
  <hr>
  
  <p><strong>Solution</strong> (as pointed out by Hans Passant)</p>
  
  <p>The problem is that the app is stuck in a "deadly embrace" as a result of the line,</p>
  
  <pre><code>proc.WaitForExit();
  </code></pre>
  
  <p>That line should be removed and the method should look like this,</p>
  
  <pre><code>private void RunConsoleApp()
  {
      Process proc = new Process();
      proc.StartInfo.FileName = "app.exe";
      proc.StartInfo.Arguments = "-a -b -c";
      proc.StartInfo.UseShellExecute = false;
  
      // set up output redirection
      proc.StartInfo.RedirectStandardOutput = true;
      proc.StartInfo.RedirectStandardError = true;    
      proc.EnableRaisingEvents = true;
      proc.StartInfo.CreateNoWindow = true;
  
      // Set the data received handlers
      proc.ErrorDataReceived += proc_DataReceived;
      proc.OutputDataReceived += proc_DataReceived;
  
      // Configure the process exited event
      proc.Exited += new EventHandler(ProcExited);
  
      proc.Start();
      proc.BeginErrorReadLine();
      proc.BeginOutputReadLine();
  
      // This blocks the main thread and results in "deadly embrace"
      // The Process.Exited event should be used to avoid this.
      //proc.WaitForExit();
  }
  </code></pre>
  
  <p>and an event handler should be provided,</p>
  
  <pre><code>/// &lt;summary&gt;
  /// Actions to take when console process completes
  /// &lt;/summary&gt;
  private void ProcExited(object sender, System.EventArgs e)
  {
      Process proc = (Process)sender;
  
      // Wait a short while to allow all console output to be processed and appended
      // before appending the success/fail message.
      Thread.Sleep(40);
  
      if (proc.ExitCode == 0)
      {
          this.AppendText("Success." + Environment.NewLine);
          ExitBootloader();
      }
      else
      {
          this.AppendText("Failed." + Environment.NewLine);
      }
  
      proc.Close();
  }
  </code></pre>