Wrapping an external app in a class
Written by Ian Elliot   
Monday, 18 April 2011
Article Index
Wrapping an external app in a class
Exit events and cross threading
Invoke method

There are lots of techniques for controlling an existing Windows application from code, but why not go one better and write a class that represents the app within your program? It can be done!

As long as you prepared to use a few non-obvious techniques then running an existing application under the control of a .NET “wrapper” program is fairly easy. Our project .NET MP3 demonstrates how to run command line .EXE program using the Process class, but it is possible to go further and wrap standard Windows applications.

As a simple example we create a wrapper for NotePad, but the technique works just a well with any Windows application. The example is a good illustration of not just using the process class, SendKeys and Shell but also how to pass on events and deal with cross-threading problems.

VB in C# - Running Notepad

You can start any application using the Process class but VB programmers have the Shell command that is easier to use. However there is nothing stopping C# programmers using classes that were intended to be used in VB .NET.

If you start a new Windows project and add a new class called NotePad then to use the Shell object all we need to do is add a reference (Project,Add Reference) to Microsoft.VisualBasic and add:

using Microsoft.VisualBasic;

The object that we want to make use of is Interaction. You should look this up in the documentation because it has lots of useful methods. The one of immediate value is Shell, which starts an application running and returns a process handle to it. The location of the application that we want to run could be specified in a number of ways, even as a parameter in the constructor, but in this case a constant is simpler:

private const string location = 
"NotePad.exe";

It seems reasonable to create the instance of the application in the constructor:

public NotePad()
{
Int32 ProcessHandle = Interaction.Shell(
  location,
AppWinStyle.NormalFocus,
false, 0);
}

Now if you return to the main form, add a button and the following code:

private void button1_Click(
object sender, EventArgs e)
{
NotePad NP = new NotePad();
}

Running the program and clicking on the button results in an instance of NotePad starting.

To really keep control of NotePad we need to associate it with a Process object. Given we have a process handle, this is easy:

NPad = Process.GetProcessById(ProcessHandle);

To make this work we need to add a private variable:

private Process NPad;

and

using System.Diagnostics;

Notice that now we can access the process handle as NPad.Id and we have lots of facilities for managing the process.

Sending data

The simplest way of sending data to the running application is to use the SendKeys static class that we get from the System.Window.Forms name space.

This is best packaged as a new method of the NotePad class.

public void Input(string Text)
{
if (NPad.Responding)
{
Interaction.AppActivate(NPad.Id);
Thread.Sleep(10); SendKeys.SendWait(Text);
}
}

The Process object is used to check that the application has a responsive user interface. Then the Interaction object is used to make the application active. Notice that (contrary to the documentation) this is the managed way to activate an application even if it has been borrowed from VB .NET.  Finally the SendWait method is use to send the text. The use of the Thread object to pause the program is necessary because some applications miss keystrokes if you send them too fast. If you find that this is happening simply increase the delay. It would be nice to avoid putting the tread to sleep and it would be nice to interlock the two applications together but in practice the method works well enough.

To make all this work we need to add:

using System.Windows.Forms;
using System.Threading;

If you now add:

NP.Input("Hello World");

to the Button's event handler you will see the message appear when the NotePad is created.

You can, of course send any commands to the application that have keyboard shortcuts – see the documentation on SendKeys to discover how to send control codes etc.

 

Banner



Last Updated ( Monday, 18 April 2011 )