C# – How to read to end process output asynchronously in C#

asynchronouscprocess

I have problem with reading the output of one Process asynchronously in C#.
I found some other similar questions on this site but they don't really help me.
Here is what I do:

  1. Make new process
  2. Set startinfo
    -FileName, Arguments, CreateNoWindow(true), UseShellExecute(false), RedirectStandardOutput(true)
  3. Add event handler to OutputDataReceived;
  4. Start process, BeginOutputReadLine and then WaitForExit().

It works fine but the output of the started process writes some percents(%) which I want to get but I can't since my code reads line by line and the percents don't show up.

Example:

%0,%1...%100
Finished.

My output:

%0
Finished. 

Here is the current code of my program:

StringBuilder sBuilder = new StringBuilder();
static void proc_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    sBuilder.AppendLine(e.Data);
}

static void CommandExecutor()
{
    Process process = new Process
    {
        StartInfo = new ProcessStartInfo
        {
            FileName = /*path of the program*/,
            Arguments = /*arguments*/,
            CreateNoWindow = true,
            UseShellExecute = false,
            WindowStyle = ProcessWindowStyle.Hidden,
            RedirectStandardOutput = true
        }
    };

    process.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived);

    process.Start();

    process.BeginOutputReadLine();

    process.WaitForExit();
}

Best Answer

Process.WaitForExit() will wait until the asynchronous output / error stream reading finished. Unfortunately this is not true for Process.WaitForExit(timeout) overload. This is what the Process class does internally:

//...

finally
{
    if (processWaitHandle != null)
    {
        processWaitHandle.Close();
    }
    if (this.output != null && milliseconds == -1)
    {
        this.output.WaitUtilEOF();
    }
    if (this.error != null && milliseconds == -1)
    {
        this.error.WaitUtilEOF();
    }
    this.ReleaseProcessHandle(safeProcessHandle);
}

... So it will wait for the async reads only if there was no timeout! To fix it simply call the parameterless WaitForExit() after WaitForExit(timeout) returned true:

// ...

if (process.WaitForExit( 10 * 1000 ) && process.WaitForExit() )
{
 // Process'es OutputDataReceived / ErrorDataReceived callbacks will not be called again, EOF streams reached
}
else
{
   throw new Exception("timeout");
}

For details read the remarks here: http://msdn.microsoft.com/en-us/library/ty0d8k56%28v=vs.110%29