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