Udostępnij za pośrednictwem


The common control library sometimes sends an NMCUSTOMDRAW message for the NM_CUSTOMDRAW notification.

I just fixed a bug in our UI that was caused by a misunderstanding of the API contract for the NM_CUSTOMDRAW handler for some of the common controls.

On of October 3rd, 2008 The common control documentation for the NM_CUSTOMDRAW message says:

lpNMCustomDraw
A pointer to a custom draw-related structure that contains information about the drawing operation. The following list specifies the controls and their associated structures. List view
NMLVCUSTOMDRAW ToolTip
NMTTCUSTOMDRAW Tree view
NMTVCUSTOMDRAW Toolbar
NMTBCUSTOMDRAW All other supported controls
NMCUSTOMDRAW

While this is correct in general it is NOT true for the CDDS_PREPAINT draw stage.  It turns out that some of the common controls only provide an NMCUSTOMDRAW structure when the drawing logic is in the CDDS_PREPAINT stage. 

If you look VERY carefully at MSDN, you can find this page which mentions that the first NM_CUSTOMDRAW notification receives an NMCUSTOMDRAW structure and not an NMLVCUSTOMDRAW handler but that’s the only page I was able to find to indicate this.

 

I’ve notified the relevant documentation folks about this and hopefully the documents will be updated in the future.  You can consider this blog post as a pre-update to the SDK documentation.

Comments

  • Anonymous
    October 03, 2008
    Is there a way for code to tell which type and version of the custom draw structures it has been passed? I've only used custom draw for some very simple stuff so I'm not very familiar with it -- and I'm a little ill & only just woke up so I could be in blind mode :-) -- but after a quick look I can't see any size/version members of NMHDR, NMCUSTOMDRAW or NMLVCUSTOMDRAW. It seems like code responding to custom draw messages has no way to sanity check what has been passed to it. Not just the type of structure but the version: NMLVCUSTOMDRAW can have several additional fields with later versions of the common controls. If there's no size/version field then that's inviting a read into random memory on earlier versions. Hmm, the existence of the extra fields in NMLVCUSTOMDRAW are controlled by the _WIN32_IE version. How can code know at runtime whether those members have been passed to it when the structure definitions are fixed at compile-time? Now I think I must be missing something as it can't be that bad. BTW, it looks like the sample code at the bottom of the referenced page has a mistake: case NM_CUSTOMDRAW:    LPNMLVCUSTOMDRAW  lplvcd = (LPNMLVCUSTOMDRAW)lParam; It's casting to LPNMLVCUSTOMDRAW regardless of painting stage. (The sample itself gets away with it since it never accesses the extra fields but it's bad for it to suggest the lParam is something it's not.)

  • Anonymous
    October 04, 2008
    I looked into my code for listview prepaint, and it also says: // lpNMCustomDraw->rc is not set correctly - bug documented in newsgroup Just wanted to add this here. Arno

  • Anonymous
    October 04, 2008
    Disregard my comment, it was w.r.t. the OnItemPrePaint message.

  • Anonymous
    October 04, 2008
    How can you even run into this? What member in the LV struct is useful in the prepaint stage? iSubItem?

  • Anonymous
    October 04, 2008
    It was the dwItemType - my code ignored the custom draw if the dwItemType field was set to LVCDI_GROUP.

  • Anonymous
    October 06, 2008
    ah, I have never used groups in the LV, XP+ only and all that...

  • Anonymous
    October 15, 2008
    The comment has been removed