Chapter 23. Layering Windows Forms on Console Applications

 

Discovery consists of seeing what everybody has seen and thinking what nobody has thought.

 
 --Albert Gyorgyi

Console applications are perhaps the most common application type used for tools because of their lightning-fast development nature, and because they provide a simple interface that is easy to learn. Users of console tools generally feel comfortable with console-based interfaces because they all typically function the same way, and it is very easy to pick up a new tool when the interface is consistent with old tools. Some advanced users also write or record scripts that automate the workflow of a particular set of tasks. Authoring scripts for console applications is much easier to do than for graphical user interfaces.

Tools development is all about reusability at both the code and application level. There may be some situations where an existing console application solves an intricate problem, but a graphical user interface version of the tool is wanted by a certain group of users. There are a few solutions to this problem. The first solution is to develop a Windows Forms version of the tool, using a fresh new code base. This solution requires the maintenance of two separate code bases, and can lead to support and synchronization problems. It also takes considerable time to build a new tool. The next solution is to develop a Windows Forms version of the tool and share the same code base. This might not be achievable if the console application is unmanaged and building a managed wrapper is out of the question.

An even more desirable solution is to build a Windows Forms wrapper around the console application, and redirect startup parameters and standard input and output. This solution offers the greatest level of maintainability and speed of development. If a change happens in the console application, it is immediately accessible by the Windows Forms version. Additionally, we do not have to worry about the console application being managed or unmanaged, since the redirection will happen at the process level, not at the code level.

Implementation

You can use the Process component to start and stop processes and retrieve information about the processes currently running on your system. We will be using this component to launch a console application, specify startup parameters, and redirect standard input and output. This component exists in the System.Diagnostics namespace.

using System.Diagnostics;

The following code defines a method that launches a redirected console application using the specified file path and argument list. Most of the code is fairly self-explanatory, though we set UseShellExecute to false so Windows Explorer is not used to launch the process. RedirectStandardInput is set to true so that we can get a stream handle to the console output. We also set CreateNoWindow to true so that a command prompt window is not launched alongside our Windows Forms application when the process is started.

The StandardOutput property returns a StreamReader that can retrieve the output data from the console application. The HasExited property can be queried while data is being read from the output stream.

public void LaunchConsoleApplication(string fileName, string arguments)
{
    if (!File.Exists(fileName))
    {
        MessageBox.Show("Invalid path to console application!");
        return;
    }

    Process process = new Process();

    process.StartInfo.FileName = fileName;
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.Arguments = arguments;
    process.StartInfo.CreateNoWindow = true;

    process.Start();

    StreamReader reader = process.StandardOutput;

    while (!process.HasExited)
    {
        OuputField.Text += reader.ReadLine() + Environment.NewLine;
        Application.DoEvents();
    }
}

The last piece of important code is to be placed in the closing event of the Form wrapping the console application. This code checks if the process is valid and if it has not exited yet. If true, the process is aborted. Obviously, this event has to have a reference to the process created by LaunchConsoleApplication.

The following code shows this event logic.

private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
{
    if (_process != null && !_process.HasExited)
    {
        _process.Kill();
    }
}

Sample Usage

The example provided alongside the implementation for this chapter is very simple. The demo console application is given two arguments: an iteration count and a message to print. The message is printed out however many iterations are specified.

The following code in the Windows Forms demo makes the console application print “Hello World” out five times. The number of iterations to print the message out is dependent on the iteration count specified as a parameter to the launch method.

private void LaunchButton_Click(object sender, EventArgs e)
{
    string message = ""Hello World"";
    LaunchConsoleApplication("SimpleConsoleApplication.exe",
                             "5 " + message);
}

The following code shows the logic for the demo console application.

static void Main(string[] args)
{
    int count = Convert.ToInt32(args[0]);

    string message;

    if (args[1] != null && args[1].Trim().Length > 0)
        message = args[1];
    else
        message = "No Message";

    for (int index = 0; index < count; index++)
    {
         Console.WriteLine(message + " - # " + (index + 1).ToString());
         System.Threading.Thread.Sleep(300);
    }
}

Conclusion

In this chapter, I discussed how to launch a console application process with parameters and redirect output to a Windows Forms application. This technique is very useful when you want to create a graphical user interface for an already existing console utility, while saving as much development and maintenance time as possible.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.217.107.229