`

WM_NOTIFY消息

 
阅读更多
  当自定义控件中发生了特殊的事件需要通知父窗口时,可以向父窗口发送消息,最简单的方法就是直接向父窗口直接发送自定义消息:
  this->GetParent()->SendMessage(WM_USR1, wParam, lParam);
这种方法简单虽然简单,但是不太干净。因为这样做的前提是要保证WM_USR1消息ID在父窗口的范围内保持唯一,否则父窗口就可能会混淆该消息的来源。而一个窗口中的控件会有很多,并不能保证所有控件的所有消息ID都是唯一的。这就会留下了隐患。
<wbr></wbr>
  其实有一种更好的,也是标准的解决方案,那就是利用WM_NOTIFY消息向父窗口发送通知。
  顾名思义,WM_NOTIFY是专门用于控件向父窗口发送消息的。这个消息与其它的消息不同,用户可以自行定义通知的内容,但传递消息的方式是统一的,程序的处理非常规范、简洁。以下是一点点总结和心得:
<wbr></wbr>
  【如何发送WM_NOTIFY消息】
  发送的方法如下所示:

<wbr><wbr><wbr> NMHDR nmhdr;</wbr></wbr></wbr>

<wbr><wbr><wbr> nmhdr.hwndFrom = <span style="color:#0000ff;">this</span>-&gt;m_hWnd;</wbr></wbr></wbr>

<wbr><wbr><wbr> nmhdr.idFrom = <span style="color:#0000ff;">this</span>-&gt;GetDlgID();</wbr></wbr></wbr>

<wbr><wbr><wbr> nmhdr.code = WM_USR1;<wbr><span style="color:#008000;">// 用户自定义消息</span></wbr></wbr></wbr></wbr>

  this->GetParent()->SendMessage(WM_NOTIFY, (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);

从上面可以看出无论是发送什么通知,其格式都是统一的:首先利用NMHDR结构体进行包装,然后再作为WM_NOTIFY消息发送出去。而NMHDR结构,既可以使用系统提供的默认结构,也可以根据需要自行进行扩充。
<wbr></wbr>
  【NMHDR结构体的扩充】
  如果仅仅是向父窗口发送一个“通知”,那么使用默认的NMHDR结构体就已经足够了;但若需要同时传递一些附加的信息,就需要对NMHDR结构体进行扩充了。使用WM_NOTIFY发送通知的魅力就在于,用户可以根据自己的需要扩充任何附加信息进去。下面就是自定义的NMHDR结构体:

  typedef struct tagMyNMHDR {

<wbr><wbr><wbr><wbr><wbr><wbr><wbr> NMHDR<wbr> nmhdr;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><span style="color:#0000ff;">int<wbr></wbr></span> user_data1;</wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><span style="color:#0000ff;">int</span><wbr> user_date2;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr> ......</wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr> } MyNMHDR;</wbr></wbr></wbr>

注意,这个结构体内包含了NMHDR结构体。这里利用到了C/C++的一个著名的特性:C/C++语言不做内存越界检查。因此,对于自定义的结构体,只要把NMHDR放在第一个元素的地方,就可以安全地把该结构体转型为NMHDR。这样就可以很方便地在WM_NOTIFY消息中发送自定义的附加信息了。
<wbr></wbr>
  【父窗口如何进行消息影射】
  消息发送出去后,父窗口(也就是消息接受方)如何接受这个消息呢?首先是要做消息映射:

  ON_NOTIFY(WM_USR1, CTRLID, memberfun1)<wbr></wbr> // 单控件

<wbr><wbr><wbr><span style="color:#333333;">ON_NOTIFY_RANGE(WM_USR1, CTRLID1, CTRLIDn, memberfun2)</span><wbr><span style="color:#008000;">// 控件组</span></wbr></wbr></wbr></wbr>

<wbr>然后要做的是定义消息接受函数:</wbr>

<wbr><wbr><wbr> afx_msg <span style="color:#0000ff;">void</span> memberfun1(NMHDR *nmhdr, LRESULT *result);<wbr><span style="color:#008000;">// 单控件</span></wbr></wbr></wbr></wbr>

  afx_msg void memberfun2(UINT id, NMHDR *nmhdr, LRESULT *result);<wbr><span style="color:#008000;">// 控件组</span></wbr>

<wbr>(以上第二项是针对控件组的消息映射,这对于那些需要动态生成控件组的应用来说非常有用。)</wbr>
<wbr>  从消息映射可以看出,每个用户自定义的消息,都被限定在指定的控件上了,并且在NMHDR结构中还有<span style="color:#0000ff;">消息源的窗口句柄</span>和<span style="color:#0000ff;">消息源的控件ID</span>。因此,用这种方法向父窗口发送通知是不会混淆消息源的,也不需要什么额外的处理。</wbr>
<wbr><hr></wbr>
  到此为止,WM_NOTIFY消息从生成、发送,到接受的过程就完成了。再回过头来看看生成NMHDR结构的地方,是否会发现什么问题呢?是的,那就是:
  NMHDR结构体的内存应该什么时机进行分配,什么时机进行释放呢?
  在上例中,NMHDR结构体是建立在栈上的,在方法执行完毕后,NMHDR所占用的内存将自动被释放,不用担心内存泄露的问题。但是也因此引发一个新问题:如果以异步的形式(PostMessage)发送消息会有什么结果呢?可想而知,在接受方处理消息的时候,发送方很有可能已经结束处理,NMHDR结构也已被自然释放掉了。因此接受方所收到的NMHDR指针已经变成了“野指针”!从而必然引发内存崩溃危险
  那么,如果把NMHDR建立在堆上,又会如何呢?这样做虽然可以避免了上述野指针的问题,但是已经分配给NMHDR结构体的内存,由谁来释放呢?什么时机释放呢?发送方固然已经无力对其进行释放,由接收方进行释放也是很麻烦的。因为有时会存在消息反射和消息传递的情况,对接收方来说很难判断自己是否是消息处理链的最后一个环节。这使问题复杂化了,同时也违背了“谁分配谁释放”的内存处理原则,稍不留神就会引发内存泄露。
  结论:最好不要在堆上建立NMHDR结构体,也不要用PostMessage方法异步发送WM_NOTIFY消息。
分享到:
评论

相关推荐

    WM_NOTIFY消息流程实例分析

    WM_NOTIFY消息流程实例分析---对应博客代码

    WM_NOTIFY.zip_WM_NOTI_WM_NOTIFY

    分析与理解通知消息-WM_NOTIFY

    MFC 全面解读WM_NOTIFY

    MFC 全面解读WM_NOTIFY

    Window 消息大全

    在WM_NOTIFY消息,使用此控件能使某个控件与它的父控件之间进行相互通信 WM_CONTEXTMENU= $007B //当用户某个窗口中点击了一下右键就发送此消息给这个窗口 WM_styleCHANGING= $007C //当调用SETWINDOWLONG函数将要...

    如何控制列表控件的一行颜色显示

    这些消息可以通过MFC定义的宏ON_NOTIFY_REFLECT映射到类的处理函数,不过VC6.0下要自己手动添加,ClassWizard里面没这些消息。 ClistCtrl类的绘制过程有很多状态,如CDDS_PREPAINT, CDDS_ITEM,CDDS_ITEMPREPAINT,...

    WTL消息处理

    以WM_NOTIFY和WM_COMMAND消息形式发送的通知消息包含各种信息。WM_COMMAND消息的参数包含发送通知消息的控件ID,控件的窗口句柄和通知代码,WM_NOTIFY消息的参数还包含一个NMHDR数据结构的指针。

    如何控制列表控件的一行颜色显示.doc

    Common控件的WM_NOTIFY消息 先发给控件自身,自己处理后再决定要不要发给父窗口。 WM_NOTIFY的消息通知码有多种颜色

    C++ Custom Control控件向父窗体发送对应的消息

    向父窗体发送消息 ,这里只讲发送 WM_NOTIFY 消息, 其它消息是相同的 在 控件中的某个函数中 设置发送消息的程序  首先定义一个WM_NOTIFY消息的专用结构. NMHDR nm; nm.code = 123456; // 这里是消息的区别代码 nm...

    VC之美化界面篇本文专题讨论VC中的界面美化,适用于具有中等VC水平的读者。读者最好具有以下VC基础:

    Windows在向窗口发送WM_PAINT消息之前,总会发送一个WM_ERASEBKGND消息通知该窗口擦除背景,默认情况下,Windows将以窗口的背景色清除该窗口。 可以响应窗口(包括子元素)的WM_ERASEBKGND,以更改它们的背景。WM_...

    emwin消息传递函数试验

    本文档介绍了消息传递的几个函数,以及不同桌面的对比实验

    mfc教程(word版)

    4.4.4.2 WM_NOTIFY消息及其处理: 73 4.4.4.3 消息反射 74 4.4.5 对更新命令的接收和处理 77 4.4.5.1 实现方法 77 4.4.5.2 状态更新命令消息 78 4.4.5.3 类CCmdUI 79 4.4.5.4 自动更新用户接口对象状态的机制 80 4.5 ...

    MFC-李进九 电子书籍完整版

    4.4.4.2 WM_NOTIFY消息及其处理: 73 4.4.4.3 消息反射 74 4.4.5 对更新命令的接收和处理 77 4.4.5.1 实现方法 77 4.4.5.2 状态更新命令消息 78 4.4.5.3 类CCmdUI 79 4.4.5.4 自动更新用户接口对象状态的机制 80 4.5 ...

    一个可停靠的,可自动隐藏的,并且可以换肤

    一个可停靠的,可自动隐藏的,并且可以换肤

    经验不足的Win32开发人员会询问建议/说明,以优化/改进WM_PAINT和WM_CTLCOLORSTATIC处理程序的代码

    简介和相关信息:我已经对主窗口的背景及其子静态控件进行了复杂的绘制。此图片的链接显示了它的外观:http://pbrd.co/1cx8DHd [^]静态控件具有SS_NOTIFY样式,值得一提的是...

    MsgInfo V1.00 察看当前进程中消息的控件

    True则只显示加入的窗体句柄消息 EnableClassName和EnableHwnd设置不一致时,以EnableClassName为准5、DisableFrequent:是否过滤掉WM_NCHITTEST、WM_SETCURSOR、WM_ENTERIDLE、WM_NOTIFY出现频繁的消息6、HookType:...

    RRGRID

    - WM_GRID_USER_OUTER+19内部使用 &lt;br&gt;//Grid往父窗口发的通知消息 //wParam --通知码/控件id组成 //lParam --与父窗口进行信息交流的结构指针(GridNotify_T*) #define GM_GRID_NOTIFY WM_GRID_...

    RINGSDK包含界面库和图象库。

    消息代码:窗口消息代码,例:WM_CREATE 自定义消息处理函数名:响应自定义消息的处理函数,这个可以随便取名,例:OnCustomMessage 命令处理函数名:响应菜单命令或控件命令的处理函数,这个可以随便取名,例:...

    发送短信API接口及其例子程序

    1.短信服务器发送短信后,将用WM_COPYDATA的消息发送一个响应包到hWnd_notify, 响应包格式如下: typedef struct __qvdSmResp_t {  int id;  int iErr;  } QVD_SM_RESP; 2. hWnd_notify不是必需的,如果对响应包不...

    Visual C++/MFC学习笔记.doc

    NOTIFY的使用方法第五章 对话框5.1 使用资源编辑器编辑对话框5.2 创建有模式对话框5.3 创建无模式对话框5.4 在对话框中进行消息映射5.5 在对话框中进行数据交换和数据检查5.6 使用属性对话框5.7 使用通用对话框5.8 ...

    Visual_C++_6.0_MFC_入门

    5.8 建立以对话框为基础的应4.F 关于WM_NOTIFY 的使用方法 第五章对话框 5.1 使用资源编辑器编辑对话框 5.2 创建有模式对话框 5.3 创建无模式对话框 5.4 在对话框中进行消息映射 5.5 在对话框中进行数据交换和数据...

Global site tag (gtag.js) - Google Analytics