Introduction
Sometimes in the life of a developer, a need arises to control another application from his/her application. It may be to provide automation services, to give control or for the ease of use of customers who are not very computer savvy.
There are many different tools and technologies available these days to accomplish that kind of automation. Integration between applications depends on the services that applications can expose or provide. For example, in the good days on Windows 3.1, Data Dynamic Exchange (DDE) or some screen scrapping techniques were used to accomplish that. DDE utilized the basic Windows Messaging Layer functionality. Since the DDE was limited to transferring data between two running applications, with the emergence of Object Linking and Embedding (OLE) automation became more prominent to these integration tasks with much confidence. OLE became the backbone for technologies such as Component Object Model (COM). Now-a-days different applications provide their object models to achieve the same kind of integration services. A good example of it would be the Microsoft Office line of products. Microsoft Office such as Excel or Word provide their object models to integrate with them.
But still from time to time there are applications which do not provide or expose any of the above mentioned techniques that can be utilized to do the integration with them. The only way to control these kinds of applications is emulating keystrokes to them to make them act as they would if they were in focus and taking keyboard input.
This small sample application shows how to accomplish this emulation of sending keystrokes to applications using Microsoft .NET Framework using C#.
SendKeys Application
This is very simple WinForm application, which basically utilizes .NET 2.0 SendKeys
class to do most of its work. SendKeys
class is defined in System.Windows.Forms
namespace. One issue with the SendKeys
class is it can only send keystrokes to the active application. Active application is the one which is in focus to accept keyboard input. To make any Windows active from another application we have to take help from the Windows native API SetForegroundWindow
. SetForegroundWindow
requires the Windows handle to bring it to the front. To get the Window handle I use yet another native API FindWindow
. FindWindow
takes two arguments, the first is the pointer to a null
-terminated string
that specifies the class name used to register the Window class and if this is null
then the second argument is a Pointer
to a null
-terminated string
that specifies the Window name (the Window's title).
int iHandle = NativeWin32.FindWindow(null, txtTitle.Text);
NativeWin32.SetForegroundWindow(iHandle);
Windows native APIs can be incorporated into a .NET application via PInvoke
. PInvoke
functionality is by inclusion of System.Runtime.InteropServices
namespace. Adding the Windows native APIs signature could be a daunting task specially if you do not have background and/or experience in C++ development. To facilitate this task some good guys brought up a very good site that can get you a jump start. In this project NativeWin32
class provides encapsulation for the Windows native API and also exposes their functionality.
As you have some idea about the driving force for this application creation, I will now explain the usability of the application for your reference.
When you launch this application it will display a single Winform as shown with an Auto radio button selected. This 'Auto' selection shows a combobox under 'Windows Title' filling up with all the top level Windows applications running on the machine. This service is only provided for ease of use. You can select 'Manual' which would display a text box to type the Windows title of the application you want to send keys to.
The 'Refresh' link would help to update the combobox entries to the currently running Windows. To update the combobox with the currently running applications, we again take a simple approach and call the native Windows API as shown below:
private void GetTaskWindows()
{
int nDeshWndHandle = NativeWin32.GetDesktopWindow();
int nChildHandle = NativeWin32.GetWindow(nDeshWndHandle,
NativeWin32.GW_CHILD);
while (nChildHandle != 0)
{
if (nChildHandle == this.Handle.ToInt32())
{
nChildHandle = NativeWin32.GetWindow
(nChildHandle, NativeWin32.GW_HWNDNEXT);
}
if (NativeWin32.IsWindowVisible(nChildHandle) != 0)
{
StringBuilder sbTitle = new StringBuilder(1024);
NativeWin32.GetWindowText(nChildHandle, sbTitle, sbTitle.Capacity);
String sWinTitle = sbTitle.ToString();
{
if (sWinTitle.Length > 0)
{
cboWindows.Items.Add(sWinTitle);
}
}
}
nChildHandle = NativeWin32.GetWindow(nChildHandle,
NativeWin32.GW_HWNDNEXT);
}
}
Once the Window is decided with either of above defined way, you can select keys you want to send from the 'All Keys' listbox and press the 'Add' link to add them into the 'Keys to Send' listbox. 'All Keys' listbox displays all the possible keys that are supported and can be sent out to other applications. You can select multiple keys at the same time with the normal selection behavior provided by the listbox. One caveat to be aware of though, the selection with the added sequence from the 'All Keys' as they appear in the listbox and not as the order of your selection. Order of selection functionality can be added with ease but I leave it as an exercise to the readers.
'LoadKeys
' and 'SaveKeys
' give the serialization and deserialization abilities for the keys displayed in 'Keys to Send' listbox. 'Delete' link helps in removing selected keys from the 'Keys to Send' listbox.
'Replicate' link provides the functionality to multiple the keystroke 'n
' times of the selected keys from the 'Keys to Send' listbox. Again the selection will multiply in sequential order.
After setting all these, pressing the 'Send Keys' button would activate the application matching with the Windows title and start sending keystrokes as someone is using a keyboard to that application.
Application Extension Possibilities
This application gives you a general idea on how to use sending keystrokes mechanism to another application. One possible extension to this approach could be sending keystrokes to multiple applications at the same time by extending the selection of multiple applications by using listbox rather then combobox.
History