Gotchas associated with using WM_PRINTCLIENT…

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”.

Comments (22)

  1. Anonymous says:

    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.

  2. Anonymous says:

    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?

  3. 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.

  4. Anonymous says:

    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.

  5. 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).

  6. Anonymous says:

    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).

  7. 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.

  8. Anonymous says:

    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.

  9. Anonymous says:

    Why didn’t the PRF_NONCLIENT flag work to draw the scrollbars?

  10. 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.

  11. Anonymous says:

    "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.)

  12. 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 :)).

  13. Anonymous says:

    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.

  14. 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.

  15. Joop: Btw, some of the things being complained about aren’t actually bugs – they’re quite intentional based on history and target audience of the feature.

  16. Anonymous says:

    I’ve never understood why Microsoft don’t have the resources to actually fix some of these bugs. Our company has 2 programmers working for it, and we fix more bugs in our software every week then it seems Microsoft fix in the whole life cycle of a product. Sure, it’s good to prioritize, but it seems like Microsoft only have two priority levels – "FIX" and "WON’T FIX".

  17. jon, I suspect that your company’s product is slightly less complicated than Windows.

    It’s all about trade-offs.  For instance, we could spend 6 months rewriting the sounds control panel to make the chrome look more like other control panels OR we could spend 6 months adding new features that customers have been clamoring for.

    It’s my belief that customers would rather have more functionality than new chrome.  Customers tend to get annoyed by new chrome.  We certainly know that when we roll out new chrome, people complain that "it all changed".

  18. Anonymous says:

    But Larry, we’re not talking about changing the colors or redesigning the control panel to look prettier. We’re talking about fixing existing, well known, long established bugs in the existing features. Windows may be a lot more complicated overall, but the individual parts aren’t necessarily anything special. Fixing a bug in one of the common controls doesn’t require a year of planning, just someone to sit down and fix it. Not to mention that Microsoft has vastly more resources than most companies do. They SHOULD be able to fix this stuff, but they just don’t seem to care.

    It’s interesting that you use the argument that "customers would rather have more functionality than new chrome". I think most customers would rather have the existing functionality working properly. And as an aside, if you ask most people to name the biggest new feature in Vista, what would they come up with – glass, perhaps? Hardly "functionality" is it?

  19. jon: But those fixing those existing, well known, long established bugs often involve significant amounts of work.

    The development teams are limited – for instance there are less than a dozen developers on the sound team, and only 2 of them have the skills to work on UI – most of them work on the low level plumbing.  Those two developers can either (a) be assigned to work on UI for new features or (b) be assigned to rewrite existing UI without adding new functionality.  You can’t have both.  And if you don’t have UI to expose the new features, you might as well not bother to implement those new features.  

    It’s a hard choice to make, but typically implementing new features trump rewriting existing features.

    As I said: We don’t get a lot of customer complants when our control panel applet doesn’t follow the style of the other control panel applets (really, we don’t).  But we DO get complaints about other stuff.

  20. Anonymous says:

    You keep talking about the sound control panel applet but I’m talking more generally about the attitude of Microsoft overall to fixing bugs.

    I think the problem is that there’s often "follow through" from Microsoft on their products in terms of bug fixes. Once a product has shipped everyone focuses on the next version. Most other companies produce software and then follow it up with bug fixes, but at Microsoft it seems like once a product is out the door that’s it. If you’re lucky the bug fixes might make it into the next major version (for which you have to pay) but more often than not the bugs just sit there forever.

    Obviously this isn’t always the case – security bugs are different, and obviously there’s been a strong direction set by management that security issues are taken seriously and will be fixed. It’s just a pity that this attitude isn’t applied to all bugs.

  21. jon: I’m talking about the sound control panel because it’s what I know. I don’t know about the other teams.  I DO know that the Windows team is typically resource constrained.  

    Microsoft DOES follow through with bug fixes.  But most of those bug fixes aren’t for cosmetic issues, but instead are focused on those problems that have been reported by our customers.  As I’ve said three or four times now, customers don’t complain about cosmetic issues, they complain about the things that prevent them from getting their work done.  That means that cosmetic issues typically wait for major releases.

Skip to main content