13

Is there anyway to redirect standard output of a spawned process and capture it as its happening. Everything I have seen just does a ReadToEnd after the process has finished. I would like to be able to get the output as it is being printed.

Edit:

    private void ConvertToMPEG()
    {
        // Start the child process.
        Process p = new Process();
        // Redirect the output stream of the child process.
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.RedirectStandardOutput = true;
        //Setup filename and arguments
        p.StartInfo.Arguments = String.Format("-y -i \"{0}\" -target ntsc-dvd -sameq -s 720x480 \"{1}\"", tempDir + "out.avi", tempDir + "out.mpg");
        p.StartInfo.FileName = "ffmpeg.exe";
        //Handle data received
        p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
        p.Start();
    }

    void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        Debug.WriteLine(e.Data);
    }
thecaptain0220
  • 2,098
  • 5
  • 30
  • 51

2 Answers2

18

Use Process.OutputDataReceived event from the process, to recieve the data you need.

Example:

var myProc= new Process();

...            
myProc.StartInfo.RedirectStandardOutput = true;
myProc.OutputDataReceived += new DataReceivedEventHandler(MyProcOutputHandler);

...

private static void MyProcOutputHandler(object sendingProcess, 
            DataReceivedEventArgs outLine)
{
            // Collect the sort command output. 
    if (!String.IsNullOrEmpty(outLine.Data))
    {
      ....    
    }
}
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Tigran
  • 61,654
  • 8
  • 86
  • 123
  • 1
    Yes, and in addition you need to set `RedirectStandardOutput` to true for this to work. – vcsjones Aug 16 '12 at 20:05
  • @vcsjones: just wrinting additional post. – Tigran Aug 16 '12 at 20:05
  • 1
    I tried that but I'm not having any luck. It runs fine but the callback is never hit. Maybe its a problem with the way the output is being printed. I am using this with ffmpeg. I will add my code to the original post. – thecaptain0220 Aug 16 '12 at 20:17
  • @thecaptain0220: but if you use `ReadToEnd(..)` does it work for you? – Tigran Aug 16 '12 at 20:33
  • No I tried p.WaitForExit() followed by p.ReadToEnd() and it returns an empty string – thecaptain0220 Aug 16 '12 at 20:47
  • @thecaptain0220: are you sure, at this point, that the *process* write *something* to output? – Tigran Aug 16 '12 at 20:48
  • If I set RedirectStandardOutput to false I can see all the status messages for the converting process. – thecaptain0220 Aug 16 '12 at 20:51
  • 4
    I also had to add `myProc.BeginOutputReadLine();` after I had started the process. – Markus Mar 13 '14 at 13:49
  • What is `if (!String.IsNullOrEmpty(outLine.Data))` for? Can data ever be null? Don't you want the empty lines in the output most of the time? – Lii Mar 31 '15 at 11:22
  • @Lii: question is about filtering out the commands or some keywords from the stream, which are nor 'null' or empty strings, I guess. – Tigran Mar 31 '15 at 11:50
  • 1
    @lii The [`dataReceivedEventHandler`](https://msdn.microsoft.com/en-us/library/system.diagnostics.datareceivedeventhandler(v=vs.110).aspx) documentation says: "When the redirected stream is closed, a null line is sent to the event handler. Ensure that your event handler checks for this condition before accessing the Data property. For example, you can use the static method String.IsNullOrEmpty to validate the Data property in your event handler." – RToyo Aug 01 '17 at 16:37
  • 1
    @RToyo IsNullOrEmpty should not be used since a null indicates to not continue but processing should continue after an empty line. – Sam Hobbs Jan 16 '19 at 19:57
8

So after a little more digging I found out that ffmpeg uses stderr for output. Here is my modified code to get the output.

        Process p = new Process();

        p.StartInfo.UseShellExecute = false;

        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.RedirectStandardError = true;

        p.StartInfo.Arguments = String.Format("-y -i \"{0}\" -target ntsc-dvd -sameq -s 720x480 \"{1}\"", tempDir + "out.avi", tempDir + "out.mpg");
        p.StartInfo.FileName = "ffmpeg.exe";

        p.ErrorDataReceived += new DataReceivedEventHandler(p_ErrorDataReceived);
        p.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);

        p.Start();

        p.BeginErrorReadLine();
        p.WaitForExit();
thecaptain0220
  • 2,098
  • 5
  • 30
  • 51
  • Great example! unfortunately does not work with p.StartInfo.UseShellExecute = true; (say, when trying to capture a long-running msbuild process and displaying the output in realtime in the Visual Studio output window). – gojimmypi Jun 25 '20 at 16:31