Invoking Command Lines Programmatically

Introduction

From time to time, the same situation occurs in my life as a programmer: I am able to accomplish a certain task quickly and easily - such as for example rearranging a computers TCP/IP settings to a set of predefined values or extracting some data from an Oracle database — by using a certain command line tool specialized on that task. But this tool would be far too troublesome to handle for an average computer user, because it is lacking a reasonable user interface and only accepts some strange, hard to understand jargon that must be typed in at the console. This is clearly not what 'using a computer' should be about in the 21st century!

What I was missing was a class that would be capable of executing every valid command line without having the caller caring much about things like console windows, system processes and the like. He simply gets back the output from the program he called - the same output that he would be presented with on the console window. The way Visual Studio's output window works might give you an idea of what I had in mind.

I soon discovered that programmatically executing a command line and receiving the resulting text output is an all but easy and straightforward business. First, you have to create and start a new system process that executes the desired command line. Then you have to create an additional thread that monitors the process' output pipes. And finally, to make things a bit more entertaining, you have to find out where exactly the output can be found and what code page is needed to make it look like something that one can present to an innocent user. And that's only the simple case, things get even more complicated when you want to execute a 'DOS command' such as e.g. dir ...

I searched the web for something that at least could be a help in accomplishing that task. I found nothing. In the end, I did what desperate developers often do (because they have to): I wrote my own solution from scratch. I came up with CommandLineProcess, a component class implemented as a Windows Class Library project.

This article describes in the first part some of the most important implementation aspects of this class. The second part presents a test and demo application for the CommandLineProcess class and, by examining some parts of the source code, demonstrates its principal usage.


The CommandLineProcess class

The CommandLineProcess class may be best described as a kind of 'windowless console'. It is a component class designed for calling an external command line from within a Windows Forms application (or any other application that wants to avoid opening a console window) and receiving its text output. This works for stand-alone command line applications as well as for commands invoking the Windows command line processor (so-called 'DOS commands').

CommandLineProcess exposes a set of properties and methods, with which a caller can define a command line, and start and stop its (asynchronous) execution. Information from the executing command line process, including its text output, is provided by various different events.

Some of the class' most important methods and properties are:

  • The Start method starts the execution of a given command line.
  • The Abort method kills the running process immediately.
  • The Close method frees all the resources (memory, handles etc.) that are associated with the process.
  • The Command property (string) defines which executable or 'DOS command' to execute. For Example: netsh.
  • The Arguments property (string) defines the argument list that the executable shall be called with. For example: -f c:\some_ip_settings.txt.
  • The CommandLine property (string, read-only) is simply the concatenation of Command and Arguments, i.e. the command line as a whole, as it would be executed on a call to the Start() method. In the example, this would be: netsh -f c:\some_ip_settings.txt.
  • The UseComSpec property (bool) determines whether or not the Windows command interpreter (cmd.exe) shall be used to execute the command line (in other words: whether or not the CommandLine property defines a 'DOS command').
  • The OutputCodepage property (int) defines the number of the codepage to use for re-encoding of the output text. Initially, this value will be set to the systems default OEM codepage.
  • The IsRunning property (bool, read-only) indicates whether the process is currently executing.

In the following, I will go through some of the main issues of the class' implementation and I will describe the events that are raised by a CommandLineProcess instance.


Starting the process

To execute a command line, the caller simply sets the values of the Command and Arguments properties to the desired values and then calls the Start() method. Internally, the CommandLineProcess class uses an object of type System.Diagnostics.Process as a wrapper for the system process that is actually executing the given command line.

As mentioned above, CommandLineProcess works for stand-alone applications accessible via a command line interface - for example H2Reg, some variations of the netsh command or some Oracle utilities - as well as for commands addressing the Windows command line processor - 'DOS commands' such as dir or ping. Whether or not cmd.exe shall be used can be determined by setting the UseComSpec property to true or false   ('COMSPEC' is the name of the environment variable that holds the path to the command line processor, most often its value is C:\Windows\system32\cmd.exe).

