Yesterday I mentioned WM_PRINTCLIENT and how awesome it is when trying to strictly control the drawing of your application.
Part of the reason it took over a week to change the drawing model is that there are a number of serious gotcha’s associated with using WM_PRINTCLIENT and controlling your own drawing story. The first is that not all controls support WM_PRINTCLIENT. It turns out that some controls don’t support the WM_PRINTCLIENT, however if you search the documentation for WM_PAINT, you’ll find the following comment:
“For some common controls, the default WM_PAINT message processing checks the wParam parameter. If wParam is non-NULL, the control assumes that the value is an HDC and paints using that device context.”
That means that if you find a common control that doesn’t support WM_PRINTCLIENT, you can use WM_PAINT specifying wParam as the HDC. Fortunately I didn’t run into this in my control.
The next gotcha is that some controls (like buttons and toolbars etc) have animations that are launched when you mouse over the control. These are often subtle (like the glow when you hover over a scrollbar thumb). In order to continue to have these effects work, you need to let those controls paint themselves – in my experience it generally didn’t cause much of a problem with flickering, but your mileage might vary.
The last gotcha is a very big one and hung me up for about half a day. The WM_PRINTCLIENT message only paints the client area of a window. If you have a window with the WM_HSCROLL or WM_VSCROLL style then you won’t be able to paint the scroll bar. Instead you need to create your own scrollbar control (with CreateWindow) and use that instead of the built-in scroll styles. There are ways you can convince the window to paint it’s non client region to an HDC but they are fraught with peril (one senior developer I was talking to about this problem described them as “unnatural acts”) and simply not worth the effort.
 There’s also a corollary to that: If you ever send a WM_PAINT to a control you MUST ensure that wParam and lParam are 0 even though they’re documented as “not used”.