ProcessInfo and RedirectStandardOutput

49,292

Solution 1

I've experienced this before. Sometimes, the way in which the process you're calling outputs to the console is not compatible with this sort of output redirection. I've been fortunate enough in this case to be able to modify the external process to get around this.

You might try running your code on another process that outputs to the console, and see if it works properly. It reads about right to me right now.

EDIT:

I went and pulled a code block I've used to do this. This is in a WPF app which redirects the process output to the window. Notice the event binding. Since this is WPF I have to invoke my call to write the data out. Since you aren't worried about blocking, ou should be able to simply replace that with:

Console.WriteLine(e.Data);

Hopefully it helps!

    private static void LaunchProcess()
    {
        Process build = new Process();
        build.StartInfo.WorkingDirectory =  @"dir";
        build.StartInfo.Arguments = "";
        build.StartInfo.FileName = "my.exe";

        build.StartInfo.UseShellExecute = false;
        build.StartInfo.RedirectStandardOutput = true;
        build.StartInfo.RedirectStandardError = true;
        build.StartInfo.CreateNoWindow = true;
        build.ErrorDataReceived += build_ErrorDataReceived;
        build.OutputDataReceived += build_ErrorDataReceived;
        build.EnableRaisingEvents = true;
        build.Start();
        build.BeginOutputReadLine();
        build.BeginErrorReadLine();
        build.WaitForExit();
    }

    // write out info to the display window
    static void build_ErrorDataReceived(object sender, DataReceivedEventArgs e)
    {
        string strMessage = e.Data;
        if (richTextBox != null && !String.Empty(strMessage))
        {
            App.Instance.Dispatcher.BeginInvoke(DispatcherPriority.Send, (ThreadStart)delegate()
            {
                Paragraph para = new Paragraph(new Run(strMessage));
                para.Margin = new Thickness(0);
                para.Background = brushErrorBrush;
                box.Document.Blocks.Add(para);
            });
       }
    } 

Solution 2

I'm not sure exactly what problem you're running into, but if you're looking to act on output as soon as it's generated, try hooking into the process's OutputDataReceived event. You can specify handlers to receive output asynchronously from the process. I've used this approach successfully.

Process p = new Process();
ProcessStartInfo info = p.info;
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;

p.OutputDataReceived += p_OutputDataReceived;
p.ErrorDataReceived += p_ErrorDataReceived;

p.Start();

p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();

..

void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
  Console.WriteLine("Received from standard out: " + e.Data);
}

void p_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
  Console.WriteLine("Received from standard error: " + e.Data);
}

See the OutputDataReceived event off Process for more information.

Solution 3

Using lambda expressions, etc:

var info = new ProcessStartInfo(path)
{
    RedirectStandardError = true,
    RedirectStandardOutput = true,
    UseShellExecute = false,
    Verb = "runas",
};

var process = new Process
{
    EnableRaisingEvents = true,
    StartInfo = info
};

Action<object, DataReceivedEventArgs> actionWrite = (sender, e) =>
{
    Console.WriteLine(e.Data);
};

process.ErrorDataReceived += (sender, e) => actionWrite(sender, e);
process.OutputDataReceived += (sender, e) => actionWrite(sender, e);

process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.WaitForExit();

Solution 4

Interestingly you can't read from standard output and standard error at the same time:

if you redirect both standard output and standard error and then try to read both, for example using the following C# code.

[C#]

string output = p.StandardOutput.ReadToEnd();

string error = p.StandardError.ReadToEnd();

p.WaitForExit();

In this case, if the child process writes any text to standard error it will block the process, because the parent process cannot read from standard error until it has finished reading from standard output. However, the parent process will not read from standard output until the process ends. A recommended solution to this situation is to create two threads so that your application can read the output of each stream on a separate thread.

http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo.redirectstandardoutput(v=vs.71).aspx

Solution 5

flowing code worked in VS2010

void OnOutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        if (String.IsNullOrEmpty(e.Data) == false)
        {
            new Thread(() =>
            {
                this.Dispatcher.Invoke(new Action(() =>
                {
                    // Add you code here
                }));
            }).Start();
        }
    }
