首页 > 编程语言 >《c++徒步》MFC篇——消息映射机制

《c++徒步》MFC篇——消息映射机制

时间:2023-04-13 09:35:32浏览次数:50  
标签:MAP MFC 映射 MSGMAP c++ AFX 消息 MESSAGE

MFC消息映射机制

什么是消息映射机制?

MFC使用消息映射机制来处理消息,引入了消息映射表的概念,表中存消息消息处理函数二者对应关系。当鼠标点击事件发生时,会产生对应消息,然后去消息映射表中查找对应的消息处理函数并执行。

什么是句柄?

句柄相当于一个编号,Windows对于我们来说相当于一个黑盒,我们只能通过这个编号,也就是句柄来获得我们想要的数据。(个人理解,句柄存了一个地址,地址所在位置存储了一些必须的信息,如,调用打印机句柄,获得打印机信息,也可以调用打印功能)

消息机制为什么要使用宏?

设计者在设计MFC时,尽可能的使MFC的代码要小,速度尽可能快。为了这个目的,设计师使用了很多奇技淫巧,使用宏就是其中之一。

消息映射机制的宏

MFC消息机制的宏有下面几个:

// 1、
DECLARE_MESSAGE_MAP()
// 2、
BEGIN_MESSAGE_MAP()(theClass,baseClass)
// 3、
END_MESSAGE_MAP()

DELCARE_MESSAGE_MAP()

DECLARE_MESSAGE_MAP()宏展开:

#define DECLARE_MESSAGE_MAP()
private:
	static const AX_MSGMAP_ENTRY _messageEntries[];
protected:
	static AFX_DATA const AFX_MSGMAP messageMap;
	virtual const AFX_MSGMAP* GetMessageMap() const;

从上面定义可以看出,DECLARE_MESSAGE_MAP()做了三件事,
(1)定义了一个长度不定的静态数组变量_messageEntries[];
(2)定义了一个静态变量messageMap;
(3)定义了一个虚拟函数GetMessageMap();

AFX_MSGMAP_ENTRY和AFX_MSGMAPX

DECLARE_MESSAGE_MAP()宏中的两个对外不公开的结构struct,即AFX_MSGMAP_ENTRY和AFX_MSGMAPX。
AFX_MSGMAP_ENTRY的定义:

struct AFX_MSGMAP_ENTRY
{
	UNIT nMessage;// windows message
	UNIT nCode;// control code or WM_NOTIFY code
	UNIT nID;// control ID
	UNIT nLastID;// used for entries specifying a range of control id’s
	UNIT nSig;// signature type (action) or pointer to messagge
	AFX_PMSG pfn;// routine to call (or special value)
};

从注释可以看出,AFX_MSGMAP_ENTRY结构实际上定义了消息和处理此消息的函数之间的映射关系。因此静态数组_messageEntries[],实际上定义了一张表,表中每一项指定了消息和消息处理函数的对应关系,也就是消息映射表。nMessage和nCode确定一条消息的内容,nID和nLastID确定了一条消息的来源,nSig和pfn确定了消息处理函数和调用方式。
此外,名字ENTRY也有入口的意思(即消息和消息处理函数之间的映射)。
AFX_MSGMAP的定义:

struct AFX_MSGMAP
	{
		const AFX_MSGMAP* pBaseMap;
		consgt AFX_MSGMAP_ENTRY* lpEntries;
}

AFX_MSGMAP定义了两个指针,pBaseMap指向另一个AFX_MSGMAP,lpEntries指针指向消息映射表_messageEntries。通过这种方式,使得在某个类中调用基类的消息处理函数很容易,因此,“父类的消息处理函数是子类的缺省消息处理函数”就“顺理成章”了。

BEGIN_MESSAGE_MAP(theClass,baseClass)

作用:定义DECLARE_MESSAGE_MAP宏声明的静态变量。

