MFC的消息映射机制的理解

一、映射机制原理

Windows程序是基于消息机制来编程的。

MFC消息映射机制的具体实现方法是:在每个能接收和处理消息的类中,定义一个消息和消息函数静态对照表,即消息映射表在消息映射表中,消息与对应的消息处理函数指针是成对出现的,也就是他们是绑定在一起的。某个类能处理的所有消息及其对应的消息处理函数的地址都列在这个类所对应的静态对照表中。当有消息需要处理时,程序只要搜索该消息静态表,查看表中是否含有该消息,就可以知道该类能否处理此消息。如果能处理该消息,则同样依照静态表能很容易找到并调用对应的消息处理函数。

之所以没有采用:在基类中针对每种消息做一个虚函数(虚函数必须由一个虚函数表vtable来实现),当子类对消息响应时候,只要在子类中重写这个虚函数即可,是因为MFC类派生层次很多,如果在基类对每个消息进行虚函数处理,那么从基类派生的每个子类都将背负一个庞大的虚函数表,这样浪费内存,故MFC没有采取这种方式而采取消息映射方式。 

二、举例(vc视频中例子)

    假设我们给视类添加一个鼠标左键的消息响应函数,MFC会在三处添加代码:

1)视类的头文件

// 生成的消息映射函数

protected:

DECLARE_MESSAGE_MAP()

public:

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);//afx_msg宏表示声明的是一个消息响应函数。

2)在视类的源文件

BEGIN_MESSAGE_MAP(CMFCTestView, CView)

// 标准打印命令

ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)

ON_WM_LBUTTONDOWN()

END_MESSAGE_MAP()

    在宏BEGIN_MESSAGE_MAP()END_MESSAGE_MAP()之间进行消息映射。ON_WM_LBUTTONDOWN()把消息WM_LBUTTONDOWN与它的响应函数OnLButtonDown()相关联。这样一旦有消息的产生,就会自动调用相关联的消息响应函数去处理。 

#define ON_WM_LBUTTONDOWN() \

{ WM_LBUTTONDOWN, 0, 0, 0, AfxSig_vwp, \

(AFX_PMSG)(AFX_PMSGW) \

(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > ( &ThisClass :: OnLButtonDown)) },

3)还是在在视类的源文件

    void CMFCTestView::OnLButtonDown(UINT nFlags, CPoint point)

{

// TODO: 在此添加消息处理程序代码和/或调用默认值

    MessageBox("View Clicked");

   CView::OnLButtonDown(nFlags, point);

}

    由上可见,一个MFC消息响应函数在程序中有三处相关信息:函数原型,函数实现,以及用来关联消息和消息响应函数的宏。

三、机理分析

MFC在后台维护了一个句柄和C++对象指针对照表,当收到一个消息后,通过消息结构里的资源(消息参数,可获得窗口句柄,查对照表)就可找到与它对应的一个C++对象指针,然后把这个指针传给应用程序框架窗口类的基类,基类利用这个指针调用WindowProc()函数(位于WinCore.cpp文件中)对消息进行处理。

在上面所说的例子中,C++对象指针即指CMFCTestView*,窗口句柄与CMFCTestView对象的指针CMFCTestView*存在一一对应的关系。

WindowProc()函数中调用OnWndMsg()函数,真正的消息路由及处理是由 OnWndMsg()函数完成的。由于WindowProc()OnWndMsg()都是虚函数,而且是用派生类对象指针调用的,有C++的多态性可知,故最终调用子类的。在OnWndMsg()函数处理时,根据消息种类去查找消息映射,判断所发的消息有没有响应函数,具体方式是到相关的头文件和源文件中寻找消息响应函数声明,最终找到对应的消息处理函数。当然,如果子类中没有对消息进行处理,则消息交由基类处理。

virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);

virtual BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult);

说明:

1、在VC6.0中删除已添加的消息响应函数

