您的位置:首页 > 其它

WM_NOTIFY消息

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

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

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

然后要做的是定义消息接受函数:afx_msg void memberfun1(NMHDR *nmhdr, LRESULT *result); // 单控件
  afx_msg void memberfun2(UINT id, NMHDR *nmhdr, LRESULT *result); // 控件组

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