Welcome to MSDN Blogs Sign in | Join | Help
Running an Executable and Collecting the Output

[Blog Map] 

Sometimes in the middle of a .NET application (either C# or VB) you want to run an executable and collect the output.  This post presents a simple function (RunExecutable) that makes it easy to do this.

I write a lot of documents that contain code.  Many of those documents also contain the expected output from the code.  When you have a very large document with many code snippets, it is useful to automate the testing of those snippets.  It gives me a warm and fuzzy feeling to verify that all of the code in my document(s) is validated just before I publish.  I’m going to use RunExecutable in an upcoming post that shows how to extract C# code from an Open XML document, compile it, run it, and validate that the output matches the output in the document.  This is particularly useful to, say, authors writing programming books.

But this code is useful in its own right.  Here is the code to run an executable, and collect the output:

using System;

using System.Text;

using System.IO;

using System.Diagnostics;

 

class RunResults

{

    public int ExitCode;

    public Exception RunException;

    public StringBuilder Output;

    public StringBuilder Error;

}

 

class Program

{

    public static RunResults RunExecutable(string executablePath, string arguments,

        string workingDirectory)

    {

        RunResults runResults = new RunResults

        {

            Output = new StringBuilder(),

            Error = new StringBuilder(),

            RunException = null

        };

        try

        {

            if (File.Exists(executablePath))

            {

                using (Process proc = new Process())

                {

                    proc.StartInfo.FileName = executablePath;

                    proc.StartInfo.Arguments = arguments;

                    proc.StartInfo.WorkingDirectory = workingDirectory;

                    proc.StartInfo.UseShellExecute = false;

                    proc.StartInfo.RedirectStandardOutput = true;

                    proc.StartInfo.RedirectStandardError = true;

                    proc.OutputDataReceived +=

                        (o, e) => runResults.Output.Append(e.Data).Append(Environment.NewLine);

                    proc.ErrorDataReceived +=

                        (o, e) => runResults.Error.Append(e.Data).Append(Environment.NewLine);

                    proc.Start();

                    proc.BeginOutputReadLine();

                    proc.BeginErrorReadLine();

                    proc.WaitForExit();

                    runResults.ExitCode = proc.ExitCode;

                }

            }

            else

            {

                throw new ArgumentException("Invalid executable path.", "executablePath");

            }

        }

        catch (Exception e)

        {

            runResults.RunException = e;

        }

        return runResults;

    }

 

    public static void Main()

    {

        RunResults runResults = RunExecutable("./ConsoleApplication2.exe", "aaa bbb ccc", ".");

        if (runResults.RunException != null)

            Console.WriteLine(runResults.RunException);

        else

        {

            Console.WriteLine("Output");

            Console.WriteLine("======");

            Console.WriteLine(runResults.Output);

            Console.WriteLine("Error");

            Console.WriteLine("=====");

            Console.WriteLine(runResults.Error);

        }

    }

}

After input from Jochan (see below), I've updated the code as shown.  Thanks, Jochan!

Code is attached.

Posted: Thursday, August 07, 2008 8:22 PM by EricWhite
Attachment(s): Program.cs

Comments

Jochen Kalmbach said:

Your code is wrong! It will *not* work, if your process will output (much) data to "StandardError" and "StandardOutput"!

See docu of "RedirectStandardOutput/Error"... please use a thread to read the error/output...

# August 7, 2008 4:26 PM

EricWhite said:

Jochen,

I understand that this will not work if producing very much output.  Remember, this is in the context of validating snippets of code that are in a document, where you would not expect output to be massive.  Sorry, I'm not an expert in all cases of use of these.  Do you feel that a separate thread is necessary even when validating snippets of code in a document?

Thanks for your input.  I certainly don't want to show code that demonstrates incorrect use.  If you can clarify further, it would be helpful.

-Eric

# August 7, 2008 4:53 PM

EricWhite said:

Code is updated per Jochan's comments.  Thanks.

# August 9, 2008 11:42 AM

Eric White's Blog said:

You can use lambda expressions to write an event handler, even for classes that predate C# 3.0 and the

# August 19, 2008 8:27 AM

Matt said:

Very nice! I've used a similar approach to do this asynchronously from another thread, writing the output lines to a TextBox as they come in:

<a href="http://thevalerios.net/matt/2008/08/monitor-a-process-asynchronously-more-delegatemarshaler-tricks/">http://thevalerios.net/matt/2008/08/monitor-a-process-asynchronously-more-delegatemarshaler-tricks/</a>

# August 19, 2008 12:13 PM

Matt said:

# August 19, 2008 12:13 PM

Eric White's Blog said:

Many types of documents contain code, including API documentation, tutorials, specifications, technical

# September 8, 2008 3:33 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Page view tracker