24

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.

KatieK
  • 13,586
  • 17
  • 76
  • 90

2 Answers2

29

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();
}
Oliver Bock
  • 4,829
  • 5
  • 38
  • 62
csharptest.net
  • 62,602
  • 11
  • 71
  • 89
1

It will be more comfortable if e.Data set to null, but actually, the value will be an empty string. Please note the first value also could be Empty string. The real answer is once you receive some value other than Empty string, then look for next Empty string. I am using Visual Studio 2019.