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(" ...
随机推荐
- tomcat的classloader机制
本系列博客打算分析一下tomcat7.x的源码,其中可能会穿插一些java基础知识的介绍 读tomcat的源码的时候,我建议和官方的User Guide一起阅读,明白tomcat做某件事情的目的之后 ...
- HDU 1166 敌兵布阵 树状数组||线段树
http://acm.hdu.edu.cn/showproblem.php?pid=1166 题目大意: 给定n个数的区间N<=50000,还有Q个询问(Q<=40000)求区间和. 每个 ...
- 关于mysql事务行锁for update实现写锁的功能
关于mysql事务行锁for update实现写锁的功能 读后感:用切面编程的理论来讲,数据库的锁对于业务来说是透明的.spring的事务管理代码,业务逻辑代码,表锁,应该是三个不同的设计层面. 在电 ...
- Java BlockingQueue Example(如何使用阻塞队列实现生产者-消费者问题)
Today we will look into Java BlockingQueue. java.util.concurrent.BlockingQueue is a java Queue that ...
- NodeJS服务端重构计划
不知不觉做node开发已经半年时间了.这期间写尝试着去攻克了一些问题.实现了一下想法,也遇到过一些坑. 是时候来梳理一下代码,规划一下接下来的工作. 现阶段我们的nodeserver端代码结构是这种: ...
- screenX, clientX, pageX
screenX:鼠标相对屏幕左上角的水平偏移量. clientX:鼠标相对于浏览器左上角的水平偏移量,会随着滚动条的移动而移动. pageX:鼠标相对浏览器左上角的水平偏移量.不会随着滚动条的移动而移 ...
- python课程:python3函数
摘自廖雪峰的网站:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014316 ...
- shrio 权限管理filterChainDefinitions过滤器配置(转)
shrio 权限管理filterChainDefinitions过滤器配置 /** * Shiro-1.2.2内置的FilterChain * @see ======================= ...
- 解密Arm中国:全球最具影响力的芯片公司中国布局浮出水面
经济观察报 记者 陈伊凡 沈怡然 李华清 对于Arm与中国合资公司事宜,5月4日下午,Arm授权的代表邮件回复<经济观察报>称:“合资公司目前刚开始运营”,“我们的重点是让这个新的合资公司 ...
- Write Code As If You Had to Support It for the Rest of Your Life
Write Code As If You Had to Support It for the Rest of Your Life Yuriy Zubarev YOU COULD ASK 97 PEOP ...