Share:
49,292
Brandon Grossutti
Author by

Brandon Grossutti

Updated on August 05, 2022

Comments

  • Brandon Grossutti
    Brandon Grossutti almost 2 years

    I have an app which calls another process in a command window and that process has updating stats that output to the console window. I thought this was a fairly simple operation but I can't seem to get it to work. Am I missing something?

    string assemblyLocation = Assembly.GetExecutingAssembly().Location;
    
    Process process = new Process
    {
        ProcessStart =
        {
            RedirectStandardOutput = true,
            UseShellExecute = false,
            WindowStyle = ProcessWindowStyle.Hidden,
            Arguments = arg,
            FileName = assemblyLocation.Substring(0, assemblyLocation.LastIndexOf("\\")) + "\\ffmpeg.exe",
            CreateNoWindow = true
        }
    };
    
    process.Start();
    
    Console.WriteLine(process.StandardOutput.ReadToEnd());
    
    process.WaitForExit();
    

    Ideally what I would like is as the output changes within that process I hit or data comes into the reader that I get events off it.

    Any help would be great, I feel like this is a newbie question but seem to be missing something.

  • Brandon Grossutti
    Brandon Grossutti almost 15 years
    you mean another thread or another process? i can run the process from cmd line and the output looks good.
  • patjbs
    patjbs almost 15 years
    I meant a different process from the one you're trying. In the instance I encountered, when I redirected the stdout, the process wouldn't clear it's output buffer when launched this way, and so the stream would just all come through at the end. This may or may not be your problem. See my code example for how I've handled this in my own apps.
  • 3Dave
    3Dave almost 14 years
    I can get this to work with most console apps but not PowerShell. Any thoughts?
  • abatishchev
    abatishchev over 13 years
    You need to Start() a process before WaitForExit()
  • abatishchev
    abatishchev over 13 years
    Sorry! My inattention. Muddled up with Process p = Process.Start(info);
  • shindigo
    shindigo over 13 years
    Excellent solution! This also solved a problem I was having where too much console output was causing the spawned process to hang at a Console.WriteLine. Thanks!
  • Peter Stephens
    Peter Stephens over 12 years
    @David Lively, you may try the undocumented PowerShell parameter -InputFormat none.
  • 3Dave
    3Dave over 12 years
    @PeterStephens That's new - I'll certainly give it a shot.
  • Ibrahim Amer
    Ibrahim Amer almost 10 years
    @MichaelPetrotta Thank you a lot sir!! .. this solved my problem like a charm :D
  • Kiquenet
    Kiquenet over 9 years
    Only a note about it: Verb "runas" only works if UseShellExecute = true, Verb = "runas". If UseShellExecute = true you cannot redirect output. View more in kiquenet.wordpress.com/2014/08/22/…
  • Kiquenet
    Kiquenet over 9 years
    What is Dispatcher ? What is this? What is OnOutputDataReceived event ? What is DataReceivedEventArgs type ? Which is the full context of your source code?
  • BatteryBackupUnit
    BatteryBackupUnit over 9 years
    Normally you should attach the event handlers before starting the process. Otherwise you might be missing events.
  • Aardvark
    Aardvark over 8 years
    It's not true that there is no way to read both streams, just that it is not safe to use only synchronous methods on both streams at the same time. I just want to clarify that @jeremy-mcgee saying "not true" doesn't make the quoted info in the answer incorrect.
  • Alexander Trauzzi
    Alexander Trauzzi almost 5 years
    This is a great breakdown of some of the nuances in capturing output. Thanks for putting this together.
  • Rajaraman Subramanian
    Rajaraman Subramanian over 2 years
    @patjbs This code snippet is really helpful.