Redirect console output to textbox in separate program
Asked Answered
A

4

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);
    }
Americanist answered 6/1, 2009 at 6:20 Comment(1)
Where is InputDataReceived?Saffren
B
73

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
}
Bebeeru answered 6/1, 2009 at 6:46 Comment(5)
I discovered that sometimes (on program exit) e.Data is null, so you have to check if e.Data != null!Fitful
+1 First time I saw something of this sort was in EditPlus. Now I can do it in my .NET programs. Thanks man!Pridgen
Don't we need to set UseShellExecute = false to redirect output?Blakney
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.Augustin
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).Opaline
S
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();
Sublapsarianism answered 6/1, 2009 at 12:11 Comment(1)
If "C:\ConsoleApp.exe" is not a .Net application this would not run!Fitful
W
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)

Whoever answered 26/11, 2011 at 18:1 Comment(0)
B
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) ));
}
Bently answered 17/2, 2015 at 14:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.