C++ Q&A

Sending Keystrokes to Any App, Calling .NET from an MFC App, and More

Paul DiLascia

Code download available at:CQA0501.exe(231 KB)

Q I'm trying to write an application that fills in forms by sending keystrokes to another application. Should I send WM_KEYDOWN and WM_KEYUP messages, or is there a better way?

Q I'm trying to write an application that fills in forms by sending keystrokes to another application. Should I send WM_KEYDOWN and WM_KEYUP messages, or is there a better way?

Many readers

A You can probably get your app to work by sending WM_KEYDOWN and WM_KEYUP messages, but SendInput is an API function designed specifically for this purpose. It synthesizes input including keystrokes and mouse events by taking an array of INPUT structures, one for each input event—keystroke or mouse action. The INPUT structure holds a union that's either MOUSEINPUT or KEYBDINPUT (or HARDWAREINPUT, to simulate the toaster oven). For the keyboard it looks like this:

struct KEYBDINPUT { WORD wVk; // virt key code WORD wScan; // hw scan code DWORD dwFlags; // flags—see doc DWORD time; // time stamp, 0 = dflt ULONG_PTR dwExtraInfo; // app-defined };

A You can probably get your app to work by sending WM_KEYDOWN and WM_KEYUP messages, but SendInput is an API function designed specifically for this purpose. It synthesizes input including keystrokes and mouse events by taking an array of INPUT structures, one for each input event—keystroke or mouse action. The INPUT structure holds a union that's either MOUSEINPUT or KEYBDINPUT (or HARDWAREINPUT, to simulate the toaster oven). For the keyboard it looks like this:

struct KEYBDINPUT { WORD wVk; // virt key code WORD wScan; // hw scan code DWORD dwFlags; // flags—see doc DWORD time; // time stamp, 0 = dflt ULONG_PTR dwExtraInfo; // app-defined };

Figure 1 Typematic Initial Dialog

Figure 1** Typematic Initial Dialog **

So sending keystrokes to another application is basically a matter of building an array of INPUT structures, one for each keystroke (up and down), and then calling SendInput. To show how it works in practice, I wrote a little program called Typematic which lets you type your name, address, phone number, or other info quickly into forms just by pressing a hot key. It's the perfect thing for Web shopaholics. When you first run Typematic it displays the dialog in Figure 1, then goes into hiding. Thereafter you can press <WinKey>+T to reactivate Typematic and get the dialog in Figure 2 to see a list of abbreviations. Type "n" for name or "a" for address, and Typematic sends the corresponding string into the current form or application. The abbreviations are defined in a static table you can modify to use your own identity:

struct ABBREV { TCHAR key; LPCTSTR text; } MYABBREVS[] = { { _T('n'),_T("Elmer Fudd") }, { _T('a'),_T("1 Bunny Way") }, ... { 0,NULL} };

Figure 2 Typematic Reactivated

Figure 2** Typematic Reactivated **

In the real world, you wouldn't hard-code this information, of course; you'd provide a user interface for customizing it, and save the info in the user's profile so each user on the machine could have different settings.

Typematic illustrates a few other tricks: how to register a hot key to activate your app (see my December 2000 column) and how to make a static text control accept keyboard input (you have to handle WM_GETDLGCODE and return DLGC_WANTCHARS.)

Typematic defines a specialized static text control CStaticAbbrev that both displays the abbreviations and reads the accelerator key. Figure 3 shows the source. When the user presses the hotkey, Typematic wakes up and sets focus to this CStaticAbbrev control, which waits for a character. When CStaticAbbrev::OnChar gets a key that matches one of the abbreviations in the table, it hides the dialog, then calls a helper function SendString to send the text:

// in CStaticAbbrev::OnChar if (/* find char in ABBREV table */) { GetParent()->ShowWindow(SW_HIDE); // hide dialog SendString(abbrev.text); // send text }

Figure 3 typematic.cpp

#include "stdafx.h" ... const HOTKEY = 'T'; // <WinKey>+T is hotkey to activate static void SendString(LPCTSTR str); class CStaticAbbrev : public CStatic { protected: afx_msg UINT OnGetDlgCode() { return DLGC_WANTCHARS; // I want all chars } afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); DECLARE_MESSAGE_MAP() }; class CMyDialog : public CDialog { public: CMyDialog(CWnd* pParent = NULL); ~CMyDialog(); protected: ... CStatic m_wndHelp; // help message CButton m_wndOK; // OK/Exit button CStaticAbbrev m_wndKeys;// static text to display/receive abbreviations UINT m_nIDHotKey; // hot key identifier BOOL m_bFirstTime; // first time activated? afx_msg LRESULT OnHotKey(WPARAM wp, LPARAM lp); DECLARE_MESSAGE_MAP() }; struct ABBREV { TCHAR key; LPCTSTR text; } MYABBREVS[] = { { _T('n'),_T("Elmer Fudd") }, // name { _T('a'),_T("1 Bunny Way") }, // addr { _T('c'),_T("Redmond") }, // city { _T('p'),_T("206 555 1212") }, // phone { 0,NULL}, }; BEGIN_MESSAGE_MAP(CStaticAbbrev, CStatic) ON_WM_GETDLGCODE() ON_WM_CHAR() END_MESSAGE_MAP() void CStaticAbbrev::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { for (int i=0; MYABBREVS[i].key; i++) { if (nChar==MYABBREVS[i].key) { // found: GetParent()->ShowWindow(SW_HIDE); // ..hide dialog SendString(MYABBREVS[i].text); // ..and send text return; } } MessageBeep(0); } LRESULT CMyDialog::OnHotKey(WPARAM wp, LPARAM lp) { if (wp==m_nIDHotKey && !IsWindowVisible()) { if (m_bFirstTime) { // first activation: replace initial message with abbrevs list CString text; for (int i=0; MYABBREVS[i].key; i++) { CString temp; temp.Format(_T("%c = %s\n"), MYABBREVS[i].key, MYABBREVS[i].text); text += temp; } m_wndKeys.SetWindowText(text); m_wndHelp.SetWindowText( _T("Type one of the keys below to enter text.")); m_wndOK.SetWindowText(_T("E&xit")); m_bFirstTime = FALSE; } ShowWindow(SW_NORMAL); // activate myself m_wndKeys.SetFocus(); // set focus to abbrev control } return 0; } static void SendString(LPCTSTR str) { INPUT inp[2]; memset(inp,0,sizeof(INPUT)); inp[0].type = INPUT_KEYBOARD; inp[0].ki.dwFlags = KEYEVENTF_UNICODE; // to avoid shift, and so on inp[1] = inp[0]; inp[1].ki.dwFlags |= KEYEVENTF_KEYUP; for (LPCTSTR p=str; *p; p++) { inp[0].ki.wScan = inp[1].ki.wScan = *p; SendInput(2, inp, sizeof(INPUT)); } }

When Typematic hides itself, Windows® automatically restores the focus to whichever window previously had it, so the input goes to whichever window the user was working in before she pressed the hotkey. Pretty clever, eh? If you need to direct input to a specific application or window, make sure it's active before calling SendInput. SetForegroundWindow is the function to call.

All the work of sending the keystrokes happens in SendString, which builds the INPUT array and calls SendInput (see Figure 3). SendString sends a sequence of KEYDOWN/KEYUP pairs of INPUT structures, one pair for each character in the string. It uses the KEYEVENTF_UNICODE flag to send the string as Unicode characters. Unicode makes life easy because you don't have to synthesize capital letters using the Shift key. Without KEYEVENTF_ UNICODE, you'd have to send capital E as <Shift> followed by e, with down/up events for each, for a total of four keystrokes. Thank the Redmondtonians for adding KEYEVENTF_UNICODE!

If you're programming with Managed C++ or some other Microsoft® .NET-compliant language, sending keystrokes is even easier. There's a Framework class, SendKeys, with a static function Send that makes sending keys as easy as pie. You can even send special keys using squiggle syntax. For example "{F1}{BACKSPACE}A" sends F1, Backspace, A. Just for fun, I wrote another version of Typematic, Typematic.NET, that uses SendKeys. Now the SendString function is trivial:

#pragma managed void SendString(LPCTSTR str) { SendKeys::SendWait(str); }

What could be easier? When I first attempted this, I naturally tried SendKeys::Send, not SendWait. Why should I wait for the app to finish eating its keys? Alas, when I tried it, Typematic crashed miserably with System.InvalidOperationException somewhere in Windows.Forms.dll. When I invoked the common language runtime (CLR) Debugger to see what the heck happened, the Output window displayed the following message: "Additional information: SendKeys cannot run inside this application because the application is not handling Windows messages. Either change the application to handle messages, or use the SendKeys.SendWait method." Now that's what I call a friendly error message! Let this be an example to you all. But before you run off to use SendKeys, be advised that it's not as reliable as SendInput. You can discover this yourself by testing Typematic and Typematic.NET against different apps like Microsoft Internet Explorer, Notepad, an MFC form view, or some other favorite app. For some reason, SendKeys doesn't always work. I suspect it's a focus or timing problem—the keys are sent but then vanish into the ether because the window you think has the focus doesn't actually have it yet. So while SendKeys is easier to use and more powerful than SendInput, it doesn't work perfectly in all situations. Sigh. Maybe the Redmondtonians will fix it in the next release.

One final warning: sending keystrokes is a notoriously flaky way to control another app. You have to get all the keys exactly right, and the slightest change in context or user interface can throw everything off. If you're trying to control another app, look for a scripting system, programming interface, or macro language.

Q I've read several articles on how to disable system key sequences like Ctrl+Alt+Del, including one of yours in the September 2002 issue of MSDN®Magazine. But, how can I programmatically send Ctrl+Alt+Del?

Q I've read several articles on how to disable system key sequences like Ctrl+Alt+Del, including one of yours in the September 2002 issue of MSDN®Magazine. But, how can I programmatically send Ctrl+Alt+Del?

William Burns

A The first question shows how to send keystrokes to any app, but you can't send Ctrl+Alt+Del using SendInput because this sequence is handled at a lower level in the operating system. Synthesizing keystrokes is not the proper way to "send" Ctrl+Alt+Del, anyway. What are you trying to do? If you want to invoke the task manager, call ShellExecute with "taskmgr.exe". If you're trying to reboot, you can call ExitWindowsEx with the EWX_REBOOT flag. ExitWindowsEx has all sorts of flags for shutting down or restarting the machine in different ways (see Figure 4). Also, your app needs the SE_SHUTDOWN_NAME privilege to reboot.

A The first question shows how to send keystrokes to any app, but you can't send Ctrl+Alt+Del using SendInput because this sequence is handled at a lower level in the operating system. Synthesizing keystrokes is not the proper way to "send" Ctrl+Alt+Del, anyway. What are you trying to do? If you want to invoke the task manager, call ShellExecute with "taskmgr.exe". If you're trying to reboot, you can call ExitWindowsEx with the EWX_REBOOT flag. ExitWindowsEx has all sorts of flags for shutting down or restarting the machine in different ways (see Figure 4). Also, your app needs the SE_SHUTDOWN_NAME privilege to reboot.

Figure 4 ExitWindowsEx Flags

Shutdown Type Description
EWX_LOGOFF Shuts down all processes, then logs the user off
EWX_POWEROFF Shuts down the system and turns off the power
EWX_REBOOT Restarts the system
EWX_SHUTDOWN Performs shutdown so it's safe to turn off the power
Modifiers Description
EWX_FORCE Force-terminates processes without sending WM_QUERYENDSESSION/WM_ENDSESSION
EWX_FORCEIFHUNG Force-terminates processes if they don't respond to WM_QUERYENDSESSION/WM_ENDSESSION

Does anyone know the origin of Ctrl+Alt+Del? If you think you know, send me e-mail. I'll tell you the answer in a future column.

Q Can I call the .NET Framework from my MFC app? I want to call a managed class from my unmanaged MFC code, and I tried to do it by #using <mscorlib.dll>, but I got a message "/RTC1 incompatible with /clr." How can I call .NET from my MFC app?

Q Can I call the .NET Framework from my MFC app? I want to call a managed class from my unmanaged MFC code, and I tried to do it by #using <mscorlib.dll>, but I got a message "/RTC1 incompatible with /clr." How can I call .NET from my MFC app?

Julian Kinsey

A Of course you can call .NET from your MFC app! Like everything else in Windows, it's easy once you know the correct voodoo. When you first create an MFC app, the App Wizard sets up all sorts of compiler options for you. One of the options under C/C++ Code Generation is "Basic Runtime Checks". When you create an MFC app, the App Wizard chooses "Both (/RTC1, equiv. to /RTCsu)" in your debug build to perform runtime checks like checking for bad stack frames, uninitialized variables, or buffer overruns and underruns. These checks are incompatible with /clr because managed code is totally different (it's Microsoft intermediate language, not native), but when you add /clr, the IDE doesn't automatically remove /RTC1. So you have to do it manually.

A Of course you can call .NET from your MFC app! Like everything else in Windows, it's easy once you know the correct voodoo. When you first create an MFC app, the App Wizard sets up all sorts of compiler options for you. One of the options under C/C++ Code Generation is "Basic Runtime Checks". When you create an MFC app, the App Wizard chooses "Both (/RTC1, equiv. to /RTCsu)" in your debug build to perform runtime checks like checking for bad stack frames, uninitialized variables, or buffer overruns and underruns. These checks are incompatible with /clr because managed code is totally different (it's Microsoft intermediate language, not native), but when you add /clr, the IDE doesn't automatically remove /RTC1. So you have to do it manually.

