深入浅出MFC学习笔记 消息
本章将会对MFC的消息映射和 命令传递机制做深入探讨。
MFC规定了消息传递的路线,消息会按照这个路线传递下去,找不到归宿的话就交给DefWindowProc。
在产生窗口之前,如果我们在创建窗口时指定的窗口类为NULL时,MFC会自动注册五个默认的窗口类,每个窗口类有自己的窗口函数。不同窗口得到的消息应该交由不同的窗口函数来处理。所谓的命令传递机制是为了让消息的流动有线路可循,实现一个巨大的网,实现所有可能的路线。这就是所谓的消息映射图。
WM_COMMAND是来自菜单或工具栏,被称为命令消息。wParam记录着这一消息来自哪个菜单项目。
除了命令消息控件传给父窗口的消息,也是以WM_COMMAND类型的,但是它们被称为notification消息。
Command target即命令的目的地。因此所有派生自CCmdTarget类的类都可以处理命令消息。
派生自CWnd的类可以处理一般的windows消息和COMMAND消息。
DECLARE_MESSAGE_MAP()
BEGIN_MESSAGE_MAP
ON_COMAMND()
END_MESSAGE()
这些宏实现了消息和消息处理函数的映射,不再介绍哦。
在BEGIN和END之间除了ON_COMMAND之外,还可以有其他的形式,标准的windows消息并不需要我们指定处理函数的名称。如:
ON_WM_CHAR();WM_CHAR OnChar
ON_WM_CLOSE(); WM_CLOSE OnClose
ON_WM_CREATE(); WM_CREATE OnCreate
这些宏MFC已经定义好,将标准的消息和消息处理函数对应起来。
AFX_DAT,AFX_DATADEF,AFX_MSG_CALL和afx_msg一样现在还没有被使用。
虽然所有继承自CCmdTarget的类都可以处理命令消息,都应该有DECLARE_MESSAGE_MAP。。。但是CWinThread却没有。它不参与消息处理。因此CWinApp在填写消息映射表是就会跳过CWinThread。
DECLARE_MESSAGE_MAP(CWinApp,CCmdTarget);
消息映射表有C++多态的味道,但是MFC却没有使用多态来实现它,究其原因估计是多态会导致很大的负担。
前面的介绍中,以AfxWinProc作为起点,此处MFC仍以此作为开始,但是却省略了很多的细节。通常消息是在消息队列中等待窗口抓取,但是MFC安装了钩子,就可以提前抓取或抓取不是自己的消息。这是在所有派生自CWnd的对象创建之际发生的。如:
Bool CWnd::CreateEx()
{
。。。
AfxHookWindowCreate(this);
HWND hWnd=::CreateWindowEx();
...
}
AfxHookWindowCreate安装了WH_CBT类型的钩子,任何窗口显示之前,注册的钩子函数会被调用。
细节不再深入介绍,只要知道以上这些干了些偷天换日的勾当,把注册窗口类时注册的窗口函数,更换为AfxWndProc。于是AfxWndProc便是DispatchMessage的目的地。之所以弄得这么复杂书上说是为了兼容什么3D constrols。不懂,暂且放这儿吧。记住结论就是了。
上面可以知道AfxWndProc是消息的源头,这在前面几张也提到过。在此函数内部会调用AfxClassWndProc,后者会调用pWnd->WindowProc();在整个MFC中拥有windowProc的类有CWnd,CControlBar,COleControl,CDialog......具体调用谁的WindowProc要看pWnd 的类型。
在CWnd::windowProc中会调用OnWndMsg函数,它是用来分辨并处理消息的专职机构。如果是命令就交给OnCommand处理,如果是通知消息就交给OnNotify处理。之所以要区分命令消息和通知消息是因为它们的上溯路径并不是单纯的只往父类上去,可能有其他路径。而一般的windows消息却沿着直线上溯。
在OnCommand又调用了OnCmdMsg函数。具体调用哪个OnCommand,OnCmdMsg也是不定的,也得看this指针的类型。OnCmdMsg它是专门处理命令消息的函数。
bool CFrameWnd::OnCmdMsg(UINT nID,int nCode)
{
CView*pView=GetActiveView();
if(pView->OnCmdMsg(nID,nCode))//处理则返回否则继续传递。
return true;
if(CWnd::OnCmdMsg(nID,nCode))
return true;
CWinApp*pApp=AfxGetApp();
if(pApp->OnCmdMsg(nID,nCode)
return true;
return fasle;
}
bool CView::OnCmdMsg(UINT nID,int nCode)
{
cout<<"CView::OnCmdMsg()"<<endl;
if(CWnd::OnCmdMsg(nID,nCode))
return true;
bool bHandled=false;
bHandled=m_pDocument->OnCmdMsg(nID,nCode);
return bHandled;
}
Bool CDocument::OnCmdMsg(UINT nID,int nCode)
{
cout<<"CDocument::OnCmdMsg()"<<endl;
if(CCmdTarget::OnCmdMsg(nID,nCode))
return true;
return false;
}
以上就是消息的传递路线,这里跟第三章模拟的命令传递路线是相同的,具体可以第三章。
OnCmdMsg是各类专门对付命令消息的函数。本类处理过后又会调用下一个类的OnCmdMsg,这样命令消息就会不断传递下去。
如果MDI主窗口接收到一个命令消息,主窗口会把消息传递给CMDIChildWnd子窗口。子窗口传递给它对应的视图,视图检查自己的消息映射表,如果没有找到对应项,将其传递给document。Document检查自己的消息 映射表,找到对应项则调用该函数,消息传递 结束。如果没有找到继续传递,document把该消息传递到document template对象。如果还是没有找到,则传回到view,view将其传递给MDI子窗口本身。继续传递给CWinApp,交给 默认的消息处理函数。
在定义CRuntimeClass时,MessageMapEntries内定义了消息函数的指针类型,
typedef void(AFX_MSG_CALL
CCmdTarget:::*AFX_PMSG)(void);
此时消息处理函数指针类型为返回值为空,参数为空,这是不符合实际的,实际使用中会经过类型转换,使其可以接收参数和返回值。
由于消息处理函数的类型各异,MFC使用了AfxSig_来说明消息处理函数的类型。在找到某消息的消息处理函数之后,判断其类型再进行响应转换。
union MessageMapFunctions mmf;
mmf.pfn=lpEntry->pfn;
switch(lpEntry->nSig)
{
case AfxSig_isg:
lResult=(this->*mmf.pfn_is)(LPTSTR)lParam);
break;
case Afx_Sig_lwl:
lResult=(this->*mmf.pfn_lwl)(wParam,lParam);
break;
case AfxSig_vv:
(this->*mmf.pfn_vv)();
break;
........
}
AfxSig_is代表参数为LPTSTR字符串,返回值为int.
Afx_lwl代表参数wiewParam和lParam。返回值为LRESULT。
Afx_vv代表参数和返回值都为void.
(this->*mmf.pfn_vv)();中的pfn_vv是union MessageMapFunctions的一个成员。如
union MessageMapFunctions
{
AFX_PMSG pfn;
bool (AFX_MSG_CALL CWnd::*pfn_bD)(CDC*);
void (AFX_MSG_CALL CWnd::*pfn_VV)(CDC*);
.............
};
注意MessageMapFunctions是union类型的哦。
真是佩服当年MFC开发人员的智慧!!!!!
深入浅出MFC学习笔记 消息的更多相关文章
- 深入浅出MFC学习笔记 第三章 MFC六大关键技术之仿真
0:MFC类层次结构 1:MFC程序的初始化过程CWinApp::InitApplication()CMyWinApp::InitInstance()CMyFrameWnd::CMyFrameWnd( ...
- MFC 学习笔记
MFC 学习笔记 一.MFC编程基础: 概述: 常用头文件: MFC控制台程序: MFC库程序: 规则库可以被各种程序所调用,扩展库只能被MFC程序调用. MFC窗口程序: 示例: MFC库中类的简介 ...
- Storm学习笔记 - 消息容错机制
Storm学习笔记 - 消息容错机制 文章来自「随笔」 http://jsynk.cn/blog/articles/153.html 1. Storm消息容错机制概念 一个提供了可靠的处理机制的spo ...
- objc_msgSend消息传递学习笔记 – 消息转发
该文是 objc_msgSend消息传递学习笔记 – 对象方法消息传递流程 的基础上继续探究源码,请先阅读上文. 消息转发机制(message forwarding) Objective-C 在调用对 ...
- MFC学习笔记1---准备工作
什么是MFC MFC,全称Microsoft Foundation Classes,微软基础类库,顾名思义,是微软的攻城狮们将一些常用的基础的Windows API 函数用C++的形式封装成类,简化程 ...
- 【MFC学习笔记-作业7-小型画图软件】【】
作业要求: 按下鼠标右键画圆. 按下鼠标左键移动曲线. 丝毫没有思路..网上教程又比这个程序复杂100倍... 好吧 总算找到一个合适的了... 转载至:http://blog.chinaunix.n ...
- Nodejs全站开发学习系列 & 深入浅出Node学习笔记 & Spider抓取
https://course.tianmaying.com/node 这个系列的文章看起来很不错,值得学习一下. /Users/baidu/Documents/Data/Interview/Web-S ...
- MFC学习笔记2---简单计算器
前言 学习了鸡啄米网页的前三部分后,我们就可以做一个小软件出来了,我选择先做一个计算器. 这是Win7系统自带的计算器: 为了提升成就感,我将计算器的大部分内容去除,于是就变成这样: 这样就只剩下了1 ...
- MFC学习笔记(一)
个人对MFC技术一直都很感兴趣,因为能够做出漂亮绚丽的界面应该是一件十分有成就感的事情. 学习的参考课本为北京博彦科技发展有限责任公司翻译的Jeff Prosise著的<MFC Windows程 ...
随机推荐
- BFS - 广度优先搜索 - 邻接列表表示法
2017-07-25 21:40:22 writer:pprp 在DFS的基础上加上了一个BFS函数 #include <iostream> #include <queue> ...
- nodejs 设计模式
1 . 单例模式 顾名思义,单例就是保证一个类只有一个实例,实现的方法是,先判断实例是否存在,如果存在则直接返回,若不存在,则创建实例对象,并将实例对象保存在静态变量中,当下次请求时,则可以直接返回这 ...
- Android中APK安装过程及原理解析
[原文] 来自华为内部资料 应用安装是智能机的主要特点,即用户可以把各种应用(如游戏等)安装到手机上,并可以对其进行卸载等管理操作.APK是Android Package的缩写,即android安装包 ...
- Spring -- 如何为applicationContext.xml 添加 util 的 *.xsd文件
- NumPy数组创建例程
NumPy - 数组创建例程 新的ndarray对象可以通过任何下列数组创建例程或使用低级ndarray构造函数构造. numpy.empty 它创建指定形状和dtype的未初始化数组. 它使用以下构 ...
- TF卡.之前的(20180923)
1.京东上搜到的(购买记录) ZC:64G的应该是 只买了一个 另一个取消了 2.TB上搜到的 购买记录是这样的(注意 也有 取消的) 3. 4. 5.
- spring mvc : 中文传值(post/get)中文乱码
请将以下代码放入 web.xml文件中,注意存放顺序,否则会报错.filter应该放在context-param后面: <!-- 字符过滤器 --> <filter> < ...
- Linux:安装git
1.下载 https://www.kernel.org/pub/software/scm/git/git-2.9.4.tar.gz 2.解压 tar zxvf git-2.9.4.tar.gz cd ...
- js监测滚动条到达最底边
scroll : function(){ $(window).scroll(function () { var scrollTop = $(this).scrollTop(); var scrollH ...
- How to Fix “ShellExecute failed (2): Is this command correct?” on Notepad++
Problem: When you click right-click->Edit with Notepad ++ and get the error “ShellExecute failed ...