The code snippet below calls the tnsping Oracle tool for a database called SomeDB:

CommandLineProcess cmd = new CommandLineProcess();
cmd.Command = "tnsping";
cmd.Arguments = "SomeDB";
bool bSuccess = cmd.Start();

A 'DOS command' would be called like this:

CommandLineProcess cmd = new CommandLineProcess();
cmd.Command = "dir";
cmd.Arguments = "C:\";
cmd.UseComSpec = true;
bool bSuccess = cmd.Start();

Dependent on whether a genuine command line application or a 'DOS command' is executed, the internal handling of the command line itself and of the executing process component substantially differs. (However, this difference is totally transparent to the caller.) A command line like tnsping SomeDB can be executed directly by the process component by simply setting the appropriate StartInfo values and then starting it. But executing something like the seemingly simple dir C:\ requires much more than that. First, an instance of the command line processor cmd.exe has to be started, then the desired command line as a whole must be written to its input stream. Furthermore, there have to be taken some additional steps in order to cause cmd.exe to terminate automatically after executing the desired command and also not to produce text output other than the one originating directly from the executed command (like the path-including command prompts you know from the console window).

The following code excerpt shows the two different approaches (m_proc is a member of type System.Diagnostics.Process):

if (UseComSpec)
{
       // set Process start info to call the 'DOS interpreter' 
       // (the 'COMSPEC' environment variable points to it) 
       m_proc.StartInfo.FileName  = Environment.GetEnvironmentVariable("COMSPEC");
}
else 
{
       // set Process start info to execute command line program directly 
       m_proc.StartInfo.FileName  = Command;
       m_proc.StartInfo.Arguments = Arguments;
}
  
if (!m_proc.Start()) return false;      // start process
  
...
 
// Some extra actions have to be taken for commands executed by the 'DOS interpreter'
if (UseComSpec) 
{
       // first use "echo off" to suppress path prompts ... 
       m_proc.StandardInput.WriteLine("echo off");
       // ... then execute actual command ... 
       m_proc.StandardInput.WriteLine(CommandLine);
       // ... and finally cause the command line processor (cmd.exe) to quit 
       // immediately after finishing execution. 
       m_proc.StandardInput.WriteLine("exit");
}

Intercepting the process output

After the process that executes the desired command line has successfully been started, the next objective is to intercept the text output it produces. Every process is provided by the operating system with two output streams, called StandardOutput und StandardError, both have to be checked permanently for possible process output. This is done by starting an additional thread, whose thread procedure checks the two streams everytime the thread is called by the operating system.

This is the method that starts the listening thread (m_threadRec is a member of type System.Threading.Thread):

protected virtual bool StartOutputRecording()
{
       try 
       {
             // Create listening thread that will execute our thread procedure 
             m_threadRec = new Thread(new ThreadStart(ReadProcessOutput));             

              ...

             m_threadRec.Start();
             return true;
       }
       catch 
       {
             m_threadRec = null;
             return false;       // failure
       }
} 

And this is an extract from the related thread procedure that does the actual work:

protected virtual void ReadProcessOutput()
{
       string strLine;

       // check process' StandardOutput stream 
       try 
       {
             while ((strLine = m_proc.StandardOutput.ReadLine()) != null)
             {
                    ...

                    RaiseOutputLineEvent(OutputType.StdOut, strLine);     // send line
             }
       }
       catch {}

       // check process' StandardError stream 
       try 
       {
             while ((strLine = m_proc.StandardError.ReadLine()) != null)
             {
                     ...

                    RaiseOutputLineEvent(OutputType.StdErr, strLine);     // send line
             }
       }
       catch {}
} 

One last note: One might presume an application to write ist regular output to the StandardOutput stream and its error messages to StandardError. Well, in a perfect world this may be the case. However, in this world, you better not rely blindly on that fact ...


