Vista Thumbnailer

I’ve been crazy busy the last few weeks, but I’ve been really rather distracted from my main project and it’s past time I got back to it. To really feel like I’ve moved on, I need to write a bunch of articles here and publish a couple of cool apps and some source code so that I can feel like I’ve reached a release point. What I’ve been playing with in all this coding is the new technology that’s been coming out of Microsoft in the last couple months: PowerShell, .NET 3 and WPF, and Windows Vista so you may or may not actually be able to use these apps …

The Vista Thumbnailer is a really slick little app that shows off some of what Vista can do … and some of what WPF can do. I’ll write more about it in the morning, because there’s some interesting things I learned in the coding of it, but in the meantime, you can download Vista Thumbnailer (7-Zip file with a config file). The only thing you really need to know is that there’s a hotkey: Win+X which will bring Thumbnailer back to the foreground even if it’s minimized in the tray. I’ll make the hotkey configurable in version 2, but for now you’re stuck with Win+X. The rest you can figure out from the screenshots (0 1 2) and by reading the tooltips on the buttons.

Play around. Let me know what you think.

(Oh, source code is here with your usual choice of BSD/Ms-PL/GPL)

[New] Edit: Continuing

So … I’ve had a lot of questions about this app during it’s development (from a few friends in our IRC channel) so it’s clear that I should try to at least give the highlights of how it works.

Thumbnails

By now you’ve probably seen more than your fill of screenshots of Windows Vista’s semi-transparent windows, and maybe you’ve had a chance to try Vista and seen these live-updating thumbnails on the Alt+Tab window, the Flip3D Win+Tab task switcher, and even the task-bar’s mouse-over (or Win+T) popups. All of this is possible because of the way Windows does desktop compositing using a new Desktop Window Manager. This DWM is actually a process which runs all the time when you have the “Aero” interface turned on, but it’s also an API exposed through dwmapi.dll … and one of the deepest fundamental changes to the way Windows work in Vista. Let me quote from “one of the developers” blogs:

... The way an application gets pixels on the screen has fundamentally changed. [In the past] applications were asked by Windows to paint their visible region, and they would paint directly to the buffer that was to be displayed by the video card. With Windows Vista, applications are asked by Windows to paint their entire surface to an offscreen surface (alternatively known as a bitmap, buffer, or texture), and it’s up to the DWM to take all of these offscreen surfaces, and “compose” them together to the onscreen buffer.

Because the windows are rendered “offscreen” and without regard to what part of the window might actually be visible … the visual representation can be reused in many places very cheaply — that is, since the visual representation is just a cached picture, there’s very little CPU cost involved in repainting it in many places … and the caching and repainting are easily handled by the DWM. Now, the DWM also does lots of other cool things, like using DirectX and hardware accelleration to do all this extra rendering of these cached surfaces, but despite appearances, this isn’t really an article about the DWM — we’re here to talk about JUST the thumbnails. Greg Schechter again:

Thumbnails in the DWM are not static snapshots of a window. They’re dynamic, constant connections between a thumbnail source window, and a place on a target window that that source window will get a “thumbnail rendering”.

Basically, the APIs in the Desktop Window Manager allow you to ask for a certain portion of one Window’s screen to be painted over (at some specified level of opacity) with all or part of the contents of another Window’s screen. In every sense, the thumbnail is just as live and up-to-date as the actual window (since it is, in fact, being painted by the same process).

So anyway, what I did is I took a “Thumbnail” class from Douglas Stockwell and enhanced it a bit … it’s still not quite perfect, but it’s trivially easy to use now: just pass it a Window handle and it hooks itself up and renders within it’s available bounds — mostly.

Glass Effect

The Vista Thumbnailer app also showcases a couple of other slick API features. First, I added a couple of simple wrappers to DwmExtendFrameIntoClientArea and DwmIsCompositionEnabled so that you can easily get the translucent “glass” effect on your whole window, or write, for instance: if( !NativeMethods.IsCompositionEnabled ) { MessageBox.Show( "Sorry you can't use this feature!" ); }

Hotkeys

I also wrote a global hotkey manager class which can be easily added to WPF applications that want to register global hotkeys. VistaThumbnailer only has one, to focus it (you can change it by editing the .config file).

These are global hotkeys, not like the “Ctrl+O” for opening a file, but like the Win+R to bring up a run dialog. They’re registered through Window’s RegisterHotkey and UnregisterHotkey APIs, and you get notified of them via window messages (but my HotkeyManager class will handle the WM_HOTKEY message for you). Here’s the short-form for how to use them (you can grab the source if you’d like to borrow the class, but I’ll be re-releasing this in a few days with some enhancements I’ll detail below).

using GeoCore.Win32;

public class Window1 : System.Windows.Window {
   private WPFHotkeyManager hkManager;
   // You need to keep a reference to the hotkey around
   // Otherwise you won't know *which* hotkey was pressed!
   private Hotkey focusHotkey;  

