How do I know when the last OutputDataReceived has arrived?

Elggarc picture Elggarc · Sep 15, 2008 · Viewed 8.7k times · Source

I have a System.Diagnostics.Process object in a program targeted at the .Net framework 3.5

I have redirected both StandardOutput and StandardError pipes and I'm receiving data from them asynchronously. I've also set an event handler for the Exited event.

Once I call Process.Start() I want to go off and do other work whilst I wait for events to be raised.

Unfortunately it appears that, for a process which returns a large amount of information, the Exited event is fired before the last OutputDataReceived event.

How do I know when the last OutputDataReceived has been received? Ideally I would like the Exited event to be the last event I receive.

Here is an example program:

using System;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApplication1
{
  class Program
  {

    static void Main(string[] args)
    {
      string command = "output.exe";
      string arguments = " whatever";

      ProcessStartInfo info = new ProcessStartInfo(command, arguments);

      // Redirect the standard output of the process. 
      info.RedirectStandardOutput = true;
      info.RedirectStandardError = true;

      // Set UseShellExecute to false for redirection
      info.UseShellExecute = false;

      Process proc = new Process();
      proc.StartInfo = info;
      proc.EnableRaisingEvents = true;

      // Set our event handler to asynchronously read the sort output.
      proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);
      proc.ErrorDataReceived += new DataReceivedEventHandler(proc_ErrorDataReceived);
      proc.Exited += new EventHandler(proc_Exited);

      proc.Start();
      // Start the asynchronous read of the sort output stream. Note this line!
      proc.BeginOutputReadLine();
      proc.BeginErrorReadLine();

      proc.WaitForExit();

      Console.WriteLine("Exited (Main)");

    }

    static void proc_Exited(object sender, EventArgs e)
    {

      Console.WriteLine("Exited (Event)");
    }



    static void proc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
    {
      Console.WriteLine("Error: {0}", e.Data);
    }



    static void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
      Console.WriteLine("Output data: {0}", e.Data);
    }


  }
}

When running this program you will notice that "Exited (Event)" appears in a completely variable location within the output. You may need to run it a few times and, obviously, you will need to replace "output.exe" with a program of your choice that produces a suitably large amount of output.

So, the question again: How do I know when the last OutputDataReceived has been received? Ideally I would like the Exited event to be the last event I receive.

Answer

csharptest.net picture csharptest.net · Sep 14, 2009

The answer to this is that e.Data will be set to null:

static void proc_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
     if( e.Data == null ) _exited.Set();
}