Stopping the process

Besides starting a process, CommandLineProcess provides the caller also with the possibility to immediately kill the running process (via its Abort() method). This is the same as pressing Ctrl+C on the console window whilst some command is being executed. Again, the actions that have to be taken greatly vary dependent on whether a command line is run by the command line processor or by a regular executable.

For 'normal' executables aborting simply means killing the related process. In this case, the code line m_ proc.Kill(); does all the job. But if we are running a 'DOS command', again it is not that simple at all.

Consider, for example, the simple command tree C:\. If you would simply call the Kill() method on the executing process, you would terminate the instance of the command line processor that was started to execute the tree command. That's ok so far. The problem is: tree.com itself is an executable, and thus a process, that in turn was started by the command line processor to execute our tree C:\ command. Thus, if we would simply call m_ proc.Kill(), we would leave behind an abandoned system process (named tree.com in this case). Obviously we need to find and kill our tree.com process instead of killing the related cmd.exe process, which then will terminate by itself as a reaction to the termination of the related tree.com process.

But it does not necessarily have to be that difficult. There are also many commands that are native to the command line processor. The dir command is an example for that. If you want to kill a process that is currently executing the command dir C:\, killing the cmd.exe process is actually all you need to do. The thing is: You cannot know in advance whether or not you have to deal with an additional process. That's why CommandLineProcess' Abort() method has become quite long. Here's an excerpt from that method that demonstrates the logic I described:

// First check if there is a process running that has the name of our 'DOS command'.
// This may or may not be true, because some of the 'DOS commands' are actually 
// executed by external processes whereas others are not. E.g. the 'tree' command is 
// actually executed by calling the 'tree.com' executable, whereas the 'dir' command is
// handled internally by the command line interpreter.
Process[ ] procs = Process.GetProcessesByName(Command);
int nCount = procs.GetLength(0);
Process procToKill = null;
int nCmdLen = Command.Length;

if (nCount == 1) // We have found one (and only one) process that has the name we look for.
{
	procToKill = procs[0];
}
else if (nCount == 0)     // No such process, but there may be one that has a file extension
{                         // appended to its name. E.g. executing the 'tree' command raises
                          // a process identified to the system as 'tree.com'.
       foreach (Process p in Process.GetProcesses())
       {
             if ((p.StartTime > m_proc.StartTime) && (p.ProcessName.Length > nCmdLen))
             {
                    if (p.ProcessName.Substring(0, nCmdLen) == Command)
                    {
                           if (procToKill == null) procToKill = p;
                           if (p.StartTime < procToKill.StartTime) procToKill = p;
                    }
             }
       }
}
else   // We have found more than one process of the desired name. In this case, 
{      // we kill the one which was started immediately after the command line
       // interpreter itself (which is represented by the m_proc variable). 
       foreach (Process p in procs)
       {
             if (p.StartTime > m_proc.StartTime)
             {
                    if (procToKill == null) procToKill = p;
                    if (p.StartTime < procToKill.StartTime) procToKill = p;
             }
       }
}

// If we have found an additional system process that was started by the process
// represented by the m_proc variable (which is actually an instance of the command 
// line processor), we kill it here and this will cause m_proc to terminate as well.
// If no additional process was found, we have to kill m_proc directly.
if (procToKill != null) procToKill.Kill();
       else m_proc.Kill();

- The above code is certainly not very elegant, but hey! It works. -


Getting information from the process

Since CommandLineProcess is designed to asynchronously execute an external system process, the question arises how the communication between the called and the calling process can be done. For that purpose, CommandLineProcess implements a set of events that enable the calling process to keep track of the various possible object states and to receive the text output from the process. The following events are available:

  • CmdLineChanged signals that the object's command line text (or its mode of usage with regard to cmd.exe) has changed.
  • OutputLine broadcasts one line of text read from one of the system process' output streams.
  • Started signals the successful start of the command line process.
  • Aborted signals that a running command line process was killed.
  • Exited signals that the command line process has exited.
  • Closed signals that all system resources allocated for the process component were freed.

