MFC的消息响应机制详解:程序员
1.MFC是Windows下程序设计的最流行的一个类库,可是该类库比较庞杂,尤为是它的消息映射机制,更是涉及到不少低层的东西,接下来详细讲解。编程
2.在讲解MFC的消息响应以前先讲解一下SDK的消息响应: SDK下的消息机制实现windows
讲解一下SDK下咱们是如何进行Windows的程序开发的。通常来讲,Windows的消息都是和线程相对应的。即Windows会把消息发送给和该消息相对应的线程。数组
在SDK的模式下,程序是经过GetMessage函数从和某个线程相对应的消息队列里面把消息取出来并放到一个特殊的结构里面,一个消息的结构是一个以下的STRUCTURE。app
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
}MSG;框架
说明一下结构体里的内容:函数
1)hwnd表示和窗口过程相关的窗口的句柄。spa
2)message表示消息的ID号。操作系统
3)wParam和lParam表示和消息相关的参数。线程
4)time表示消息发送的时间。
5)pt表示消息发送时的鼠标的位置。
再用TranslateMessage函数用来把虚键消息翻译成字符消息并放到响应的消息队列里面,最后DispatchMessage函数把消息分发到相关的窗口过程。
而后窗口过程根据消息的类型对不一样的消息进行相关的处理。在SDK编程过程当中,用户须要在窗口过程当中分析消息的类型和跟消息一块儿的参数的含义,作不一样的处理,
相对比较麻烦,而MFC把消息调用的过程给封装起来,使用户可以经过ClassWizard方便的使用和处理Windows的各类消息。
3.MFC的消息实现机制
在MFC的框架结构下,咱们能够清晰的看到,能够进行消息处理的类的头文件里面都会含有DECLARE_MESSAGE_MAP()宏,这里主要进行消息映射和消息处理函数的声明。
能够进行消息处理的类的实现文件里通常都含有以下的结构。
BEGIN_MESSAGE_MAP(CInheritClass, CBaseClass)
END_MESSAGE_MAP()
1)全部可以进行消息处理的类都是基于CCmdTarget类的,也就是说CCmdTarget类是全部能够进行消息处理类的父类。CCmdTarget类是MFC处理命令消息的基础和核心。
2)同时MFC定义了下面的两个主要结构:
AFX_MSGMAP_ENTRY
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; // windows message
UINT nCode; // control code or WM_NOTIFY code
UINT nID;
UINT nLastID;
UINT nSig;
AFX_PMSG pfn;
};
其中AFX_MSGMAP_ENTRY结构包含了一个消息的全部相关信息:
1)nMessage为Windows消息的ID号。
2)nCode为控制消息的通知码。
3)nID为Windows控制消息的IDnLastID表。
4)若是是一个指定范围的消息被映射的话,nLastID用来表示它的范围。nSig表示消息的动做标识。
5)AFX_PMSG pfn 它其实是一个指向和该消息相应的执行函数的指针。
AFX_MSGMAP
struct AFX_MSGMAP
{
#ifdef _AFXDLL
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
#else
const AFX_MSGMAP* pBaseMap;
#endif
const AFX_MSGMAP_ENTRY* lpEntries;
};
FX_MSGMAP主要做用是两个:
1)用来获得基类的消息映射入口地址。
2)获得自己的消息映射入口地址。
实际上,MFC把全部的消息一条条填入到AFX_MSGMAP_ENTRY结构中去,造成一个数组,该数组存放了全部的消息和与它们相关的参数。
同时经过AFX_MSGMAP能获得该数组的首地址,同时获得基类的消息映射入口地址,这是为了当自己对该消息不响应的时候,就调用其基类的消息响应。
分析一下MFC是如何让窗口过程来处理消息的,实际上全部MFC的窗口类都经过钩子函数_AfxCbtFilterHook截获消息,而且在钩子函数_AfxCbtFilterHook中把窗口过程设定为
AfxWndProc。原来的窗口过程保存在成员变量m_pfnSuper中。
在MFC框架下,通常一个消息的处理过程是这样的,如下做为说明:
函数AfxWndProc接收Windows操做系统发送的消息。
函数AfxCallWndProc调用CWnd类的方法WindowProc进行消息处理。注意AfxWndProc和AfxCallWndProc都是AFX的API函数。而WindowProc已是CWnd的一个方法。
因此能够注意到在WindowProc中已经没有关于句柄或者是CWnd的参数了。
方法WindowProc调用方法OnWndMsg进行正式的消息处理,即把消息派送到相关的方法中去处理。消息是如何派送的呢?实际上在CWnd类中都保存了一个AFX_MSGMAP的
结构,而在AFX_MSGMAP结构中保存有全部咱们用ClassWizard生成的消息的数组的入口,咱们把传给OnWndMsg的message和数组中的全部的message进行比较,
找到匹配的那一个消息。实际上系统是经过函数AfxFindMessageEntry来实现的。找到了那个message,实际上咱们就获得一个AFX_MSGMAP_ENTRY结构,
而咱们在上面已经提到AFX_MSGMAP_ENTRY保存了和该消息相关的全部信息,其中主要的是消息的动做标识和跟消息相关的执行函数。
而后咱们就能够根据消息的动做标识调用相关的执行函数,而这个执行函数实际上就是经过ClassWizard在类实现中定义的一个方法。
这样就把消息的处理转化到类中的一个方法的实现上。
举一个简单的例子,好比在View中对WM_LButtonDown消息的处理就转化成对以下一个方法的操做。
void CInheritView::OnLButtonDown(UINT nFlags, CPoint point)
{
handler code here and/or call default
CView::OnLButtonDown(nFlags, point);
}
注意这里CView::OnLButtonDown(nFlags, point)实际上就是调用CWnd的Default()方法。 而Default()方法所作的工做就是调用DefWindowProc对消息进行处理。
这其实是调用原来的窗口过程进行缺省的消息处理。
若是OnWndMsg方法没有对消息进行处理的话,就调用DefWindowProc对消息进行处理。这是其实是调用原来的窗口过程进行缺省的消息处理。因此若是正常的消息处理的
话,MFC窗口类是彻底脱离了原来的窗口过程,用本身的一套体系结构实现消息的映射和处理。即先调用MFC窗口类挂上去的窗口过程,再调用原先的窗口过程。而且用户面
对和消息相关的参数再也不是死板的wParam和lParam,而是和消息类型具体相关的参数。
好比和消息WM_LbuttonDown相对应的方法OnLButtonDown的两个参数是nFlags和point。nFlags表示在按下鼠标左键的时候是否有其余虚键按下,point更简单,
就是表示鼠标的位置。
同时MFC窗口类消息传递中还提供了两个函数,分别为WalkPreTranslateTree和PreTranslateMessage。咱们知道利用MFC框架生成的程序,都是从CWinApp开始执行的,
而CWinapp实际继承了CWinThread类。在CWinThread的运行过程当中会调用窗口类中的WalkPreTranslateTree方法。
而WalkPreTranslateTree方法实际上就是从当前窗口开始查找愿意进行消息翻译的类,直到找到窗口没有父类为止。
在WalkPreTranslateTree方法中调用了PreTranslateMessage方法。实际上PreTranslateMessage最大的好处是咱们在消息处理前能够在这个方法里面先作一些事情。
举一个简单的例子:
好比咱们但愿在一个CEdit对象里,把全部的输入的字母都以大写的形式出现。咱们只须要在PreTranslateMessage方法中判断message是否为WM_CHAR,
若是是的话,把wParam(表示键值)由小写字母的值该为大写字母的值就实现了这个功能。
继续上面的例子,根据咱们对MFC消息机制的分析,咱们很容易获得除了上面的方法,咱们至少还能够在另外两个地方进行操做。
a.在消息的处理方法里面即OnChar中,固然最后咱们再也不调用CEdit::OnChar(nChar, nRepCnt, nFlags),而是直接调用DefWindowProc(WM_CHAR,nChar,MAKELPARAM
(nRepCnt,nFlags))。
由于从咱们上面的分析能够知道CEdit::OnChar(nChar, nRepCnt, nFlags)实际上也就是对DefWindowProc方法的调用。
b.咱们能够直接重载DefWindowProc方法,对message类型等于WM_CHAR的,直接修改nChar的值便可。
4.今天就写这些,明天继续,程序员们要想要精通代码,最主要的方式之一就是要多练习,多调试,这样面对bug的时候才能临危不动。
改变本身,从如今作起-----------久馆