49

I'm developing an Windows Forms application that requires me to call a separate program to perform a task. The program is a console application and I need to redirect standard output from the console to a TextBox in my program.

I have no problem executing the program from my application, but I don't know how to redirect the output to my application. I need to capture output while the program is running using events.

The console program isn't meant to stop running until my application stops and the text changes constantly at random intervals. What I'm attempting to do is simply hook output from the console to trigger an event handler which can then be used to update the TextBox.

I am using C# to code the program and using the .NET framework for development. The original application is not a .NET program.

EDIT: Here's example code of what I'm trying to do. In my final app, I'll replace Console.WriteLine with code to update the TextBox. I tried to set a breakpoint in my event handler, and it isn't even reached.

    void Method()
    {
        var p = new Process();
        var path = @"C:\ConsoleApp.exe";

        p.StartInfo.FileName = path;
        p.StartInfo.UseShellExecute = false;
        p.OutputDataReceived += p_OutputDataReceived;

        p.Start();
    }

    static void p_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        Console.WriteLine(">>> {0}", e.Data);
    }
John Saunders
  • 160,644
  • 26
  • 247
  • 397

4 Answers4

72

This works for me:

void RunWithRedirect(string cmdPath)
{
    var proc = new Process();
    proc.StartInfo.FileName = cmdPath;

    // set up output redirection
    proc.StartInfo.RedirectStandardOutput = true;
    proc.StartInfo.RedirectStandardError = true;    
    proc.EnableRaisingEvents = true;
    proc.StartInfo.CreateNoWindow = true;
    // see below for output handler
    proc.ErrorDataReceived += proc_DataReceived;
    proc.OutputDataReceived += proc_DataReceived;

    proc.Start();

    proc.BeginErrorReadLine();
    proc.BeginOutputReadLine();

    proc.WaitForExit();
}

void proc_DataReceived(object sender, DataReceivedEventArgs e)
{
    // output will be in string e.Data
}
Mark Maxham
  • 1,501
  • 2
  • 13
  • 19
  • 5
    I discovered that sometimes (on program exit) e.Data is null, so you have to check if e.Data != null! – mmmmmmmm Jan 06 '09 at 12:54
  • +1 First time I saw something of this sort was in EditPlus. Now I can do it in my .NET programs. Thanks man! – Alex Essilfie Oct 06 '10 at 15:10
  • 3
    Don't we need to set `UseShellExecute = false` to redirect output? –  Sep 22 '14 at 18:44
  • 1
    Thanks Mark, however using this with a compiled Ruby script as an executable with just command output doesn't quite work as intended. First, as Jon of All Trades mentions, you need to have proc.StartInfo.UseShellExecute = false; ...then you can all of the data sent via BeginOutputReadLine() at once after the program completes. I have a feeling the ReadLine literally wants lines instead of text, so if the return/new line codes sent by the executable don't match the environment, it will not catch any data in OutputDataReceived until the app finishes. – John Suit Dec 04 '15 at 18:01
  • If you use this code in production, remember that `Process` is disposable, and also remember to detach the event handlers (`proc.ErrorDataReceived -= proc_DataReceived` etc). – Moo Feb 16 '16 at 11:42
5

You can use the following code

        MemoryStream mem = new MemoryStream(1000);
        StreamWriter writer = new StreamWriter(mem);
        Console.SetOut(writer);

        Assembly assembly = Assembly.LoadFrom(@"C:\ConsoleApp.exe");
        assembly.EntryPoint.Invoke(null, null);
        writer.Close();

        string s = Encoding.Default.GetString(mem.ToArray());
        mem.Close();
Ahmed
  • 7,148
  • 12
  • 57
  • 96
1

I've added a number of helper methods to the O2 Platform (Open Source project) which allow you easily script an interaction with another process via the console output and input (see http://code.google.com/p/o2platform/source/browse/trunk/O2_Scripts/APIs/Windows/CmdExe/CmdExeAPI.cs)

Also useful for you might be the API that allows the viewing of the console output of the current process (in an existing control or popup window). See this blog post for more details: http://o2platform.wordpress.com/2011/11/26/api_consoleout-cs-inprocess-capture-of-the-console-output/ (this blog also contains details of how to consume the console output of new processes)

Dinis Cruz
  • 4,161
  • 2
  • 31
  • 49
0

Thanks to Marc Maxham for his answer that save me time !

As Jon of All Trades notice it, UseShellExecute must be set to false in order to redirect IO streams, otherwise the Start() call throws an InvalidOperationException.

Here is my modification of the code where txtOut is a WPF readonly Textbox

void RunWithRedirect(string cmdargs)
{
    var proc = new Process()
    {
        StartInfo = new ProcessStartInfo("cmd.exe", "/k " + cmdargs)
        {
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            CreateNoWindow = true
        },
        EnableRaisingEvents = true
    };

    // see below for output handler
    proc.ErrorDataReceived += proc_DataReceived;
    proc.OutputDataReceived += proc_DataReceived;
    proc.Start();

    proc.BeginErrorReadLine();
    proc.BeginOutputReadLine();

    proc.WaitForExit();
}

void proc_DataReceived(object sender, DataReceivedEventArgs e)
{
    if (e.Data != null)
        Dispatcher.BeginInvoke(new Action( () => txtOut.Text += (Environment.NewLine + e.Data) ));
}
Jimi
  • 29,621
  • 8
  • 43
  • 61
LauLo
  • 87
  • 1
  • 5