views:

2033

answers:

3

Hello,

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

I have redirected both StandardOutput and StandardError pipes and I'm recieving 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 recieved? Ideally I would like the Exited event to be the last event I recieve.

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 recieved? Ideally I would like the Exited event to be the last event I recieve.

Many thanks in advance,

Elggarc

+1  A: 

Unfortunately for you, in this case the point of the asynchronous reading of the output data is so you can deal with it at your leisure. Therefore you cannot ascertain if this DataReceivedEvent is the last or not. If you still require asynchronous reading of data from a process, you have the option of reading the data synchronously, but doing so in a thread or BackgroundWorker, guaranteeing that when there was no more data to receive the thread or BackgroundWorker would exit.

References:

  1. BackgroundWorker
  2. Thread
sixlettervariables
A: 

Spot on.

Thanks!

+2  A: 

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();
}
csharptest.net
Thanks, that was a great help.
ThisIsTheDave