Winapi WM_通知和NM_定制绘图

Winapi WM_通知和NM_定制绘图,winapi,Winapi,当NM_CUSTOMDRAW通知代码通过WM_NOTIFY消息发送给控件的父控件时,此WM_NOTIFY消息的lParam参数是NMCUSTOMDRAW结构的地址,如下所示: 另一方面,WM_NOTIFY消息的LPRAM应该是 A pointer to an NMHDR structure that contains the notification code and additional information. For some notification messages, this pa

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

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

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){   .... 
但问题是,我们不知道这个LPRAM是一个NMHDR结构还是一个NM_CUSTOMDRAW结构一个proior,如何才能正确地转换LPRAM?如果LPRAM只是一个NMHDR, 应该使用LPNMHDR和pnm->code,不是吗

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


当我读到这篇文章时

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

CDRF_NOTIFYPOSTPAINT当整个控件的绘制周期完成时,控件将发送NM_CUSTOMDRAW通知。当dwDrawStage等于CDDS_PREPAINT时会发生此情况。

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


有人能解释一下在那篇MSDN文章中返回值的含义列表中“当……发生这种情况时”是什么意思吗。
lParam
指针同时是
NMHDR*
NMLVCUSTOMDRAW*
。如果查看
NMLVCUSTOMDRAW
是如何定义的,您将看到它以
NMHDR
成员开头

话虽如此,您可以可靠地将
LPARAM
强制转换为您选择的任何对象:
NMHDR*
NMCUSTOMDRAW*
NMLVCUSTOMDRAW*
。如果通知来自listview,消息本身是
WM_NOTIFY
,并且
NMHDR::code
等于
NM_CUSTOMDRAW
,则三个强制转换中的任何一个都是正确的


NMLVCUSTOMDRAW
视为通用
NMHDR

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

话虽如此,您可以可靠地将
LPARAM
强制转换为您选择的任何对象:
NMHDR*
NMCUSTOMDRAW*
NMLVCUSTOMDRAW*
。如果通知来自listview,消息本身是
WM_NOTIFY
,并且
NMHDR::code
等于
NM_CUSTOMDRAW
,则三个强制转换中的任何一个都是正确的


可以将
NMLVCUSTOMDRAW
看作通用
NMHDR

的通知特定扩展,Microsoft Windows以普通的旧数据格式构建其结构。因此,如果我定义:

struct A {
    int a;
};

struct B {
    A a;
    int b;
};

struct C {
    A a;
    int c;
};

内存中B的布局实际上是两个整数,A(一个整数)的全部内容,然后是B(另一个整数)的全部内容。因此,只要我能得到A值,就可以安全地将B视为A,并从A成员中确定我的指针是类型B还是类型C。在您提供的示例中,NMHDR是通用值(A),NMLISTVIEW是特定值(B或C)。测试hdr值(类型为NMHDR)以查看LPRAM是什么类型,并从中将其转换为正确的子类型。对于C和C++窗口开发来说,这是正确的。

< P>微软Windows结构的方式是一种普通的旧数据格式。因此,如果我定义:

struct A {
    int a;
};

struct B {
    A a;
    int b;
};

struct C {
    A a;
    int c;
};

内存中B的布局实际上是两个整数,A(一个整数)的全部内容,然后是B(另一个整数)的全部内容。因此,只要我能得到A值,就可以安全地将B视为A,并从A成员中确定我的指针是类型B还是类型C。在您提供的示例中,NMHDR是通用值(A),NMLISTVIEW是特定值(B或C)。测试hdr值(类型为NMHDR)以查看LPRAM是什么类型,并从中将其转换为正确的子类型。对于C和C++窗口开发来说,这是正确的。< / P>你是对的,我只是没意识到。但是如果控件是TreeView,我想使用TreeView,并且在WM_NOTIFY中,我将lParam转换为LPNMLVCUSTOMDRAW,虽然这并不重要,但在我看来它看起来并不好。你可以单独转换,不会带来任何麻烦。一旦您铸造,您就会看到控件标识符是treeview的标识符,并且不再使用这种铸造错误的结构。好或坏-这是如何通知工作,并开始工作多年前。当时,让它简单而不臃肿是非常重要的。@user565739:通常,您首先将
lParam
强制转换为
NMHDR*
,这样您就可以检查它的
code
成员,然后根据需要将
lParam
重新强制转换为更合适的
NM…*
类型。您是对的,我只是没有意识到。但是如果控件是TreeView,我想使用TreeView,并且在WM_NOTIFY中,我将lParam转换为LPNMLVCUSTOMDRAW,虽然这并不重要,但在我看来它看起来并不好。你可以单独转换,不会带来任何麻烦。一旦您铸造,您就会看到控件标识符是treeview的标识符,并且不再使用这种铸造错误的结构。好或坏-这是如何通知工作,并开始工作多年前。在那个时候,让它简单而不臃肿是非常重要的。@user565739:通常,您会首先将
lParam
强制转换为
NMHDR*
,以便检查它的
代码