Tag Archives: UI Automation

Automating a WinForms login form using SendKeys

This article describes how you can fill in form fields and invoke buttons from code using SendKeys, without directly interacting with the UI. The initial examples do this from the same application, but it is later shown how to do this UI automation from a separate application.

sendkeys-login-initial2

In this article, we’re going to use a simple login form as an example. It contains what you’d normally expect: fields to enter the username and password, and a Login button. Additionally, it contains an Automate button at the top which we’ll use to execute our automation code.

You’ll notice that I already have something in the Automate button’s click event handler:

            SendKeys.Send("username");

If you try this, you might expect that something gets written in the username field. But alas, nothing happens. That’s because SendKeys is limited to sending keystrokes to the focused control on the currently active application. Therefore, to actually send text to the username field, we first have to focus it.

We can try forcing focus on the username field:

            this.usernameField.Focus();
            SendKeys.Send("username");

…and indeed that works. But that won’t quite work if we’re automating the UI from a second application, since it has no idea about the fields present in our login form.

Therefore, another way is to actually send TAB keys to navigate to the desired control, before sending actual text. Special keys such as TAB and ENTER are represented by special codes such as {TAB} and {ENTER} (refer to the SendKeys documentation for a full list). Thus we can achieve the same effect like this:

            SendKeys.Send("{TAB}username");

And likewise, we can fill in the whole form, and finally invoke the Login button by first giving it focus and then sending an ENTER key:

            SendKeys.Send("{TAB}username{TAB}password{TAB}{ENTER}");

So you can see that the result is just what we expected:

sendkeys-login-loggedin

Naturally, keep in mind that tabbing to the desired control is entirely dependent on the tab index of the controls. If that changes, your automation code will have to change accordingly. It might not be an ideal approach, but it’s just about the best you can do for SendKeys if you want an application to send keystrokes to another.

Speaking of which, so far we’ve taken the shortcut of doing everything within the same application, in which case giving focus to controls directly is just fine. Let us now create a second Windows Forms application, and see how we can use it to automate our login form’s UI.

Actually, all we need is a simple form with a button, whose Click event handler will execute our automation code:

sendkeys-login-automatorstub

Now as I said before, SendKeys works only with the currently active application. If we want to automate our login form, we’ll need some code to find it from the list of running applications, and activate it. This StackOverflow answer has some code that takes care of this.

The first thing we need to do is find the process we want to automate. For that we need the name of the process. If it’s already running, you can find it in the Task Manager:

sendkeys-login-taskmanager

Notice how if you’re running directly from Visual Studio, the process will contain a “.vshost” before the file extension.

We can now get the process we want (Process is in the System.Diagnostics namespace):

            Process p = Process.GetProcessesByName("WinFormsLogin.vshost").FirstOrDefault();

Note that we omit the .exe extension from the process name above.

Once that is done, we need to bring that process to the foreground using some code from the answer linked above. So first, import the Win32 SetForegroundWindow() function (DllImport requires the System.Runtime.InteropServices namespace):

[DllImport ("User32.dll")]
static extern int SetForegroundWindow(IntPtr point);

Once we have this, we bring the process to the foreground, and send any keystrokes we need:

            Process p = Process.GetProcessesByName("WinFormsLogin.vshost").FirstOrDefault();

            if (p != null)
            {
                IntPtr h = p.MainWindowHandle;
                SetForegroundWindow(h);
                SendKeys.SendWait("{ENTER}");
            }

And there you go, the Automator application invokes the automation button on the Login application:

sendkeys-login-acrossapps

Now you’ll notice I’m kind of cheating here: I’m just sending the ENTER key to activate the Automate button in the Login form (which happens to have a tab index of zero, i.e. it’s the first thing to be focused). The applications you want to automate won’t normally have an Automate button. But just as you can send an ENTER key from one application to another, you can send other keys. We can thus do our automation anyway:

            Process p = Process.GetProcessesByName("WinFormsLogin.vshost").FirstOrDefault();

            if (p != null)
            {
                IntPtr h = p.MainWindowHandle;
                SetForegroundWindow(h);
                SendKeys.Send("{TAB}username{TAB}password{TAB}{ENTER}");
            }

Great! You can use SendKeys for simple automation of Windows Forms applications by sending keystrokes – even across applications. If you want to automate Microsoft Word or anything of the sort, this won’t work, although there are alternatives. If you’re doing more serious stuff (e.g. WPF) there are entire APIs you can look at.