用户登录  |  用户注册
首 页商业源码原创产品编程论坛
当前位置:PB创新网文章中心编程技巧计算机理论

MFC中消息映射机制分析

减小字体 增大字体 作者:佚名  来源:本站整理  发布时间:2009-01-10 12:07:12
【本文由PB创新网为您整理】

摘  要:MFC以层次结构组织起来,比较庞杂,尤其是它的消息映射机制,更是涉及到很多底层的东西。本文通过对整个消息映射机制进行系统的分析,可以帮助程序开发人员更好地了解MFC,进行可视化编程。

关键词:消息驱动;消息映射;MFC 程序设计

1 引言
微软公司提供的MFC基本类库(Microsoft Foundation Classes),是进行可视化编程时使用最为流行的一个类库。MFC封装了大部分Windows API函数和Windows控件,使得程序的开发变得简单,极大的缩短了程序的开发周期。MFC独创的Document/View框架结构,能够将管理数据的代码和显示数据的程序代码分开,并且设计了一套方便的消息映射和命令传递机制,方便程序员的开发使用。其中消息映射机制本身比较庞大和复杂,对它的分析和了解无疑有助于我们写出更为合理的高效的程序。这里我们分析一下MFC的消息映射机制,以了解MFC是如何对Windows的消息加以封装,方便用户的开发。
2 SDK下的消息机制实现
首先,简单回顾一下SDK下我们是如何进行Windows的程序开发的。Windows程序的运行是依靠外部发生的事件来驱动的,事件由操作系统捕捉,以消息的形式进入消息队列,然后通过消息循环从队列中不断取出消息,送到对应的窗口过程里处理。相对于DOS程序,Windows是以WinMain作为程序的入口点,以下就是一个简化的Win32程序的主体,通过while语句实现消息循环:
WinMain(…)
{
   MSG msg;
   RegisterClass(…);           // 注册窗口类
   CreateWindow(…);            // 创建窗口
   ShowWindow(…);              // 显示窗口
   UpdateWindow(…);
   While(GetMessage(&msg,…)){   // 消息循环
TranslateMessage(…);
DispatchMessage(…);
}
return msg.wParam;
}
其中,msg代表消息,程序是通过GetMessage函数从和某个线程相对应的消息队列里面把消息取出来并放到消息变量msg里面。然后TranslateMessage函数用来把键盘消息转化并放到响应的消息队列里面,最后DispatchMessage函数把消息分发到相关的窗口过程去处理。窗口过程根据消息的类型对不同的消息进行相关的处理。在SDK编程过程中,用户需要在窗口过程中分析消息的类型及其参数的含义,然后做不同的处理,相对比较麻烦;而MFC把消息调用的过程给封装起来,使用户能够通过ClassWizard方便的使用和处理Windows的各种消息。
3 MFC中的消息映射机制
在MFC的框架结构下,“消息映射”是通过巧妙的宏定义,形成一张消息映射表格来进行的。这样一旦消息发生,Framework就可以根据消息映射表格来进行消息映射和命令传递。
首先在需要进行消息处理的类的头文件(.H)里,都会含有DECLARE_MESSAGE_MAP()宏,声明该类拥有消息映射表格:
class CscribbleDoc:public Cdocument
{
    …
DECLARE_MESSAGE_MAP()
};
然后在类应用程序文件(.CPP)实现这一表格
BEGIN_MESSAGE_MAP(CInheritClass, CBaseClass)
     //{{AFX_MSG_MAP(CInheritClass)
         ON_COMMAND(ID_EDIT_COPY,OnEditCopy)
         ………
     //}}AFX_MSG_MAP
END_MESSAGE_MAP()
---- 这里主要进行消息映射的实现,把它和消息处理函数联系在一起。其中出现三个宏,第一个宏是BEGIN_MESSAGE_MAP有两个参数,分别是拥有消息表格的类,及其父类。第二个宏是ON_COMMAND,指定命令消息的处理函数名称。第三个宏是END_MESSAGE_MAP()作为结尾符号。中间的奇怪符号//}}和//{{,是ClassWizard产生的,对程序无影响。
观察DECLARE_MESSAGE_MAP的定义:
#define DECLARE_MESSAGE_MAP () /
private: /
static const AFX_MESSAGE_ENTRY _messageEntries[]; /
protected: /
static AFX_DATA const AFX_MSGMAP messageMap; /
virtual const AFX_MSGMAP* GetMessageMap() const; /
里面又包含了MFC新定义的两个数据结构,如下:
AFX_MSGMAP_ENTRY
struct AFX_MSGMAP_ENTRY
{
     UINT nMessage;   // windows message
     UINT nCode;      // control code or WM_NOTIFY code
     UINT nID;        // control ID (or 0 for windows messages)
     UINT nLastID;    // used for entries specifying a range of control id's
     UINT nSig;       // signature type (action) or pointer to message #
     AFX_PMSG pfn;    // routine to call (or special value)
};
和AFX_MSGMAP
struct AFX_MSGMAP
{
     const AFX_MSGMAP* pBaseMap;
     const AFX_MSGMAP_ENTRY* lpEntries;
};
其中AFX_MSGMAP_ENTRY结构包含了一个消息的所有相关信息,而AFX_MSGMAP主要作用有两个,一是用来得到基类的消息映射入口地址。二是得到本身的消息映射入口地址。
实际上,MFC把所有的消息一条条填入到AFX_MSGMAP_ENTRY结构中去,形成一个数组,该数组存放了所有的消息和与它们相关的参数。同时通过AFX_MSGMAP能得到该数组的首地址,同时得到基类的消息映射入口地址。当本身对该消息不响应的时候,就可以上溯到基类的消息映射表寻找对应的消息响应。
现在我们来分析MFC是如何让窗口过程来处理消息的,实际上所有MFC的窗口类都通过钩子函数_AfxCbtFilterHook截获消息,并且在钩子

[1] [2]  下一页

Tags:

作者:佚名

文章评论评论内容只代表网友观点,与本站立场无关!

   评论摘要(共 0 条,得分 0 分,平均 0 分) 查看完整评论
PB创新网ourmis.com】Copyright © 2000-2009 . All Rights Reserved .
页面执行时间:20,296.88000 毫秒
Email:ourmis@126.com QQ:2322888 蜀ICP备05006790号