MFC代码分析02:初探MFC程序消息处理机制
上一篇:MFC代码分析01:初探MFC程序初始化及运行经典的Windows版Hello World,当消息产生,系统就会把消息放到应用程序消息队列中,应用程序通过GetMessage取出消息内容,并通过DispatchMessage把消息交换给操作系统。此时,窗口消息回调函数就会被激活,去处理这一消息。
然而,在MFC中,消息是不是按照这样的机制进行中转处理呢?答案是不是的。为什么呢?虽然多态的特性,允许子类去改写一函数,使得在实际使用中使用子类的函数而不是父类的函数。但这样的代价就是背负着一个虚函数表。MFC各类的关系是一个复杂的树状结构,我们知道,如果一旦通过子类重写父类消息响应函数取实现消息的中转,那么每一个MFC类都要背负一个沉重的虚函数表,这样来说,对资源是一种极大的浪费。
MFC消息处理采取消息映射的策略进行实现:在每一个能接收和处理消息的类中,定义一个
消息和响应函数的映射表。当接收到消息时,程序从消息表中检索是否存在该消息及其绑定的响应函数,如果存在则将消息交由该响应函数处理。
我们用一个最简单的例子进行说明,我们以WM_CREATE消息为例进行说明。当我们用向导创建一个WM_CREATE的响应函数时,VC便会为你在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间创建一段代码:
BEGIN_MESSAGE_MAP()
...
ON_WM_CREATE()
...
END_MESSAGE_MAP()
我们看一看,这一个ON_WM_CREATE()是个什么东西。转到其定义,我们发现,其实它是一个宏,其位于afxmsg_.h中:
#define ON_WM_CREATE() \
{ WM_CREATE, 0, 0, 0, AfxSig_is, \
(AFX_PMSG) (AFX_PMSGW) \
(static_cast< int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT) > (OnCreate)) },
我们发现,这些宏进行的就是一个静态绑定的过程。以下是其中另外一些宏的含义:
AfxSig_is:枚举值,表示一函数指针类型 int (LPTSTR),存储于Entries in a message map (a 'AFX_MSGMAP_ENTRY') table中
AFX_PMSG: typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);
AFX_PMSGW:typedef void (AFX_MSG_CALL CWnd::*AFX_PMSGW)(void);
我们在同一文件中也能发现一些最基本的系统消息的定义。
我们采用跟踪的方法,跟踪WM_CREATE消息,看看MFC的消息到底是怎么中转的。我们发现,其轨迹如下:
AfxWndProcBase --> AfxCallWndProc --> CWnd::WindowProc --> CWnd::OnWndMsg --> 消息处理函数
AfxWndProcBase,AfxCallWndProc(消息中转通道)
作用:将消息转至窗口消息回调函数
CWnd::WindowProc(主消息回调函数)
转交CWnd::OnWndMsg
CWnd::OnWndMsg
其中有个MessageMapFunctions结构,表示消息映射数据成员。进行消息的中转
用户系统信息:Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322)