《MFC篇》消息映射机制 |
您所在的位置:网站首页 › mfc消息队列长度 › 《MFC篇》消息映射机制 |
消息映射机制
什么是消息映射机制?
MFC使用消息映射机制来处理消息,引入了消息映射表的概念,表中存消息和消息处理函数及二者对应关系。当鼠标点击事件发生时,会产生对应消息,然后去消息映射表中查找对应的消息处理函数并执行。 什么是句柄?句柄相当于一个编号,Windows对于我们来说相当于一个黑盒,我们只能通过这个编号,也就是句柄来获得我们想要的数据。(个人理解,句柄存了一个地址,地址所在位置存储了一些必须的信息,如,调用打印机句柄,获得打印机信息,也可以调用打印功能) 消息机制为什么要使用宏?设计者在设计MFC时,尽可能的使MFC的代码要小,速度尽可能快。为了这个目的,设计师使用了很多奇技淫巧,使用宏就是其中之一。 消息映射机制的宏MFC消息机制的宏有下面几个: // 1、 DECLARE_MESSAGE_MAP() // 2、 BEGIN_MESSAGE_MAP()(theClass,baseClass) // 3、 END_MESSAGE_MAP() DELCARE_MESSAGE_MAPDECLARE_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_MSGMAPXDECLARE_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作用:定义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(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 消息映射机制入门 消息映射中的消息是什么?窗口消息一般由三部分组成: 1、一个无符号整数,是消息值 2、消息附带的WPARAM类型的参数 3、消息附带LPARAM类型的参数。其实我们一般说的消息值,也就是一个无符号整数,经常被定义为宏。 消息映射机制的形象比喻原文链接:https://zhuanlan.zhihu.com/p/489889991 前几天赵工忽然凑到我脸上来,问我晓不晓得MFC的消息机制原理。 当时我正在努力摸鱼,被这猝不及防闯入的笑脸吓的差点打出一套闪电五连鞭。 我说你别逗我了,你干这一行的时间比我吃饭都多,问谁也不应该来问我这菜鸟吧。 赵工笑的脸更大了,一个劲的叫我说说嘛。 我忽然明白过来,他也想摸鱼,那我就不困了。 我们都知道MFC是一种window程序设计,一种基于事件驱动的程序设计模式。 这种事件驱动,主要是消息。 什么叫消息呢? 比如你是键盘侠,那得敲键盘,按下键盘就是消息; 比如你浏览网页,那得用鼠标点击,按下鼠标就是消息; 比如你想看岛国的学习资料,那得有个硬盘吧,插入硬盘就是消息。 在MFC窗口中,我们看到的现象是:我们点了个按钮,触发了消息机制,MFC程序执行了一些我们事先写好的操作。 不过,我们点下按钮或者敲下键盘,首先捕获到这个消息的,并不是程序——而是操作系统。 这就好比你扫微信付款给店家,你以为开开心心付了钱,店家开开心心收到钱了,实际上首先收到这笔钱的,是微信付款的后台系统。 操作系统获取到消息后,就会自动将其存入消息队列中,无论你按了多少个消息,就算是网上重拳出击的键盘侠,发出的每一个键盘消息都会被存入消息队列中。 消息队列这东西只有一个特定,那就是先入先出,先存进去的消息会先被派出去。 想一下,假如十个人给店家付款,先付款的反而店家没有先收到钱,店家慌了,你也慌了,估计怎么也得上演一集霍元甲大战黄飞鸿的好戏。 消息队列一收到存进来消息,高兴坏了,来活了。 它们就负责将消息按照顺序一个一个派送给应用程序,丝毫不敢怠慢,打工人没得选择。 经过了消息——操作系统——消息队列——应用程序,MFC应用程序才在真正接收到了消息。 然后应用程序会把消息再分发给操作系统,让操作系统去执行响应函数。 但是应用程序也做了些东西的,它负责将消息进行翻译,虽然再分发。 为什么要翻译? 很简单啊,就比如说组合键,一套CTRL+C,CTRL+V,你不翻译一下,系统真以为你是想发CTRL,C,CRTL,V这几个信号。 翻译完成后才会分发给操作系统,由操作系统来执行窗口过程。 参考链接:https://blog.csdn.net/li_xunhuan/article/details/105574498 参考链接:https://www.zhihu.com/question/30393750 消息驱动和事件驱动的共同点,都是先有一个事件,事件产生相应的消息,再把消息放入消息队列,由需要的项目获取。他们的区别是消息是谁产生的。 以鼠标点击为例: 1、消息驱动:鼠标只管自己点击,不需要和系统过多的交互,消息由系统(或者第三方程序)循环检测,来捕获消息放入消息队列,消息对于鼠标点击事件来说是被动产生,高内聚。 2、事件驱动:鼠标点击产生点击事件后,要向系统发送消息“我点击了”的消息,消息是主动产生的。再发送到消息队列中。事件往往会将事件源包装起来。 备注:事件源:发生事件的对象。(即当前操作的对象) 消息驱动和事件驱动优缺点: 1、消息驱动耦合低,跨模块好用。 2、事件驱动耦合高,同模块内好用。 3、事件驱动是侵入式的,霸占主循环;消息驱动非侵入式的,将主循环该怎样设计的自由留给用户。 4、如果你在设计一个东西举棋不定,那么可以看看win32的GetMessage,本身就是一个耦合度极低的接口,又足够自由,接口任何语言都很方便,也可以在其基础上再封装成事件驱动。 |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |