All Your Base Are Belong To Us

March 20, 2009

In the previous post, we have only scratched the surface of how to provide a custom thumbnail and custom preview for an application’s window. However, we focused on top-level windows in that post – these are the windows that DWM (Desktop Window Manager) recognizes, loves and converses with. But what about child windows in an MDI application? What about individual tab windows in a TDI application, like Internet Explorer?

This is a completely different story, with a significantly steeper barrier of entry. The reason is that the DWM won’t talk to child windows no matter what we do. This means that for each tab window, we have to create a top-level invisible (or off-screen) proxy window that we can register with our application’s taskbar button. This proxy window will delegate the DWM messages for providing a thumbnail and a live preview to the real child window, making this whole act transparent to the user.

Implementing something like this in native code is not trivial, and mainly revolves around handling all the different window messages in your proxy window’s window procedure. Specifically, you would need to handle the following messages:

Fortunately, this work is handled for you by the CustomWindowsManager class that we’ve seen in the previous episode (part of the Windows7.DesktopIntegration project in the managed wrapper). The wrapper automatically creates a proxy window on your behalf and hooks up all the window messages so that your application behaves seamlessly. All you need to do is provide the thumbnail and live preview (or rely on the partial support for automatically rendering a screenshot of the window*).

This simple web browser has support for multiple tabs, each of which is registered as an individual taskbar thumbnail, with full live preview support. (See * below for an explanation of why there are sometimes glitches in the rendered image – mainly because there’s no way to grab the screen data from a tab that is not currently visible.)

How is this done? Well, for each new tab, we create a CustomWindowsManager instance and pass to it the tab’s window handle as well as the parent form’s window handle. This automatically causes the CustomWindowsManager to create a proxy window for our tab, and hook up all the events required. All we need to do now is provide the actual thumbnail bitmap and live preview bitmap, which are stored when the tab is rendered. (Note that in this scenario, there’s no need to call DispatchMessage from your form’s window procedure because the CustomWindowsManager does it automatically in the proxy window’s window procedure.)

Here’s the code that executes when a new tab is added to the simple web browser:

Not much at all here other than the actual logic that provides the thumbnail and live preview – which is of course the application’s task. There are quite a few other interesting things around the CustomWindowsManager class which I encourage you to investigate on your own.

* I’m saying “partial support” here because it’s fairly difficult to automatically obtain a screenshot of a child window accurately. Moreover, it might be the case that the child window is not even drawn until it is selected – in which case there is no screenshot that could possibly be obtained! In these cases, it is up to your application to use its internal rendering logic in both scenarios – when a thumbnail/live preview is needed, and of course when the window is actually shown.