Note Because the OutputLine event is triggered by an external thread, any code handling this event must be thread-safe!

In the second part of this article, I will show how these events can be used in your own code. For more implementation details please refer to the code and the documentation included in the src download package.


Getting human-readable text: the code page issue

The last thing I'd like to address here deals with text encoding. Sometimes the text output produced by a process might contain some special characters that are not part of the standard ASCII character set. Something like Ping-Statistik f.r 127.0.0.1: is clearly nothing that one would want to present to a user, or you may try the tree command without using code page no. 850 to see what I mean. That's why the CommandLineProcess class exposes the Codepage property, that lets the calling process select an appropriate code page to re-encode the text before it is broadcasted via the OutputLine event. Re-encoding of the text takes place in the ReadProcessOutput() method that was already introduced above. An object of type System.Text.Encoding is used to do that. Here's how the re-encoding is done.

First, the received text (strLine) is converted to a byte array, using the original output encoding:

m_buffer = m_proc.StandardOutput.CurrentEncoding.GetBytes(strLine);

Then the byte array gets re-encoded using the desired code page (which is represented by the m_encOutput variable):

String strResult = m_encOutput.GetString(m_buffer);

The OutputCodepage property will initially be set to a default value reflecting the standard OEM code page of the system. The DefaultOutputCodepage property returns the number of this code page:

// set OEM code page of current system environment by default
return CultureInfo.CurrentCulture.TextInfo.OEMCodePage;

This value should be good enough for 'DOS commands' and many command line tools. However, in some cases you might have to experiment a while in order to obtain a text that is human-readable ...


The provided online documentation

Besides the usual solution and source files, the src zip file contains an elaborate and extensive online documentation for the CommandLineProcess class that was created using Visual Studio's XML documentation feature and NDoc 1.3. This documentation gives a thorough overview of the CommandLineProcess class and goes deeper into some implementation details that could not be addressed here. - Admittedly, the extensive XML comments make the source file somewhat hard to read. But Visual Studio's outlining feature should enable you to find the code between the comments ...

I provided two versions of this documentation: one is a HTML 2 .chm help file for stand-alone usage, the other version is for integration with Visual Studio's MSDN online help system. (There is also a short how-to text file that briefly describes how this can be done, it's quite easy and straightforward.)

Invoking Command Lines Programmatically

Putting it all together:

The test and demo application

The fastest and easiest way to get a feeling for the CommandLineProcess class, its behaviour, its opportunities and its limitations, is possibly to experiment with it for a while. To do that, I wrote a Windows Forms application that may be described as something like a user interface for all of CommandLineProcess' methods, properties and events.

The picture below shows the program after executing the command ping localhost (on a german machine):

[DemoApp.jpg]

As you can see from the picture, the CommandLineProcess class exposes some more properties than the ones I have addressed here in this article. The values of these properties are directly mirroring the corresponding properties of the underlying System.Diagnostics.Process component.

The Browse button right to the Output Codepage text box will open a selection dialog box that lets the user select a code page from a list, thus making it quite comfortable to check the outcomes of using different code pages.

The CommandLineProcessDemo application is not only good for demonstration purpose. It is also a handy tool to explore the behaviour of a certain command line utility that you might want to use in your own application. I already mentioned that this is absolutely necessary. You can never be sure whether the text you need can be found on the StandardOutput or the StandardError stream (I even saw cases where all text ever produced was mindlessly written to both streams at the same time...), or what code page you will need in the end. Or maybe you need to check out the return values of a certain command line tool. All this can be done using the 'demo' application.

In the following, I will go through some code that is taken from the demo app's source and that shows how the CommandLineProcess class can be used in a Windows Forms Application. This may serve as a quick guide to incorporating the class into your own projects.

Step 1 - declaring the main form class

