Larry Osterman's WebLog

Confessions of an Old Fogey
Blog - Title

Gotchas associated with using WM_PRINTCLIENT…

Gotchas associated with using WM_PRINTCLIENT…

  • Comments 22

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[1].  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.




[1] 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”.

  • PingBack from

  • Useful info that should save people some time. I didn't realise that anything which didn't work with WM_PRINTCLIENT would work with WM_PAINT+HDC. Shame it isn't consistent (but it's too late now so whatever) but it's good to know that it's always possible one way or the other.

    On the subject of Vista's mouse-over animations and scrollbars, in case it helps anyone: There's a bug in the scrollbar control where it continues painting its fade-out animation over the top of your *client* area after the scrollbar is hidden. There's also an easy workaround (plus a simple demo app I wrote w/ source) here:

    You're unlikely to see it, since it's uncommon for a scrollbar to be turned off shortly after a mouse-over, but it can make your app look very bad if it happens.

    I found it while writing a viewer plugin that looks like this:

    In that state clicking the "play" button would (indirectly) cause the horiz scrollbar to hide and you'd naturally trigger the bug by moving the mouse past the scrollbar on the way to the toolbar below.

  • You seem to have made a leap there.  The docs say some controls let you specify an HDC in WM_PAINT.  You take this to mean "that if you find a common control that doesn’t support WM_PRINTCLIENT, you can use WM_PAINT specifying wParam as the HDC[1]."

    That seems to be overstating it.  A control that doesn't support WM_PRINTCLIENT *might* support the HDC param in WM_PAINT, but--then again--it might not.

    I'm still very curious why you have to jump through all these hoops.  What is so special about your dialog that requires this heroic effort and reliance on undocumented and thus unsupported behaviors?

  • Adrian, none of the stuff I'm doing is undocumented (at least as far as I know).  I think I should have rephrased the comment above to indicate that you could <i>try</i> wm_paint with the HDC in wParam to see if it works.

    And the issue here was a visual issue that annoyed the heck out of a number of people, including my boss.

  • If the visual issue is the black backgrounds around sliders in the Vista Volume Mixer (or the way they flicker when it's resized, but that doesn't bother me much) then that will make me quite happy, although I think it's poor if it's only going to be fixed in Win7 and not in Vista.

  • Leo: The primary issue was the flicker, but there are a number of other issues associated with the painting algorithm (sometimes the various elements would disappear from the dialog) that were more serious.  I believe that the black backgrounds were fixed earlier (I haven't seen them in a while).

    And there's no way that stuff like that gets fixed in Vista.  Vista shipped almost 2 years ago, so it's in maintenance mode.  That means that the ony stuff that gets fixed are serious problems that cause customers serious amount of grief.  Painting issues in a utility application don't come close to making the "serious amount of grief" bar.

    If there was a crash that had a couple of million hits from the online crash analysis, THAT would probably make the bar (and I fixed one of those in Vista SP1).

  • I guess I wasn't clear enough.

    I'm not suggesting that the flicker and painting problems in the original dialog aren't worth fixing.  What's am asking is, what is the root cause of the problem?  Why don't loads of other dialogs have this problem?

    There must be something very unusual about how the original dialog is implemented if there's are such horrific painting problems.  It makes me think there's a bug in that code rather than a fundamental problem in the Windows painting model that must be worked around with WM_PRINTCLIENT (which was invented for some very specific scenarios).

  • Adrian: The root cause is that sndvol has visual elements that cross multiple controls (the "flood mark").  To paint the flood mark correctly, it is drawn in WM_ERASEBKGND (otherwise it gets overwritten by the controls when they're drawn).  The same is true for a couple of the other visual elements in sndvol.  Everything else is fallout from that.

  • as stated, This WM_PAINT behavior is common control specific, and outside of the spec.

    That MSDN article should have capitalized Common Control, since most controls in the word in fact do not do this.  They all call BeginPaint and ignore the wparam and lparam.

    > 1] There’s also a corollary to that: If you ever send a WM_PAINT

    right but as you know applications are never supposed to send WM_PAINT, it's supposed only to be generated only as a side effect of invalidation. that's why there is the print client message.  I suspect there must be a few hack in vista to work around apps that didn't follow the semantics of update regions.  

    I think we've had a few problems as well; in larger apps there is often a junior programmer that never learned windows programming who will try to draw outside of the standard drawing method, or hack around something.

  • Why didn't the PRF_NONCLIENT flag work to draw the scrollbars?

  • Brian: I'm not sure.  It worked barely, but the results were bad.  Since I was trying something that really wasn't supposed to work, I gave up on it and manually created the scrollbar - it was amost no code change and worked quite nicely.

  • "Vista shipped almost 2 years ago, so it's in maintenance mode.  That means that the ony stuff that gets fixed are serious problems that cause customers serious amount of grief."

    Problem is, it seemed like Vista was in maintenance mode, with no chance of non-critical bugs ever being fixed, before the OS had even hit retail. That bug and many others were well known two years ago and I remember it being one of the first things I noticed when I installed the Vista RTM in early January 2007.

    I'm not blaming you, of course. It's just annoying that bugs like that never seem to get fixed even when the OS is brand new. They make the OS look bad and many of them force 3rd party developers to work around more and more bugs (e.g. in the common controls; not so much the volume mixer) with each Windows release. It seems that Windows releases only ever add bugs for us to discover and work around, never fix them.

    (Even if a Windows release does fix bugs we still have to support our users on older Windows versions that will never have the fixes released for them, so "if it's broken when it ships it's going to be broken forever" is a rather frustrating truth.)

  • And my boss has been complaining about the flicker for about the same amount of time.

    The bottom line is that visual bugs like this one get prioritized lower than bugs that involve things actually working correctly - in this case, sndvol works correctly, it just flickers.  Other bugs (like stuff crashes) get prioritized higher.

    And yeah, I work around bugs in the common controls all the time.  The horrible thing about the common controls is that their bugs live forever because people start to depend on the bugs (I've gotten to be friendly with several of the common control developers recently :)).

  • I'm not a professional developer, but when I read something like "create your own scrollbar control" I get the impression that this is the kind of stuff that *could* cause visual inconsistencies. There have been some complaints that the GUI in Vista is not consistent, any comments on this?

    See for an (extreme) example of the stuff I'm referring to.

    Offtopic; I've been reading your blog for a couple of years now, keep it up! :) It's very interesting, also for people who don't do development as their (primary) job, like me.

  • Joop, actually it doesn't.  I think you misunderstood what I meant - I meant creating a window in the "SCROLLBAR" window class, which is the same window class used for all other scrollbars in the system.

Page 1 of 2 (22 items) 12