   public Window1() {
      // ... somewhere ... hook SourceInitialized (you can do it in the XAML)
      SourceInitialized +=new EventHandler(Window1_SourceInitialized);
   }
   
   void Window_SourceInitialized(object sender, EventArgs e)
   {
      // make the whole window glassy, preserving the border
      NativeMethods.TryExtendFrameIntoClientArea(this, BorderThickness);

      // create the hotkey manager in "SourceInitialized" because
      // it doesn't accept hotkeys anyway until the window is Initialized
      // -- this is because it needs a window handle.
      hkManager = new WPFHotkeyManager(this);
      // register for the hotkey event, otherwise ... nothing happens.
      hkManager.HotkeyPressed += new WPFHotkeyManager.HotkeyPressedEvent(Hotkey_Pressed);
      // create a hotkey -- remember, this is global (and be careful of the types here)
      focusKey = new Hotkey(ModifierKeys.Win, Keys.X);
      // register the hotkey
      hkManager.Register(FocusKey);
   }


   void Hotkey_Pressed(System.Windows.Window window, Hotkey hotkey)
   {
      // an action for each hotkey ....
      if (hotkey.Equals(FocusKey))
      {
         Show(); Activate();
      }
   }
}

I want you to notice that I had to create my own Keys enumeration in this, because the WPF developers unbelievably chose to use an ordering for their Key enumeration which is inconsistent with the Windows API ordering. You could use the System.Windows.Forms enumeration, but that would require adding a reference to the Forms assembly in your WPF application just to get a silly enum! I have to say that this seems to be absolutely the WORST design decision I’ve seen in the .NET Framework — not only are they duplicating enumerations which exist elsewhere, but they couldn’t even copy-and-paste it in order?

Chrome Free Windows!

I thought I’d mention this, just in case you haven’t seen it before. Irregular shaped windows are trivially easy to do in WPF. All you have to do is add the following attributes to your Window tag: WindowStyle=“None” AllowsTransparency=“True” Background=“Transparent”

Further Development

DWM API Thumbnails

There are still a few tweaks that need to be made to the Thumbnail Image control. It doesn’t adjust when the source window is changed until you resize the window (because it doesn’t check the size except when WPF asks it to) and I’m not sure if it’s possible apart from re-checking the source window shape on a timer. I’m a little afraid that I’m leaking the thumbnail window so I need to wrap them in a Safe Handle, and override OnUnloaded to clean up.

I’m also curious if there’s a way, in the DWM api, to get these thumbnails batched into a video or saved to an image handle so you can use them for screenshots … I’ll have to take some additional time to research that.

Hotkeys

There’s also some changes I want to make to the way my hotkeys class works. Right now you have to hang on to your Hotkey objects in order to be able to process the hotkey events correctly (unless you only have a single Hotkey) ... and it’s not possible to use a switch statement on the event, so if you have a lot of hotkeys, it gets a bit ridiculous. I initially did this because I didn’t like trusting the user to come up with unique Hotkey Id’s, but now I’m thinking that it might be better if you could use just the Ids and create yourself an enumeration for them. I need to play with this, because one of my key use scenarios is having windowless plugins be able to register and process their own hotkeys — which makes enums not completely safe, because different pieces of code are dynamically creating hotkeys.

I also don’t like not being able to register the hotkeys during construction. My first attempt to fix that is a version of this HotkeyManager (which I’ll release shortly) that creates it’s own window — this means you don’t have to worry about calling it in SourceInitialized, but it’s a pretty expensive fix if you’ve already got a window. I’m going to try doing it another way — where hotkeys registered before the handle is initialized will be queued for registration later, and this should be a better solution in most cases. I do have a System.Windows.Forms version (which I will release with all the other versions) that doesn’t have this problem (because with Windows.Forms you get a window handle on construction), but again, I don’t like including that whole assembly for something fairly trivial.

Hopefully I’m going to get better at these writeups as time goes on, because I feel like this one is a bit rambling. Questions and comments are welcome!

Similar Posts:

    None Found

6 thoughts on “Vista Thumbnailer”

  1. Hi, I’ve been playing with DWM today, succesfully rendering live thumbnails of open applications. However, I’ve found no way or documentation about getting access to a buffer to take a screenshot of the thumbnails.

    Have you had any success doing so? I noticed there are a few undocumented calls in the dwmapi.dll but they don’t seem related about giving access to any frame buffer.

  2. Hello,
    I was searching for a long time for something like this… very cool hack! I was wondering if you made or plan to make any further progress on the “version 2” that you mentioned above, with the configurable hotkey etc. I downloaded the sourcecode but honestly I am not sure what to do with it. :( I wish I could take time off from my job to learn to code but alas, between the girlfriend and the job I barely have time to eat, sleep, and sh*t these days :(

Comments are closed.