0

当 NM_CUSTOMDRAW 通知代码通过 WM_NOTIFY 消息发送到控件的父级时,此 WM_NOTIFY 消息的 lParam 参数是 NMCUSTOMDRAW 结构的地址,如下所示:

http://msdn.microsoft.com/en-us/library/windows/desktop/ff919569(v=vs.85).aspx

另一方面,WM_NOTIFY 消息的 lParam 应该是

A pointer to an NMHDR structure that contains the notification code and additional
information. For some notification messages, this parameter points to a larger
structure that has the NMHDR structure as its first member.

在许多代码示例中,对于 WM_NOTIFY 消息的处理程序,我看到

LPNMLISTVIEW     pnm         =   (LPNMLISTVIEW)lParam;
    switch   (pnm->hdr.code){   .... 

但问题是,我们不知道这个 lParam 是一个 NMHDR 结构还是一个 NM_CUSTOMDRAW 结构,我们怎么能正确地转换 lParam?如果 lParam 只是一个 NMHDR,则应该使用 LPNMHDR 和 pnm->code,不是吗?

更糟糕的是,不同的控件使用不同类型的结构:NMLVCUSTOMDRAW、NMTVCUSTOMDRAW、NMLVCUTTOMDRAW 和 NMTBCUSTOMDRAW。那么在 WM_NOTIFY 处理程序开始时正确的做法是什么,区分它是否使用 NM_CUSTOMDRAW,并确定正确的 NMCUSTOMDRAW 结构类型。


当我读到这篇文章

http://msdn.microsoft.com/en-us/library/windows/desktop/ff919569%28v=vs.85%29.aspx

在 MSDN 上,我无法理解某些部分。例如,

CDRF_NOTIFYPOSTPAINT 当整个控件的绘制周期完成时,该控件将发送 NM_CUSTOMDRAW 通知。这发生在 dwDrawStage 等于 CDDS_PREPAINT 时。

当一个控件在整个控件的绘制周期完成时发送一个 NM_CUSTOMDRAW 通知时,这个 NM_CUSTOMDRAW 应该有 dwDrawState 等于 CDDS_PREPOSTPAINT,不是吗?

有人可以在该 MSDN 文章中的返回值含义列表中解释什么“这发生在......”。

4

2 回答 2

2

这很容易。lParam指针是NMHDR*同时的NMLVCUSTOMDRAW*。如果您查看如何NMLVCUSTOMDRAW定义,您将看到它以NMHDR成员开头。

话虽如此,您可以可靠地将您的内容投射LPARAM到您选择的任何内容上:NMHDR*, NMCUSTOMDRAW*, NMLVCUSTOMDRAW*. 如果通知来自 listview,则消息本身是WM_NOTIFY并且NMHDR::code等于NM_CUSTOMDRAW,那么这三个转换中的任何一个都将是正确的。

NMLVCUSTOMDRAW其视为 general purpose 的特定于通知的扩展NMHDR

于 2013-01-24T14:42:16.927 回答
2

Microsoft Windows 构建其结构的方式是普通旧数据格式。因此,如果我定义:

struct A {
    int a;
};

struct B {
    A a;
    int b;
};

struct C {
    A a;
    int c;
};

B 在内存中的布局实际上是两个整数,A 的全部内容(一个整数)然后 B 的全部内容(另一个整数)。因此,将 B 视为 A 是安全的,因为我可以获得 a 值并从 a 成员中确定我的指针是否真的属于 B 类型或 C 类型。在您提供的示例中,NMHDR 是通用值( A) 和 NMLISTVIEW 是具体值(B 或 C)。您测试 hdr 值(类型为 NMHDR)以查看 lParam 是什么类型,然后将其转换为正确的子类型。这适用于 C 和 C++ Windows 开发。

于 2013-01-24T14:49:24.317 回答