First of all, we need a Windows Forms class that declares a member variable of type CommandLineProcess. The three RichTextBox elements also shown here are for displaying the received output text and some protocol entries:

class CommandLineProcessDemo_form : System.Windows.Forms.Form
{
    CommandLineProcess m_cmd = new CommandLineProcess();

    ... 

    RichTextBox richEditStdOutput;
    RichTextBox richEditStdError;
    RichTextBox richEditProtocol;

    ... 

    [STAThread]
    static void Main () 
    {
        Application.Run(new CommandLineProcessDemo_form());
    }
}

Step 2 - registering with the CommandLineProcess' events

As described above, the CommandLineProcess class provides all of its information in the form of events. In order to receive these events, we need to wire an event handler delegate to each of these events. I did this 'wiring' in the constructor of the form class:

public CommandLineProcessDemo_form() 
{
    // form initialization stuff ... 

    ...

    // Connect to CommandLineProcess' events 
    // ------------------------------------- 
    m_cmd.CmdLineChanged += new CommandLineProcess.CmdLineChangedEventHandler(OnCmdLineChanged);
    m_cmd.Aborted        += new CommandLineProcess.AbortedEventHandler(OnAborted);
    m_cmd.Exited         += new CommandLineProcess.ExitedEventHandler(OnExited);
    m_cmd.Started        += new CommandLineProcess.StartedEventHandler(OnStarted);
    m_cmd.OutputLine     += new CommandLineProcess.OutputLineEventHandler(OnOutputLine);
    m_cmd.Closed         += new CommandLineProcess.ClosedEventHandler(OnClosed);

    // do something... 
    PingToYourself();
}