For each .cpp file in your project, set Basic Runtime Checks to Default. This is rather unfortunate, since for native/unmanaged functions, the checks are a good thing. They help you find bugs in your program before you ship. It's a shame to throw out the checks just because you want to call a .NET class or two. Isn't there some way to have your .NET and runtime checks, too?

The problem is that to use Managed Extensions to call the Framework, you have to set Use Managed Extensions to Yes, which sets /clr, and the only place you can do it is in the project settings, which are global. Use Managed Extensions turns /clr on for all modules in your project. By default, all your functions are now managed. If you prefer to make native mode the default, you can add a line at the end of your stdafx.h:

#pragma unmanaged

Since every module includes stdafx.h, now all your modules compile in native mode the way they always did. When it's time to call the Framework, you can flip to managed mode like so:

#pragma managed void DoSomethingWithDotNET(...) { // call framework classes here // safe from managed functions }

Until now, I've always used this trick (of putting #pragma unmanaged at the end of stdafx.h). But it doesn't solve the runtime-check problem because /clr is still incompatible with /RTC even if most of your functions are native. In mixed-mode apps the compiler doesn't let you say "do the runtime checks in native functions where they make sense."

Figure 5 Project Settings

Figure 5** Project Settings **

What you really want to do is compile with /clr only the modules that actually call the Framework. But how can you do that, when Use Managed Extensions appears in the project-wide settings? Easy: you can always add specific switches in the Command Line section of the module's build properties. Figure 5 and Figure 6 show how to set this up. In your global project settings, set Use Managed Extensions to No, then add /clr to each module that calls the Framework. Now all the other modules can still use /RTC1 and get all the runtime checking goodies. Of course, now you have to move <mscorlib.dll> and all the other Framework files from stdafx.h to the managed modules. If you like, you can put all the standard .NET includes in one file UsesDotNet.h that looks something like this:

