mfc消息响应机制分析

上传人:第*** 文档编号:33963914 上传时间:2018-02-19 格式:DOCX 页数:5 大小:34.24KB
返回 下载 相关 举报
mfc消息响应机制分析_第1页
第1页 / 共5页
mfc消息响应机制分析_第2页
第2页 / 共5页
mfc消息响应机制分析_第3页
第3页 / 共5页
mfc消息响应机制分析_第4页
第4页 / 共5页
mfc消息响应机制分析_第5页
第5页 / 共5页
亲,该文档总共5页,全部预览完了,如果喜欢就下载吧!
资源描述

《mfc消息响应机制分析》由会员分享,可在线阅读,更多相关《mfc消息响应机制分析(5页珍藏版)》请在金锄头文库上搜索。

1、MFC 消息响应机制分析- MFC 是 Windows 下程序设计的最流行的一个类库,但是该类库比较庞杂,尤其是它的消息映射机制,更是涉及到很多低层的东西,我们在这里,对它的整个消息映射机制进行了系统的分析,可以帮助程序开发人员对 MFC 的消息映射机制有一个比较透彻的了解。1引言- VC+的 MFC 类库实际上是 Windows 下 C+编程的一套最为流行的类库。MFC 的框架结构大大方便了程序员的编程工作,但是为了更加有效、灵活的使用 MFC 编程,了解 MFC 的体系结构往往可以使编程工作事半功倍。它合理的封装了WIN32 API 函数,并设计了一套方便的消息映射机制。但这套机制本身比较

2、庞大和复杂,对它的分析和了解无疑有助于我们写出更为合理的高效的程序。这里我们简单的分析 MFC 的消息响应机制,以了解 MFC 是如何对 Windows 的消息加以封装,方便用户的开发。2. SDK 下的消息机制实现- 这里简单的回顾一下 SDK 下我们是如何进行 Windows 的程序开发的。一般来说,Windows 的消息都是和线程相对应的。即 Windows 会把消息发送给和该消息相对应的线程。在 SDK 的模式下,程序是通过 GetMessage 函数从和某个线程相对应的消息队列里面把消息取出来并放到一个特殊的结构里面,一个消息的结构是一个如下的 STRUCTURE。 typedef

3、struct tagMSG HWND hwnd;UINT message; WPARAM wParam;LPARAM lParam;DWORD time;POINT pt; MSG;- 其中 hwnd 表示和窗口过程相关的窗口的句柄,message 表示消息的 ID 号,wParam 和 lParam 表示和消息相关的参数,time 表示消息发送的时间,pt 表示消息发送时的鼠标的位置。 - 然后 TranslateMessage 函数用来把虚键消息翻译成字符消息并放到响应的消息队列里面,最后 DispatchMessage 函数把消息分发到相关的窗口过程。然后窗口过程根据消息的类型对不同的消

4、息进行相关的处理。在 SDK 编程过程中,用户需要在窗口过程中分析消息的类型和跟消息一起的参数的含义,做不同的处理,相对比较麻烦,而 MFC 把消息调用的过程给封装起来,使用户能够通过 ClassWizard 方便的使用和处理 Windows 的各种消息。 3MFC 的消息实现机制- 我们可以看到,在 MFC 的框架结构下,可以进行消息处理的类的头文件里面都会含有 DECLARE_MESSAGE_MAP()宏,这里主要进行消息映射和消息处理函数的声明。可以进行消息处理的类的实现文件里一般都含有如下的结构。 BEGIN_MESSAGE_MAP(CInheritClass, CBaseClass)

5、/AFX_MSG_MAP(CInheritClass)/AFX_MSG_MAPEND_MESSAGE_MAP()- 这里主要进行消息映射的实现和消息处理函数的实现。 - 所有能够进行消息处理的类都是基于 CCmdTarget 类的,也就是说 CCmdTarget 类是所有可以进行消息处理类的父类。CCmdTarget 类是 MFC 处理命令消息的基础和核心。 - 同时 MFC 定义了下面的两个主要结构: AFX_MSGMAP_ENTRYstruct AFX_MSGMAP_ENTRYUINT nMessage; / windows messageUINT nCode; / control cod

6、e or WM_NOTIFY codeUINT nID; / control ID (or 0 for windows messages)UINT nLastID; / used for entries specifying a range of control idsUINT nSig; / signature type (action) or pointer to message #AFX_PMSG pfn; / routine to call (or special value);和 AFX_MSGMAPstruct AFX_MSGMAP#ifdef _AFXDLLconst AFX_M

7、SGMAP* (PASCAL* pfnGetBaseMap)();#elseconst AFX_MSGMAP* pBaseMap;#endifconst AFX_MSGMAP_ENTRY* lpEntries;其中 AFX_MSGMAP_ENTRY 结构包含了一个消息的所有相关信息,其中nMessage 为 Windows 消息的 ID 号nCode 为控制消息的通知码nID 为 Windows 控制消息的 IDnLastID 表示如果是一个指定范围的消息被映射的话,nLastID 用来表示它的范围。nSig 表示消息的动作标识AFX_PMSG pfn 它实际上是一个指向和该消息相应的执行函数

8、的指针。- 而 AFX_MSGMAP 主要作用是两个,一:用来得到基类的消息映射入口地址。二:得到本身的消息映射入口地址。 - 实际上,MFC 把所有的消息一条条填入到 AFX_MSGMAP_ENTRY 结构中去,形成一个数组,该数组存放了所有的消息和与它们相关的参数。同时通过 AFX_MSGMAP 能得到该数组的首地址,同时得到基类的消息映射入口地址,这是为了当本身对该消息不响应的时候,就调用其基类的消息响应。 - 现在我们来分析 MFC 是如何让窗口过程来处理消息的,实际上所有 MFC 的窗口类都通过钩子函数_AfxCbtFilterHook截获消息,并且在钩子函数_AfxCbtFilte