(Don't worry about the PingToYourself() method here, it will soon be introduced.)


Step 3 - implementing the event handlers

So far, we have assured that everytime when an event is fired by the m_cmd member, this leads to a call of a related method of our form class. Next we have to provide an implementation for these event handlers. They have to be of exactly the same type as the declaration of the corresponding event handler delegates declared as part of the CommandLineProcess class. (This concept is similar to function pointers and callback functions in C++. For more details and an overview of events, event handlers and delegates please refer to your MSDN documentation or some articles here on CodeGuru).

This is the event handler for the OutputLine event. It receives an argument class (named OutputLineEventArgs) that contains one line of text outputted by the running command line program, together with a flag (OutputType) indicating whether this line of text stems from the StandardOutput or StandardError stream. Note that processing this event has to be thread-safe, because the OutputLine event is initiated by the listening thread of CommandLineProcess, and this means that the related event handler can be called at any point during the course of the program. The easiest way of ensuring thread safety for an object (at least for its member variables) is to simply call lock(this) for the critical section:

// process outputs one line of text
private void OnOutputLine(object sender, CommandLineProcess.OutputLineEventArgs e)
{
    RichTextBox rtb;

    // ignore empty lines 
    if ((e.Text == null) || (e.Text.Length == 0)) return;

    // which output stream ? 
    if (e.OutputType == CommandLineProcess.OutputType.StdOut) 
        rtb = this.richEditStdOutput;
    else if (e.OutputType == CommandLineProcess.OutputType.StdErr)
        rtb = this.richEditStdError;
    else return;

    lock(this)      // protect richtextbox variable from being accessed by different threads 
    {               // simultaneously
        rtb.AppendText(e.Text + "\n"); // write to richedit control
    }
}

Next is the event handler for the CmdLineChanged event. It receives an argument class of type CmdLineChangedEventArgs. Its Text member contains the objects command line as it is currently set, UseComSpec contains the value of the same-named CommandLineProcess property. The event handler outputs the command line text and the value of the UseComSpec flag to the protocol window:

// Command line has changed
private void OnCmdLineChanged(object sender, CommandLineProcess.CmdLineChangedEventArgs e)
{
	if (e.Text != null)
    {
		StringBuilder strBld = new StringBuilder("CmdLineChanged event received, ");
		strBld.Append( "Text: '" + e.Text + "', ");
        if (e.UseComSpec) strBld.Append("UseComSpec: Yes.");
			else strBld.Append("UseComSpec: No.");

		richEditProtocol.AppendText(strBld.ToString() + "\n"); // write to richedit
	}
    else 
    {
		richEditProtocol.AppendText("CmdLineChanged event received, Text is null.\n"); 
    }
}

Note There is no need to be thread-safe here, since the CmdLineChanged event can occur only in reaction to setting the Command, Arguments, or UseComSpec properties from within our own code. This means that handling the event is equivalent to a direct (synchronous) function call. There is no possibility of a timely overlap in such a situation.

Last not least there are the event handlers for the Started, Aborted, Closed, and Exited events. There is nothing new to these methods. The argument class for each of these events contains a DateTime member (named StartTime, AbortTime and so on), and the event handlers simply write the value of this variable to the protocol rich edit control, if it is a valid time value. The ExitedEventArgs argument class contains an additional member for the process exit code, which is handled the same way. Here's the code for the four methods:

// CommandLineProcess has started
private void OnStarted(object sender, CommandLineProcess.StartedEventArgs e)
{
    if (e.StartTime == CommandLineProcess.UndefinedTimeValue)
    {
        richEditProtocol.AppendText("Started event received, Time not defined.\n"); 
    }
    else 
    {
        richEditProtocol.AppendText("Started event received, Time: '" + 
                                  e.StartTime.ToString("hh:mm:ss.ff") + "'.\n"); 
    }
}
// CommandLineProcess has aborted
private void OnAborted(object sender, CommandLineProcess.AbortedEventArgs e)
{
    if (e.AbortTime == CommandLineProcess.UndefinedTimeValue)
    {
        richEditProtocol.AppendText("Aborted event received, Time not defined.\n"); 
    }
    else 
    {
        richEditProtocol.AppendText("Aborted event received, Time: '" + 
                                  e.AbortTime.ToString("hh:mm:ss.ff") + "'. \n "); 
    }
}
// Process was closed (i.e. all related system resources were freed)
private void OnClosed(object sender, CommandLineProcess.ClosedEventArgs e)
{
    if (e.CloseTime == CommandLineProcess.UndefinedTimeValue)
    {
        richEditProtocol.AppendText("Closed event received, Time not defined.\n"); 
    }
    else 
    {
        richEditProtocol.AppendText("Closed event received, Time: '" + 
                                  e.CloseTime.ToString("hh:mm:ss.ff") + "'.\n"); 
    }
}
// CommandLineProcess has exited
private void OnExited(object sender, CommandLineProcess.ExitedEventArgs e)
{
    StringBuilder strBld = new StringBuilder("Exited event received, Time");

    if (e.ExitTime != CommandLineProcess.UndefinedTimeValue)
    {
        strBld.Append(": " + e.ExitTime.ToString("hh:mm:ss.ff") + ", Code");
    }
    else 
    {
        strBld.Append(" not defined, Code");
    }

    if (e.ExitCode != CommandLineProcess.UndefinedCodeValue)
    {
        strBld.Append(": " + e.ExitCode.ToString() + ".\n");
    }
    else 
    {
        strBld.Append(" not defined.\n");
    }

    richEditProtocol.AppendText(strBld.ToString()); 

    m_cmd.Command = null;    // clear command line after execution
}

Step 5 - preventing the form from being closed while process is executing

One more thing to care about is program termination. We have to make sure that the main window cannot be closed whilst the command line process is running, because this would lead to quite ugly consequences. Therefore, if the CommandLineProcess object is currently executing, closing the main window (which means termination of the application) is canceled if the user tries to do so. This can be done in the form's event handler for the Closing event:

// Protect main window from being closed while CommandLineProcess is executing
private void CommandLineProcessDemo_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
       if (m_cmd.IsRunning) 
       {
             e.Cancel = true; // Cancel closing

             // inform user
             string strMsg;
             strMsg  = "Closing canceled, CommandLineProcess is executing.\n" + 
						"Wait for exit or abort.";
             MessageBox.Show(strMsg);
       }
}