#using <mscorlib.dll> #using <System.dll> #include <vcclr.h> using namespace System;

Figure 6 Module Settings

Figure 6** Module Settings **

Then just #include "UsesDotNet.h" in each module that calls the Framework. You can still use #pragma managed/unmanaged to mix managed and native code within a module.

There's one more catch. When you add /clr to one of your modules, you also have to select "Not Using Precompiled Headers" in addition to turning off the runtime checks. Precompiled header information only works when all the modules have the same compile options; if one module has /clr, it can't use the same precompiled header as other modules that don't. Hey, computers are so fast these days, who needs precompiled headers anyway? If you want to get really fancy, you can always compile your managed modules through a different header file like UsesDotNet.h.

For a real, live, working project that uses the approach I've described, take a look at the Typematic.NET application from the first question in this column. You can download it from the MSDN Magazine Web site. All of the modules in Typematic.NET are compiled the normal native way, using precompiled headers through stdafx.h and no Managed Extensions. The only function that calls the .NET Framework, SendString, lives by itself in its quiet lonesome module SendString.cpp, which gets the managed compilation treatment with /clr, no runtime checks, and no precompiled headers. Enjoy!

Send your questions and comments for Paul to  cppqa@microsoft.com.

Paul DiLascia is a freelance writer, consultant, and Web/UI designer-at-large. He is the author of Windows++: Writing Reusable Windows Code in C++ (Addison-Wesley, 1992). Paul can be reached at www.dilascia.com.