Posts Tagged ‘Aero Peek’

postheadericon Fun with PInvoke and Aero Peek

There are so many fun things you can do in Windows when your scripting language allows you to make PInvoke calls to Win32 APIs … but I have to say it’s amazing how many things have been added to Windows recently and still left out of the .Net framework …

Anyway, on to the Aero Peek stuff. If you haven’t seen it, Aero Peek is a feature of Windows 7, which lets you get a peek at your desktop, or at a single window for a moment. Basically, you can press Win+Space (the Windows logo key and the space bar) and all of your open windows instantly turn transparent, revealing … whatever was on your desktop: wallpaper, icons, and gadgets. You can also use it by hovering your mouse on the right corner of the taskbar, or you can peek at a single window by hovering over it’s taskbar button and then over it’s thumbnail.

In any case, I have a couple of windows which I would like to have stay visible on the desktop when I hit the aero peek hotkey: Rainlendar and Miranda. It turns out there’s a simple API call for this: DwmSetWindowAttribute which lets you set the DWMWA_EXCLUDED_FROM_PEEK attribute to ENABLED … causing a window to no longer hide when you press that hotkey. Of course, that API call should be made by those apps, in response to a user setting (so I’ve told their authors about it), but it doesn’t have to be (so I wrote a script to do it myself).

In the old days, I would have written a little systray app which would give you a popup list of all windows, or perhaps added a menu item to a window’s right-click menu … and I would have had to deal with creating some way to persist which apps you wanted to apply this to, and then I could have applied the setting to them whenever you opened them.

But now, I have PowerShell. I don’t need to give you menus and store settings, because I can just let you edit a little script instead.

So here’s a script which will let you turn off Aero Peek transparency for windows by window title and/or process name … Once you have this function available, you can keep Rainlendar’s calendar, tasks, and event windows all visible by just running Remove-AeroPeek -Process Rainlendar2 or you can keep your Miranda contact list visible by running Remove-AeroPeek "Miranda IM" (although you should not that depends on the window title matching just that one window — and Miranda lets you change what your title is, so you may have to adjust it).

Of course, that script really deserves explanation, because it’s showing off quite a few advanced things…

The first thing is that I’m using a Try/Catch block in the BEGIN block to make sure I only execute that code once. You can’t call Add-Type with the same code multiple times in a single PowerShell session, because the type will already exist when you call it the second time. So the code in the try block will throw an exception if the type doesn’t already exist, and in the catch handler, we’ll create the type, and define the other function we need.

Add-Type is a super-powerful cmdlet which compiles code on the fly (or imports types from pre-compiled assemblies). In this case we’re using it to import a little class called Dwm which I started writing myself from PInvoke.net and the MSDN documentation, but then eventually copied most of from a NeoWin forum thread… All this class really does is define the API function and the flags we need to pass to it, and then provides a wrapper for the DwmSetWindowAttribute call. We could have written that call in PowerShell, but at the end of the day, once you start compiling C# code in PowerShell, it’s hard to know when to stop ;)

The Select-Window function is (yet another customized version of) a function I wrote awhile back on PoshCode as part of my (still in progress) rewrite of WASP to use the UIAutomationClient … I’ve just modified it to add only the three properties of the window that I’m interested in: Title and ProcessId (for identifying the correct windows) and Handle (for passing to the DwmSetWindowAttribute call). It uses the RootElement property of System.Windows.Automation.AutomationElement to do a search, and then a series of GetCurrentPropertyValue calls to determine the Name, ProcessId, and NativeWindowHandle of the windows it finds.

That’s pretty much all there is to it, other than filtering out the window(s) that we want and actually calling the API. I think I’m going to have to play a little bit more with this to see what else we can do — I’ve already realized that this means we can make little widgets with PowerBoots and set them to stick around just like regular desktop gadgets …

Reblog this post [with Zemanta]
Archives