选中相关联的类,属性,在属性页的消息栏中,在要删除的消息上,点击,选择删除。VC6.0会帮我们删除与消息相关的三处代码(包含消息响应函数)。

2、句柄和指针

句柄是由系统分配的资源ID(我们认为它是一个标识某个系统资源的32位的整数),用于标识系统所分配的资源,这里的资源包含进程、线程等的广泛内容。句柄和指针都是地址。

句柄可以认为是某种意义上的指针,但不是指针;句柄是一些表的索引;也就是指向指针的指针(即二级指针,windows系统在内存中维护的一个对象或一个窗口。因为以虚拟存储方式,需要调度页面,所以程序实际的物理地址是不断变化的,系统中用一个内存地址不变的表来维护这个变化的地址(进行登记),因此当访问到这个不变的表项时就能确定程序的物理地址(所以叫句柄为指向指针的指针。)

Win32里,句柄是指向一个“无类型对象”(void*)的指针,是一个4字节长的数据。

从构造上看,句柄是一个指针,尽管它没有指向用于存储某个对象的内存位置。事实上,句柄指向一个包含了对该对象进行的引用的位置。

句柄的声明是这样的: 

typedef void *HANDLE 

由于Windows是一个多任务操作系统,它可以同时运行多个程序或一个程序的多个副本,这些运行的程序称为一个实例。为了对同一程序的多个副本进行管理,Windows引入了实例句柄。Windows为每个应用程序建立一张表,实例句柄就好象是这张表的一个索引。 

不同在于: 

1句柄所指的可以是一个很复杂的结构,并且很有可以是与系统有关的,比如说上面所说的线程的句柄,它指向的就是一个类或者结构,他和系统有很密切的关系,当一个线程由于不可预料的原因而终止时,系统就可以回收它所占用的资源,如CPU,内存等;这个句柄中的某一些项,是与系统进行交互的。

2指针也可以指向一个复杂的结构,但通常是用户定义的,所以必需的工作都要用户完成,特别是在删除的时候。

3、视类窗口始终覆盖在框架类窗口之上,所以,我们的鼠标操作一般由视类窗口捕获。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MFC(Microsoft Foundation Classes)是一组用于开发 Windows 应用程序的 C++ 类库。在 MFC 中,消息映射是一种机制,用于将 Windows 消息与相应的消息处理函数关联起来。 消息映射是通过在类的消息映射表中定义消息处理函数来实现的。消息映射表是一个由宏定义和消息映射项组成的静态数组。每个消息映射项指定了一个 Windows 消息的 ID 和相应的消息处理函数。 消息处理函数是类中的成员函数,用于处理特定的 Windows 消息。当一个窗口接收到一个消息时,MFC 会根据消息映射表中的定义找到对应的消息处理函数,并执行该函数来处理该消息。 下面是一个简单的示例,展示了如何使用消息映射消息处理函数: ```cpp // 声明消息映射表 BEGIN_MESSAGE_MAP(CMyWnd, CWnd) ON_WM_PAINT() ON_WM_LBUTTONDOWN() END_MESSAGE_MAP() // 定义消息处理函数 void CMyWnd::OnPaint() { // 处理 WM_PAINT 消息 // ... } void CMyWnd::OnLButtonDown(UINT nFlags, CPoint point) { // 处理 WM_LBUTTONDOWN 消息 // ... } ``` 在上面的示例中,`CMyWnd` 是一个继承自 `CWnd` 的自定义窗口类。通过在消息映射表中使用 `ON_WM_PAINT` 宏和 `ON_WM_LBUTTONDOWN` 宏,将 `OnPaint` 函数和 `OnLButtonDown` 函数与 `WM_PAINT` 消息和 `WM_LBUTTONDOWN` 消息关联起来。 当窗口接收到相应的消息时,就会调用对应的消息处理函数进行处理。 需要注意的是,消息映射表中的消息处理函数必须是类的成员函数,并且符合特定的函数签名。 希望这个简单的解释能够帮助你理解 MFC 中的消息映射消息处理机制。如果还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值