从MFC消息映射宏分析MFC消息映射的实现
来源:互联网 发布:王的男人知乎评价 编辑:程序博客网 时间:2024/05/19 16:05
在MFC中,我们可以找到如下三个宏
DECLARE_MASSAGE_MAP()
BEGINE_MASSAGE_MAP(CLASS, BASSCLASS)
END_MASSAGE_MAP()
下面来分析这三个宏
1 DECLARE_MESSAGE_MAP()
作用:为一个消息响应类声明必需的成员变量和成员函数。
#define DECLARE_MESSAGE_MAP()
private:
static const AFX_MSGMAP_ENTRY _messageEntries[];
protected:
static const AFX_MSGMAP messageMap;
virtual const AFX_MSGMAP* GetMessageMap() const;
可以看出DECLARE_MESSAGE_MAP() 宏中定义了两个静态成员函数和一个重载的虚函数
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_PTR nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
{
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_PTR nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
再看看AFX_MESSAGE结构
struct AFX_MSGMAP
{
const AFX_MSGMAP* pBaseMap;
const AFX_MSGMAP_ENTRY* lpEntries;
};
{
const AFX_MSGMAP* pBaseMap;
const AFX_MSGMAP_ENTRY* lpEntries;
};
可见结构体AFX_MSGMAP中定义了两个指针,pBaseMap指向另一个AFX_MSGMAP,lpEntries指向一个消息入口表。可以推想,在响应消息时,一定是在lpEntries指向的消息入口表中寻找响应函数,也可能会在pBaseMap指向的结构体中做同样的响应函数寻找操作(有点不理解)。
重载的虚函数GetMessageMap,可以猜测只是用来返回成员messageMap的地址而已
2 BEGIN_MESSGAE_MAP(CLASS, BASECLASS)
作用:定义DECLARE_MESSAGE_MAP宏声明的静态变量。
#define BEGIN_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[] =
{
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[] =
{
BEGIN_MESSAGE_MAP宏有两个参数,theClass表示为当前类,bassClass为当前类的父类。
BEGIN_MESSAGE_MAP宏首先定义了函数GetMessageMap的函数体,如前文所述,直接返回当前类的成员变量messageMap的地址。
const AFX_MSGMAP* theClass::GetMessageMap() const
{ return &theClass::messageMap; }
{ return &theClass::messageMap; }
然后初始化了当前类的成员变量messageMap。messageMap的pBaseMap指针指向其父类的messageMap成员,lpEntries指针指向当前类的_messageEntries数组的首地址。
AFX_COMDAT const AFX_MSGMAP theClass::messageMap =
{ &baseClass::messageMap, &theClass::_messageEntries[0] };
{ &baseClass::messageMap, &theClass::_messageEntries[0] };
最后,定义了_messageEntries数组初始化代码的开始部分。
AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] =
{
{
第三个宏END_MESSAGE_MAP()
作用:定义_messageEntries数组初始化代码的结束部分。
#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宏为例。ON_COMMAND宏的源代码为:
{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宏为例。ON_COMMAND宏的源代码为:
#define ON_COMMAND(id, memberFxn)
{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSigCmd_v,
static_cast<AFX_PMSG> (memberFxn) },
{ WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSigCmd_v,
static_cast<AFX_PMSG> (memberFxn) },
通过以上分析,我们可以得到一个链表式的数据结构,子类的messageMap成员为链表的头节点。链表的每个节点都包含一个消息入口表。MFC的消息系统的标准备消息处理函数CCmdTarget::OnCmdMsg正是通过这样一个链表查找到消息的响应函数,并调用该函数来响应消息。
- 从MFC消息映射宏分析MFC消息映射的实现
- 从MFC消息映射宏分析MFC消息映射的实现
- MFC消息映射的实现
- MFC消息映射的实现
- MFC 消息映射的实现
- MFC的消息映射宏
- MFC的消息映射
- MFC的消息映射
- MFC的消息映射
- MFC的消息映射
- 【MFC】消息映射宏
- MFC消息映射宏
- 深入分析MFC消息映射
- MFC 消息映射实现原理
- MFC消息映射机制实现
- MFC之消息映射的实现(1)
- MFC之消息映射的实现(2)
- MFC消息映射的实现(转)
- CString、TCHAR*、char*转换
- 了解VS2008 和.NET Framework3.5最主要的十件事
- 数组循环移动代码,只使用一个临时变量
- 关于ulimit的深入思考
- 文件上传
- 从MFC消息映射宏分析MFC消息映射的实现
- linux 下 apache启动、停止、重启命令
- pdo打开sqlserver表失败问题
- 哈哈
- 建模的误区—— 走出一般性的设计误区,迈向成功之途
- 十一黄金周,到科士德嵌入式学院来充电
- 中文化和国际化问题权威解析之一:字符编码发展历程
- 免费学习编程知识。
- Rational Rose和UML可视化建模基础