#define BEEGIN_MESSAGE_MAP(theClass,baseClass)
   const AFX_MSGMAP* theClass::GetMessageMap() const 
   {
	return &theClass::messageMap;
   }
   AFX_COMDAT const AFX_MSGMAP theClass::messageMap =
   { &baseClass::messageMap,&theClass::_messageEntries[0]};
   AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[]=
   {
	#define END_MESSAGE_MAP()
	{0,0,0,0,AfxSig_end,(AFX_PMSG)0}
   };

BEGIN_MESSAGE_MAP有两个参数,theClass表示当前类,baseClass表示父类。
BEGIN_MESSAGE_MAO首先定义了函数GetMessageMap的函数体,返回成员变量messageMap的地址。
然后,AFX_COMDAT const AFX_MSGMAP theClass::messageMap=??,初始化了成员变量messageMap。messageMap的pBaseMap指向父类的messageMap,lpEntries指针指向当前类的_messageEntries数组的首地址。
最后,AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[]=??,定义了_messageEntries数组初始化的开始部分代码, 即一个“{”。

END_MESSAGE_MAP()

作用:定义_messageEntries数组初始化的结束部分代码,即“{0,0,0,0,AfxSig_end,(AFX_PMSG)0} };”

#define END_MESSAGE_MAP()
   {0,0,0,0,AfxSig_end,(AFX_PMSG)0}
	 };

其他宏

在DECLARE_MESSAGE_MAP和END_MESSAGE_MAP之间还有一些宏,如ON_COMMAND、ON_WM_CREATE等,这些宏最终都会被生成一条AFX_MSGMAP_ENTRY结构的数据,并成为消息映射表_messageEntries的一个元素。
以ON_COMMAND宏为例:

#define ON_COMMAND(id,memberFxn)
	{
		WM_COMMAND, CN_COMMAND, (WORD)id,(WORD)id, AfxSigCmd_v,
		static_cast<AFX_PMSG>(memberFxn)
	}

参考
https://blog.csdn.net/weixin_42083441/article/details/109726786
https://www.jianshu.com/p/c1cdba489b88
https://www.cnblogs.com/zzw19940404/p/14008341.html
https://blog.csdn.net/lovemysea/article/details/74893961
https://blog.csdn.net/zhangchuan7758/article/details/121653589

消息映射机制的形象比喻

原文链接:https://zhuanlan.zhihu.com/p/489889991

前几天赵工忽然凑到我脸上来,问我晓不晓得MFC的消息机制原理。

当时我正在努力摸鱼,被这猝不及防闯入的笑脸吓的差点打出一套闪电五连鞭。

我说你别逗我了,你干这一行的时间比我吃饭都多,问谁也不应该来问我这菜鸟吧。

赵工笑的脸更大了,一个劲的叫我说说嘛。

我忽然明白过来,他也想摸鱼,那我就不困了。

我们都知道MFC是一种window程序设计,一种基于事件驱动的程序设计模式。

这种事件驱动,主要是消息。

什么叫消息呢?

比如你是键盘侠,那得敲键盘,按下键盘就是消息;

比如你浏览网页,那得用鼠标点击,按下鼠标就是消息;

比如你想看岛国的学习资料,那得有个硬盘吧,插入硬盘就是消息。

在MFC窗口中,我们看到的现象是:我们点了个按钮,触发了消息机制,MFC程序执行了一些我们事先写好的操作。

不过,我们点下按钮或者敲下键盘,首先捕获到这个消息的,并不是程序——而是操作系统。

这就好比你扫微信付款给店家,你以为开开心心付了钱,店家开开心心收到钱了,实际上首先收到这笔钱的,是微信付款的后台系统。

image

操作系统获取到消息后,就会自动将其存入消息队列中,无论你按了多少个消息,就算是网上重拳出击的键盘侠,发出的每一个键盘消息都会被存入消息队列中。

消息队列这东西只有一个特定,那就是先入先出,先存进去的消息会先被派出去。

想一下,假如十个人给店家付款,先付款的反而店家没有先收到钱,店家慌了,你也慌了,估计怎么也得上演一集霍元甲大战黄飞鸿的好戏。

image

消息队列一收到存进来消息,高兴坏了,来活了。

它们就负责将消息按照顺序一个一个派送给应用程序,丝毫不敢怠慢,打工人没得选择。

经过了消息——操作系统——消息队列——应用程序,MFC应用程序才在真正接收到了消息。

image

然后应用程序会把消息再分发给操作系统,让操作系统去执行响应函数。

但是应用程序也做了些东西的,它负责将消息进行翻译,虽然再分发。

image

为什么要翻译?

很简单啊,就比如说组合键,一套CTRL+C,CTRL+V,你不翻译一下,系统真以为你是想发CTRL,C,CRTL,V这几个信号。

翻译完成后才会分发给操作系统,由操作系统来执行窗口过程。

image

标签:MAP,MFC,映射,MSGMAP,c++,AFX,消息,MESSAGE
From: https://www.cnblogs.com/fusio/p/17312209.html

相关文章

  • ARM64页表映射
    1.ARMv8-A架构基于ARMv8-A架构的处理器最大可以支持到48根地址线,也就是寻址2的48次方的虚拟地址空间,即虚拟地址空间范围为0x0000_0000_0000_0000~0x0000_FFFF_FFFF_FFFF,共256TB。一个是从0x0000_0000_0000_0000到0x0000_FFFF_FFFF_FFFF,另外一个是从0xFFFF_0000_0000_0000到0xFFFF......
  • 第十四届蓝桥杯省赛c/c++大学B组 试题A:日期统计(无深搜暴力求解)
    试题A:日期统计本题总分:5分【问题描述】小蓝现在有一个长度为100的数组,数组中的每个元素的值都在0到9的范围之内。数组中的元素从左至右如下所示:56869161249198236477595038758158618303792705885709919446......
  • Docker介绍下载安装、制作镜像及容器、做目录映射、做端口映射
    在计算机中,虚拟化(英语:Virtualization)是一种资源管理技术,是将计算机的各种实体资源,如服务器、网络、内存及存储等,予以抽象、转换后呈现出来,打破实体结构间的不可切割的障碍,使用户可以比原本的组态更好的方式来应用这些资源。这些资源的新虚拟部份是不受现有资源的架设方式,地域或物......
  • C++文件处理
    ......
  • Mybatis-关联关系映射
    1.一对多 1.1.导入数据表--一对多--客户表(主表)createtablet_customer(customer_idintprimarykeynotnullauto_increment,customer_namevarchar(50)notnull);--多对一--订单表(从表)createtablet_order(order_idintprimarykeynotnull......
  • MFC-ASSERT条件为真继续执行,条件为假中断执行
     CStringstr;inti=10;ASSERT(i==10);//条件为真继续执行,条件为假中断执行str.Format(_T("i=10为真"));::OutputDebugString(str);//ASSERT(i<10);str.Format(_T("i<10为假"));::OutputDebugString(str); ......
  • c++ new和malloc
    1、new/delete是C++关键字,需要编译器支持。malloc/free是库函数,需要头文件支持;2、使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸。3、new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对......
  • c++指针参数传递和引用参数传递的区别
    1) 指针参数传递本质上是值传递,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,会在栈中开辟内存空间以存放由主调函数传递进来的实参值,从而形成了实参的一个副本(替身)。值传递的特点是,被调函数对形式参数的任何操作都是作为局部变量进行的,......
  • MSBUILD : error MSB3428: Could not load the Visual C++ component "VCBuild.exe".
    完整报错信息:MSBUILD:errorMSB3428:CouldnotloadtheVisualC++component"VCBuild.exe".Tofixthis,1)installthe.NETFramework2.0SDK,2)installMicrosoftVisualStudio2005or3)addthelocationofthecomponenttothesystempathifit......
  • C++第二章课后习题2-29,2-30
    2-29在程序中定义一个整型变量,倔以1~100的值。要求用户猜这个数,比较两个数的大小,把结果提示给用户,直到猜对为止。分别使用while、do…while语句实现循环。#include<iostream>usingnamespacestd;intmain(){inta=56;cout<<"请输入您要猜的数(0......