Step 6 - performing some action

Now we have the main form class, we have registered with CommandLineProcess' various events and we have implemented the related event handlers. Finally we have to do something to see how it works. The PingToYourself() method that you have already seen above does exactly what its name implies: it starts the CommandLineProcess member with the ping localhost command line:

// call the ping utility
private void PingToYourself()
{
    m_cmd.Command = "ping";
    m_cmd.Arguments = "localhost";
    m_cmd.UseComSpec = true; // this is optional here
    if (!m_cmd.Start()) MessageBox.Show("CommandLineProcess.Start() failed!");
}

Note that this piece of code would also work with the UseComSpec property set to false, since ping is a 'DOS command', but ping.exe is at the same time a stand-alone executable that can be run on its own.

The code above will produce a text output to the protocol window that will be similar to the following:

CmdLineChanged event received, Text: 'ping'. UseComSpec: No.
CmdLineChanged event received, Text: 'ping localhost'. UseComSpec: No.
CmdLineChanged event received, Text: 'ping localhost'. UseComSpec: Yes.
Started event received, Time: 01:58:19.70.
Exited event received, Time: 01:58:22.95, Code: 0.
CmdLineChanged event received, Text is null.

The StandardOutput rich edit box will read something like this (for a german machine named centrino):

StandardOutput: Ping centrino [127.0.0.1] mit 32 Bytes Daten:
StandardOutput: Antwort von 127.0.0.1: Bytes=32 Zeit<1ms TTL=64
StandardOutput: Antwort von 127.0.0.1: Bytes=32 Zeit<1ms TTL=64
StandardOutput: Antwort von 127.0.0.1: Bytes=32 Zeit<1ms TTL=64
StandardOutput: Antwort von 127.0.0.1: Bytes=32 Zeit<1ms TTL=64
StandardOutput: Ping-Statistik f|r 127.0.0.1:
StandardOutput: Pakete: Gesendet = 4, Empfangen = 4, Verloren = 0 (0% Verlust),
StandardOutput: Ca. Zeitangaben in Millisek.:
StandardOutput: Minimum = 0ms, Maximum = 0ms, Mittelwert = 0ms


Summary

This article introduces the CommandLineProcess class, which is designed for calling a command line from within any other code and receiving the resulting text output via an event mechanism. The first part discusses some of the implementation details of the class and describes some subtleties that had to be taken into account when writing the code. The second part presents a demo and test application for the CommandLineProcess class and gives a brief overview of how it can be utilized in your own code. For issues that were not addressed in this article (or not explicitely enough), please refer to the online documentation included with the src zip file.

CommandLineProcess is a good means for creating a user-friendly interface for an existing, but hard-to-handle command line tool. There are many tools of this kind out there, for example some Oracle utilities or some variations of the netsh command, to name just two. Me, for example, I have used CommandLineProcess to create a Windows application that lets the average user load and save data from and to an Oracle database with just a few mouse clicks. Actually it's not much more than a Windows user interface for the Oracle imp and exp command line tools. But for someone who is sick of typing weird commands at the console that no one can remember, it can be quite an improvement of his everyday work.

And that's what software development in the end is all about: Making life easier. Not necessarily my own, but, in any case, that of the users of my programs.



Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • In this webinar, IDC featured speaker Steve Conway, Vice President of High Performance Computing, will present an update on the global x86 HPC cluster market. The presentation will include IDC's five-year forecast for the medium- to large-scale technical computing and data analysis emerging markets by systems, processors and application middleware. Cray's featured speaker, John Lee, Vice President of Cray Cluster Advanced Technology Systems, will present the new Cray® CS400™ cluster series based on …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds