MFC下WM_NOTIFY消息处理流程
参考文章:MFC的消息反射机制
在前一篇文章:MFC消息处理流程概述中描述了MFC消息处理的大体流程。由CWnd::OnWndMsg函数可知,当消息为WM_NOTIFY消息时,调用的是virtual CWnd::OnNotify处理。
- if (message == WM_NOTIFY)
- {
- NMHDR* pNMHDR = (NMHDR*)lParam;
- if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult))
- goto LReturnTrue;
- return FALSE;
- }
- BOOL CWnd::OnNotify(WPARAM, LPARAM lParam, LRESULT* pResult)
- {
- NMHDR* pNMHDR = (NMHDR*)lParam;
- HWND hWndCtrl = pNMHDR->hwndFrom;
- // get the child ID from the window itself
- UINT_PTR nID = _AfxGetDlgCtrlID(hWndCtrl);
- int nCode = pNMHDR->code;
- // reflect notification to child window control
- if (ReflectLastMsg(hWndCtrl, pResult))
- return TRUE; // eaten by child
- AFX_NOTIFY notify;
- notify.pResult = pResult;
- notify.pNMHDR = pNMHDR;
- return OnCmdMsg((UINT)nID, MAKELONG(nCode, WM_NOTIFY), ¬ify, NULL);
- }
以上hWndCtrl为子窗口的句柄,通过调用ReflectLastMsg(hWndCtrl, pResult)给子窗口一个自身处理的机会,将消息反射给子窗口处理。ReflectLastMsg返回TRUE,表明子窗口处理了此消息,则OnNotify返回并不交由父窗口处理;反之,表示子窗口未处理此消息,此时,调用OnCmdMsg(...)由父窗口进行处理。
ReflectLastMsg通过层层调用最终会调用CWnd::ReflectChildNotify函数来处理WM_NOTIFY反射消息。
- BOOL PASCAL CWnd::ReflectLastMsg(HWND hWndChild, LRESULT* pResult)
- {
- CWnd* pWnd = (CWnd*)pMap->LookupPermanent(hWndChild);
- return pWnd->SendChildNotifyLastMsg(pResult);
- }
- BOOL CWnd::SendChildNotifyLastMsg(LRESULT* pResult)
- {
- return OnChildNotify(pThreadState->m_lastSentMsg.message,
- pThreadState->m_lastSentMsg.wParam, pThreadState->m_lastSentMsg.lParam, pResult);
- }
- BOOL CWnd::OnChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
- {
- return ReflectChildNotify(uMsg, wParam, lParam, pResult);
- }
CWnd::ReflectChildNotify函数如下:
- BOOL CWnd::ReflectChildNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
- {
- // Note: reflected messages are send directly to CWnd::OnWndMsg
- // and CWnd::OnCmdMsg for speed and because these messages are not
- // routed by normal OnCmdMsg routing (they are only dispatched)
- switch (uMsg)
- {
- ......
- case WM_NOTIFY:
- {
- // reflect the message through the message map as OCM_NOTIFY
- NMHDR* pNMHDR = (NMHDR*)lParam;
- int nCode = pNMHDR->code;
- AFX_NOTIFY notify;
- notify.pResult = pResult;
- notify.pNMHDR = pNMHDR;
- return CWnd::OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_NOTIFY), ¬ify, NULL);
- }
- ......
- }
很显然,调用了virtual CWnd::OnCmdMsg函数来处理,实际上是virtual CCmdTarget::OnCmdMsg函数,CWnd继承自CCmdTarget。
注意:以上return CWnd::OnCmdMsg(0, MAKELONG(nCode, WM_REFLECT_BASE+WM_NOTIFY), ¬ify, NULL)语句,在WM_NOTIFY的基础上+WM_REFLECT_BASE,因为消息流程走到这步,是在子控件窗口的消息映射表中查找反射消息处理函数。
注意区分WM_NOTIFY消息与WM_NOTIFY反射消息,WM_NOTIFY反射消息即消息WM_REFLECT_BASE+WM_NOTIFY,父窗口收到WM_NOTIFY消息而扔给子窗口处理时,为了区分,子窗口处理的消息被译成WM_REFLECT_BASE+WM_NOTIFY消息,否则岂不和子窗口本身的WM_NOTIFY消息混淆了。
- BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,
- AFX_CMDHANDLERINFO* pHandlerInfo)
- {
- //从消息映射中查找对应的处理函数
- for (pMessageMap = GetMessageMap(); pMessageMap->pfnGetBaseMap != NULL;
- pMessageMap = (*pMessageMap->pfnGetBaseMap)())
- {
- lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID);
- if (lpEntry != NULL)
- {
- // 找到对应的消息处理函数
- return _AfxDispatchCmdMsg(this, nID, nCode,
- lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo);
- }
- }
- return FALSE; // not handled 没有对应的消息处理函数则返回FALSE
- }
在子控件窗口类的消息映射表中没有找到对应的WM_REFLECT_BASE+WM_WM_NOTIFY消息(即对应WM_NOTIFY的反射消息)处理函数返回FALSE,也即以上ReflectLastMsg(hWndCtrl, pResult)返回FALSE,这样父窗口就会处理。
否则,在_AfxDispatchCmdMsg函数中会调用对应的反射消息处理函数处理,ReflectLastMsg(hWndCtrl, pResult)返回TRUE,这样父窗口就不会处理了。
http://blog.csdn.net/hisinwang/article/details/8045382
MFC下WM_NOTIFY消息处理流程的更多相关文章
- WM_NOTIFY消息流程实例分析
我们以CListCtrl控件为例来分析WM_NOTIFY消息. CListCtrl控件在Report样式下会包含CHeaderCtrl标头控件,即CHeaderCtrl标头控件为CListCtrl控件 ...
- MFC下OpenGL入门(可以用)
MFC下OpenGL入门 源文件 1, 建一工程文件,我这里命名为first,现在first工程里面我们没有添加任何东西,所有的东西都是MFC自动帮我们创建的. 2, 添加链接库.这一步很关键.打开菜 ...
- [Sciter系列] MFC下的Sciter–4.HTML与图片资源内置
[Sciter系列] MFC下的Sciter–4.HTML与图片资源内置,防止代码泄露. 本系列文章的目的就是一步步构建出一个功能可用,接口基本完善的基于MFC框架的SciterFrame程序,以此作 ...
- [Sciter系列] MFC下的Sciter–2.Sciter中的事件,tiscript,语法
[Sciter系列] MFC下的Sciter–2.Sciter中的事件,tiscript,CSS部分自觉学习,重点说明Tiscript部分的常见语法和事件用法. 本系列文章的目的就是一步步构建出一个功 ...
- vc++深入跟踪MFC程序的执行流程
在MFC程序设计的学习过程中最令人感到难受,甚至于有时会动摇学习者信心的就是一种对于程序的一切细节都没有控制权的感觉.这种感觉来源于学习者不知道一个MFC程序是如何运行起来的(即一个MFC程序的执行流 ...
- wxWidgets:消息处理流程
首先解释下EventHandler. wxWidgets中EventHandler并不是简单的指消息(事件)处理函数,而是一个用于处理窗口系统消息的类.收到消息后,wxEventHandler会调用e ...
- 深入跟踪MFC程序的执行流程
来源: http://blog.csdn.net/ljianhui/article/details/8781991 在MFC程序设计的学习过程中最令人感到难受,甚至于有时会动摇学习者信心的就是一种对于 ...
- MFC下CSocket编程详解(转)
原文转自 http://blog.csdn.net/yejiansnake/article/details/2175778 MFC下CSocket编程详解: 1. 常用的函数和注意事项(详细的函数接口 ...
- MFC下调用控制台和控制台下MFC库的支持
1.MFC下调用控制台 在CWinApp的InitInstance中对话框的DoModal之前加入 AllocConsole(); // 开辟控制台 SetConsoleTitle(_T(" ...
随机推荐
- amazeui学习笔记--css(布局相关2)--等分网格 AVG Grid
amazeui学习笔记--css(布局相关2)--等分网格 AVG Grid 一.总结 1.与grid区别:网格中:am-g + am-u-xx-n 等分网格中只有一个: am-avg-sm-4(在u ...
- python3 登录验证小程序,同一用户输错三次密码,锁定账户
''' 让用户输入用户名密码 认证成功后显示欢迎信息用户3次认证失败后,退出程序,再次启动程序尝试登录时,还是锁定状态''' # !/usr/bin/env python # -*- coding:u ...
- Day2:模块初识
一.模块(库) 别人写好的一堆功能,封装起来,你直接导入就可以用,就不用自己再写一次,使用import方法 二.分类:标准库与第三方库 标准库:免安装,导入即可使用,最常用的一些功能 第三方库:需要下 ...
- chmod用数字来表示权限的方法
前提: mode权限设定字串.格式:[ugoa...][[+-=][rwxX]...][,...] 当中u表示拥有者(user).g表示与拥有者属于同一个群体(group),o表示其它以外的人(ot ...
- Maven 异常:Project configuration is not up-to-date with pom.xml解决方案
一.异常信息: 导入maven工程后,出现如下错误: Description Resource Path Location TypeProject configuration ...
- 使用wepy开发微信小程序商城第一篇:项目初始化
使用wepy开发微信小程序商城 第一篇:项目初始化 前言: wepy小程序项目初始化的操作,官方文档看了好几遍,感觉写得不是很清楚. 这篇写得挺好的:小程序开发之wepy 1.初始化项目 (1)全局安 ...
- iTestin云测工具
软件概述 iTestin是免费服务移动App开发者的真机自动化云测试客户端工具.基于真实的智能终端设备录制一个测试脚本然后运行,并输出运行结果.覆盖Android和iOS两大设备平台,支持Pad/Ph ...
- [RxJS] Multicasting shortcuts: publish() and variants
Because using multicast with a new Subject is such a common pattern, there is a shortcut in RxJS for ...
- 【ALearning】第四章 Android Layout组件布局(二)
前面我们分别介绍和学习了LinearLayout(线性布局).FrameLayout(单帧布局)和AbsoluteLayout(绝对布局).这次我们要进行RelativeLayout(相对布局)和Ta ...
- python课程:python3的输入输出
输出函数用法 (话说python3的输出好像没有python2的灵活了) print('hello,world') #单引号和双引号都可以输出print("hello,world&quo ...