9、rHook 中把窗口过程设定为 AfxWndProc。原来的窗口过程保存在成员变量m_pfnSuper 中。 - 所以在 MFC 框架下,一般一个消息的处理过程是这样的。 函数 AfxWndProc 接收 Windows 操作系统发送的消息。 函数 AfxWndProc 调用函数 AfxCallWndProc 进行消息处理,这里一个进步是把对句柄的操作转换成对 CWnd 对象的操作。函数 AfxCallWndProc 调用 CWnd 类的方法 WindowProc 进行消息处理。注意 AfxWndProc 和 AfxCallWndProc 都是AFX 的 API 函数。而 WindowProc

10、 已经是 CWnd 的一个方法。所以可以注意到在 WindowProc 中已经没有关于句柄或者是CWnd 的参数了。 方法 WindowProc 调用方法 OnWndMsg 进行正式的消息处理,即把消息派送到相关的方法中去处理。消息是如何派送的呢?实际上在 CWnd 类中都保存了一个 AFX_MSGMAP 的结构,而在 AFX_MSGMAP 结构中保存有所有我们用 ClassWizard 生成的消息的数组的入口,我们把传给 OnWndMsg 的 message 和数组中的所有的 message 进行比较,找到匹配的那一个消息。实际上系统是通过函数 AfxFindMessageEntry 来实现

11、的。找到了那个 message,实际上我们就得到一个AFX_MSGMAP_ENTRY 结构,而我们在上面已经提到 AFX_MSGMAP_ENTRY 保存了和该消息相关的所有信息,其中主要的是消息的动作标识和跟消息相关的执行函数。然后我们就可以根据消息的动作标识调用相关的执行函数,而这个执行函数实际上就是通过 ClassWizard 在类实现中定义的一个方法。这样就把消息的处理转化到类中的一个方法的实现上。举一个简单的例子,比如在 View 中对 WM_LButtonDown 消息的处理就转化成对如下一个方法的操作。 void CInheritView:OnLButtonDown(UINT nF

12、lags, CPoint point) / TODO: Add your message handler code here and/or call default CView:OnLButtonDown(nFlags, point);注意这里 CView:OnLButtonDown(nFlags, point)实际上就是调用 CWnd 的 Default()方法。 而 Default()方法所做的工作就是调用 DefWindowProc 对消息进行处理。这实际上是调用原来的窗口过程进行缺省的消息处理。 如果 OnWndMsg 方法没有对消息进行处理的话,就调用 DefWindowProc 对

13、消息进行处理。这是实际上是调用原来的窗口过程进行缺省的消息处理。 - 所以如果正常的消息处理的话,MFC 窗口类是完全脱离了原来的窗口过程,用自己的一套体系结构实现消息的映射和处理。即先调用 MFC 窗口类挂上去的窗口过程,再调用原先的窗口过程。并且用户面对和消息相关的参数不再是死板的wParam 和 lParam,而是和消息类型具体相关的参数。比如和消息 WM_LbuttonDown 相对应的方法 OnLButtonDown 的两个参数是 nFlags 和 point。nFlags 表示在按下鼠标左键的时候是否有其他虚键按下,point 更简单,就是表示鼠标的位置。- 同时 MFC 窗口类消

14、息传递中还提供了两个函数,分别为 WalkPreTranslateTree 和 PreTranslateMessage。我们知道利用 MFC 框架生成的程序,都是从 CWinApp 开始执行的,而 CWinapp 实际继承了 CWinThread 类。在 CWinThread的运行过程中会调用窗口类中的 WalkPreTranslateTree 方法。而 WalkPreTranslateTree 方法实际上就是从当前窗口开始查找愿意进行消息翻译的类,直到找到窗口没有父类为止。在 WalkPreTranslateTree 方法中调用了PreTranslateMessage 方法。实际上 PreT

15、ranslateMessage 最大的好处是我们在消息处理前可以在这个方法里面先做一些事情。举一个简单的例子,比如我们希望在一个 CEdit 对象里,把所有的输入的字母都以大写的形式出现。我们只需要在PreTranslateMessage 方法中判断 message 是否为 WM_CHAR,如果是的话,把 wParam(表示键值) 由小写字母的值该为大写字母的值就实现了这个功能。 - 继续上面的例子,根据我们对 MFC 消息机制的分析,我们很容易得到除了上面的方法,我们至少还可以在另外两个地方进行操作。 - 一:在消息的处理方法里面即 OnChar 中,当然最后我们不再调用 CEdit:OnC

16、har(nChar, nRepCnt, nFlags),而是直接调用 DefWindowProc(WM_CHAR,nChar,MAKELPARAM (nRepCnt,nFlags)。因为从我们上面的分析可以知道CEdit:OnChar(nChar, nRepCnt, nFlags)实际上也就是对 DefWindowProc 方法的调用。 - 二:我们可以直接重载 DefWindowProc 方法,对 message 类型等于 WM_CHAR 的,直接修改 nChar 的值即可。 4小结- 通过对 MFC 类库的分析和了解,不仅能够使我们更好的使用 MFC 类库,同时,对于我们自己设计和实现框架和类,无疑也有相当大的帮助。二MFC 的消息映射机制 MFC 的设计者们在设计 MFC 时,紧紧把握一个目标,那就是尽可能使得 MFC 的代码要小,速度尽可能快。为了这个目标,他们使用了许多

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 解决方案

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号