charlie's blog

Sunday, February 9, 2014

how do I write an Alt+Tab replacement program?

Over the years I've done several Alt+Tab replacement projects, and recently I started a new one. Unfortunately I found that the techniques which worked under Windows XP do not work under Windows 7 (and presumably not under Windows 8 either). I did eventually get it to work, and created this page to document what was required.

Here are the essential ingredients for an Alt+Tab replacement (a "switcher") under Windows 7:

#1: Capture Alt+Tab

Under Windows XP this was easy, you would just use RegisterHotKey and override the default handling of Alt+Tab. Unfortunately this does not work under Windows 7*. Instead, the best option I found was to set a Windows hook using SetWindowsHookEx, specifically a low-level keyboard hook (WH_KEYBOARD_LL). From here you can detect the Alt+Tab key combination and invoke whatever UI you want.

* Actually, it might work once you enable uiAccess (see below). I never tried it again after switching to Windows hooks.

#2: Enumerate windows

A switcher needs to know which applications it's switching between. There are a few ways to do this, and it's not particularly complicated. Two options are EnumWindows and the UI Accessibility framework (see System.Windows.Automation). The latter has more functionality but can be less performant if you're not careful.

As a side note, you can also use the UI Accessibility framework to determine the order of buttons in the Windows task bar, which might be useful depending on what behavior you want in your switcher. I did this by finding the Explorer process and searching its windows for one with a ClassNameProperty of "MSTaskListWClass". The child windows of this window seem to be the taskbar buttons. There might be cleaner ways to do this, though, and no doubt this is subject to breakage in future releases of Windows.

#3: Actually switch apps

Once the user picks an app to switch to, your switcher needs to actually perform the switch. This is the part that gives people the most trouble, and the one I fought with the longest. I tried SetForegroundWindow (unreliable), SwitchToThisWindow (also unreliable), AttachThreadInput (unreliable and probably a bad idea), and no doubt some other things I already forgot about. These do not work due to deliberate (and good) security limitations in Windows.

What does work is to set uiAccess to true in your application manifest (see this MSDN overview). You do not need to change requestedExecutionLevel (the app does not need to run with elevation), you just need uiAccess="true". In order for uiAccess to work, you will need to sign your executable (self-signing is a good option for initial development) and install it in Program Files. If you fail to do either of those things, your app will not be able to launch.

Once you enable uiAccess, your switcher will be ready to go. I ended up settling on SwitchToThisWindow for the switching, but I think SetForegroundWindow would probably work as well. For debugging, usually I just temporarily change uiAccess to false and live with the fact that some switches will fail due to security limitations.

Conclusion

That's it! Hopefully this will be useful to other developers; figuring this out (particularly item 3) was a long and frustrating process, and hopefully this can save people some pain.

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]