几个重要的结构体:

struct AFX_MSGMAP
{
AFX_MSGMAP* pBaseMessageMap;
AFX_MSGMAP_ENTRY* lpEntries;
}

 

struct AFX_MSGMAP_ENTRY
{
UINT nMessage;// Windows消息
UINT nCode;// 控制消息的通知码
UINT nID;// 其控制组件的ID
UINT nLastID;// 如果是一定范围的消息映射,此值表示区间的最大值
UINT nSig; // 消息的动作标识
AFX_MSG pfn;// 消息响应函数
}

此结构体的数据由任何一个ON_宏都会把这六个数据初始化,例如 此处的ON_WM_CREATE 和 下面提到的ON_COMMAND:

#define ON_WM_CREATE() \
{ WM_CREATE, 0, 0, 0, AfxSig_is, (AFX_MSG)(AFX_PMSGW)(int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT)OnCreate) },

  

AFX_PMSG 是一个函数指针:

typedef void (CCmdTarget::* AFX_PMSG)(void);

定义一个DECLARE_MESSAGE_MAP()宏

#define DECLARE_MESSAGE_MAP() \
static AFX_MSGMAP_ENTRY _messageEntries[] ;\
static AFX_MSGMAP messageMap; \
virtual AFX_MSGMAP* GetMessageMap() const;

于是DECLARE_MESSAGE_MAP宏就相当于声明了下面的数据结构:

  

  

 这个数据结构的内容填充工作由下面三个宏完成:

#define BEGIN_MESSAGE_MAP (theClass,baseClass) \
AFX_MSGMAP* theClass::GetMessageMap() const \
{ return &theClass::messageMap; }\
AFX_MSGMAP theClass::messageMap = \
{
&(baseClass::messageMap), \
(AFX_MSGMAP_ENTRY*) &(theClass::_messageEntries) ; \
} \
AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \
{
#define ON_COMMAND(id,memberFxn) \
{ WM_COMMAND, 0, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)memberFxn },
#define END_MESSAGE_MAP() \
{ 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0} \
};

这个AfxSig枚举的具体作用是什么呢?

上面的宏ON_WM_CREATE和ON_COMMAND也有出现类似的AfxSig_,那么到底作何用处?

从上面两个宏的最后一个参数可以看出,表示的是具体的执行函数,且都进行了类型转换,最终转换为AFX_PMSG.

可是AFX_PMSG的定义呢?我们再写一遍。

typedef void (CCmdTarget::* AFX_PMSG)(void);

这是一个什么鬼?无参,无返回值,不可能所有的函数都如此吧?

这正是AfxSig_的作用所在,当需要调用AFX_MSGMAP_ENTRY中的消息响应函数pfn的时候,具体的动作是这样的(出现在wincore.cpp CWnd::OnWndMsg 和 DispatchCmdMsg中):

union MessageMapFunctions mmf;
mmf.pfn = lpEntry->pfn; // lpEntry 是AFX_MSGMAP_ENTRY的对象
switch(lpEntry->nSig)
{
case AfxSig_is:
lResult = (this->*mmf.pfn_is)((LPTSTR)lParam);
break;
case AfxSig_lwl:
lResult = (this->*mmf.pfn_lwl)(wParam, lParam);
break;
case AfxSig_vv:
lResult = (this->*mmf.pfn_vv)();
break;
.....
}

重点注意: MessageMapFunctions 和AfxSig_. AfxSig_ 定义位于AFXMSG_.H档。

enum AfxSig
{
AfxSig_end = 0, // [marks end of message map] AfxSig_b_D_v, // BOOL (CDC*)
AfxSig_b_b_v, // BOOL (BOOL)
AfxSig_b_u_v, // BOOL (UINT)
AfxSig_b_h_v, // BOOL (HANDLE)
AfxSig_b_W_uu, // BOOL (CWnd*, UINT, UINT)
AfxSig_b_W_COPYDATASTRUCT, // BOOL (CWnd*, COPYDATASTRUCT*)
AfxSig_b_v_HELPINFO, // BOOL (LPHELPINFO);
AfxSig_CTLCOLOR, // HBRUSH (CDC*, CWnd*, UINT)
AfxSig_CTLCOLOR_REFLECT, // HBRUSH (CDC*, UINT)
AfxSig_i_u_W_u, // int (UINT, CWnd*, UINT) // ?TOITEM
AfxSig_i_uu_v, // int (UINT, UINT)
AfxSig_i_W_uu, // int (CWnd*, UINT, UINT)
AfxSig_i_v_s, // int (LPTSTR)
AfxSig_l_w_l, // LRESULT (WPARAM, LPARAM)
AfxSig_l_uu_M, // LRESULT (UINT, UINT, CMenu*)
.... // 后面很多不列举
};

MessageMapFunctions 定义于WINCORE.cpp 中:

union MessageMapFunctions
{
AFX_PMSG pfn; // generic member function pointer BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_D)(CDC*);
BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_b)(BOOL);
BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_u)(UINT);
BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_h)(HANDLE);
BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_W_u_u)(CWnd*, UINT, UINT);
BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_W_COPYDATASTRUCT)(CWnd*, COPYDATASTRUCT*);
BOOL (AFX_MSG_CALL CCmdTarget::*pfn_b_HELPINFO)(LPHELPINFO);
HBRUSH (AFX_MSG_CALL CCmdTarget::*pfn_B_D_W_u)(CDC*, CWnd*, UINT);
HBRUSH (AFX_MSG_CALL CCmdTarget::*pfn_B_D_u)(CDC*, UINT);
int (AFX_MSG_CALL CCmdTarget::*pfn_i_u_W_u)(UINT, CWnd*, UINT);
int (AFX_MSG_CALL CCmdTarget::*pfn_i_u_u)(UINT, UINT);
int (AFX_MSG_CALL CCmdTarget::*pfn_i_W_u_u)(CWnd*, UINT, UINT);
int (AFX_MSG_CALL CWnd::*pfn_i_s)(LPTSTR);
int (AFX_MSG_CALL CWnd::*pfn_i_S)(LPCTSTR);
LRESULT (AFX_MSG_CALL CWnd::*pfn_l_w_l)(WPARAM, LPARAM);
LRESULT (AFX_MSG_CALL CWnd::*pfn_l_u_u_M)(UINT, UINT, CMenu*);
	....  // 后面很多不列举
};

其实真正的函数只有pfn一个,但通过union后,它就有了许多类型不同的形象。这里可以看出union自动转型的作用。  

//***********************************************************************************************

上面讲基本内容解释完毕,下面以实例来演示宏展开后的结果:

//in header file
class CView : public CWnd
{
public:
//...
DECLARE_MESSAGE_MAP()
}; //in implementation file
#define CViewid 122
//...
BEGIN_MESSAGE_MAP(CView, CWnd)
ON_COMMAND(CViewid, 0)
END_MESSAGE_MAP //被展开之后为 //in header file
class CView : public CWnd
{
public:
//...
static AFX_MSGMAP_ENTRY _messageEntries[];
static AFX_MSGMAP messageMap;
virtual AFX_MSGMAP* GetMessageMap() const;
}; //in implementation file
AFX_MSGMAP* CView::GetMessageMap() const
{
return &CView::messageMap;
} AFX_MSGMAP CView::messageMap = { &(CWnd::messageMap), (AFX_MSGMAP_ENTRY*)&(CView::_messageEntries) }; AFX_MSGMAP_ENTRY CView::_messageEntries[] = {
{WM_COMMAND, 0, (WORD)122, (WORD)122, 1, (AFX_MSGMAP)0},
{0, 0, 0, 0, 0, (AFX_MSGMAP)0}
};

以图表示则为:

  

MFC中定义了各种类似ON_COMMAND这样的宏,把各式各样的消息与特定的消息处理函数关联起来。

下面的代码中每一个CCmdTarget的衍生类都产生类似上图的消息映射表:

//in head file
class CObject
{
//....
//注意:CObject并不属于消息流动网的一份子
}; class CCmdTarget :public CObject
{
//...
DECLARE_MESSAGE_MAP()
}; class CWinThread :public CCmdTarget
{
//...
//注意:CWinThread并不属于消息流动网的一份子
}; class CWinApp :public CWinThread
{
//...
DECLARE_MESSAGE_MAP()
}; class CDocument :public CCmdTarget
{
//...
DECLARE_MESSAGE_MAP()
}; class CWnd :public CCmdTarget
{
//...
DECLARE_MESSAGE_MAP()
}; class CFrameWnd :public CWnd
{
//...
DECLARE_MESSAGE_MAP()
}; class CView :public CWnd
{
//...
DECLARE_MESSAGE_MAP()
}; class CView :public CWnd
{
//...
DECLARE_MESSAGE_MAP()
}; class CMyWinApp :public CWinApp
{
//...
DECLARE_MESSAGE_MAP()
}; class CMyFrameWnd :public CFrameWnd
{
//...
DECLARE_MESSAGE_MAP()
}; class CMyDoc :public CDocument
{
//...
DECLARE_MESSAGE_MAP()
}; class CMyView :public CView
{
//...
DECLARE_MESSAGE_MAP()
};
//in implementation file
BEGIN_MESSAGE_MAP(CWnd, CCmdTarget)
ON_COMMAND(CWndid, 0)
END_MESSAGE_MAP BEGIN_MESSAGE_MAP(CFrameWnd, CWnd)
ON_COMMAND(CFrameWndid, 0)
END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CDocument, CCmdTarget)
ON_COMMAND(CDocumentid, 0)
END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CView, CWnd)
ON_COMMAND(CViewid, 0)
END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CWinApp, CCmdTarget)
ON_COMMAND(CWinAppid, 0)
END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CMyWinApp, CWinApp)
ON_COMMAND(CMyWinAppid, 0)
END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
ON_COMMAND(CMyFrameWndid, 0)
END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CMyDoc, CDocument)
ON_COMMAND(CMyDocid, 0)
END_MESSAGE_MAP() BEGIN_MESSAGE_MAP(CMyView, CView)
ON_COMMAND(CMyViewid, 0)
END_MESSAGE_MAP() //同时也设定了消息的终极标靶CCmdTarget的映射表内容:
AFX_MSGMAP CCmdTarget::messageMap =
{
NULL,
&CCmdTarget::_messageEntries[0]
}; AFX_MSGMAP_ENTRY CCmdTarget::_messageEntries =
{
{0, 0, CCmdTargetid, 0, AfxSig_end, 0 }
}

以上构成了完整的消息流动网,如下图:

 

MFC 消息映射、分派和传递的更多相关文章

  1. MFC消息映射与命令传递

    题外话:刚开始学视窗程序设计的时候,我就打印了一本Windows消息详解,里面列举了各种已定义消息的意义和作用,共10多页,在编程的时候翻翻,有时觉得很受用.我发觉很多编程的朋友,虽然每天都面对消息, ...

  2. 深入浅出MFC——消息映射与命令传递(六)

    1. 消息分类: 2. 万流归宗——Command Target(CCmdTarget): 3. "消息映射"是MFC内建的一个信息分派机制.通过三个宏(DECLARE_MESSA ...

  3. 剖析MFC六大关键技术(五六)--消息映射与命令传递

    说到消息,在MFC中,“最熟悉的神秘”可算是消息映射,那是我们刚开始接触MFC时就要面对的东西.有过SDK编程经验的朋友转到MFC编程的时候,一下子觉得什么都变了样.特别是窗口消息及对消息的处理跟以前 ...

  4. MFC六大核心机制之五、六:消息映射和命令传递

    作为C++程序员,我们总是希望自己程序的所有代码都是自己写出来的,如果使用了其他的一些库,也总是千方百计想弄清楚其中的类和函数的原理,否则就会感觉不踏实.所以,我们对于在进行MFC视窗程序设计时经常要 ...

  5. MFC消息映射的原理:笔记

    多态的实现机制有两种,一是通过查找绝对位置表,二是查找名称表:两者各有优缺点,那么为什么mfc的消息映射采用了第二种方法,而不是c++使用的第一种呢?因为在mfc的gui类库是一个庞大的继承体系,而里 ...

  6. MFC技术内幕系列之(四)---MFC消息映射与消息传递内幕

    ////////////////////////////////////////////////////////////////////////////////////                 ...

  7. MFC消息映射机制以及画线功能实现

    ---此仅供用于学习交流,切勿用于商业用途,转载请注明http://www.cnblogs.com/mxbs/p/6213404.html. 利用VS2010创建一个单文档标准MFC工程,工程名为Dr ...

  8. MFC编程入门之五(MFC消息映射机制概述)

    在MFC软件开发中,界面操作或者线程之间通信都会经常用到消息,通过对消息的处理实现相应的操作.比较典型的过程是,用户操作窗口,然后有消息产生,送给窗口的消息处理函数处理,对用户的操作做出响应. 一.什 ...

  9. VS2010/MFC编程入门之五(MFC消息映射机制概述)

    VS2010/MFC编程入门之五(MFC消息映射机制概述)-软件开发-鸡啄米 http://www.jizhuomi.com/software/147.html 上一讲鸡啄米为大家简单分析了MFC应用 ...

  10. MFC消息映射机制

    1.MFC应用框架主要类之间的关系 MFC自动生成的框架中重要的类有:C-App.CMainFrame.C-Doc和C-View. 其他的类如CClassView.CFileView等都是在框架窗口( ...

随机推荐

  1. 【Kettle】1、简单介绍

    本人为转载,感谢作者的辛勤劳作:http://blog.csdn.net/rotkang/article/details/20810921 ------------------------------ ...

  2. MySQL存储引擎之Spider内核深度解析

      作者介绍 朱阅岸,中国人民大学博士,现供职于腾讯云数据库团队.研究方向主要为数据库系统理论与实现.新硬件平台下的数据库系统以及TP+AP型混合系统. Spider是为MySQL/MariaDB开发 ...

  3. 辉光UIView的category

    辉光UIView的category 本人视频教程系类   iOS中CALayer的使用 效果如下: 源码: UIView+GlowView.h 与 UIView+GlowView.m // // UI ...

  4. 显示脉冲效果的PulsingView

    显示脉冲效果的PulsingView 效果如下: 源码: PulsingView.h 与 PulsingView.m // // PulsingView.h // PulsingView // // ...

  5. 1251. 序列终结者【平衡树-splay】

    Description 网上有许多题,就是给定一个序列,要你支持几种操作:A.B.C.D.一看另一道题,又是一个序列 要支持几种操作:D.C.B.A.尤其是我们这里的某人,出模拟试题,居然还出了一道这 ...

  6. Kafka设计解析(十一)Kafka无消息丢失配置

    转载自 huxihx,原文链接 Kafka无消息丢失配置 目录 一.Producer端二.Consumer端 Kafka到底会不会丢数据(data loss)? 通常不会,但有些情况下的确有可能会发生 ...

  7. HDU1753 (大正小数相加)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1753 大明A+B Time Limit: 3000/1000 MS (Java/Others)    ...

  8. 原生JavaScript技巧大收集

    原生JavaScript技巧大收集 地址:http://itindex.net/detail/47244-javascript

  9. 测试oracle表空间自动扩展

    2019-04-1116:01:25 表空间分配10m自动扩展,向表中插入数据,看表空间达到10m以后是否会报错. 测试过程如下: 1.创建表空间 CREATE TABLESPACE TEST DAT ...

  10. 断言NSAssert的使用

    1. NSAssert 断言(NSAssert)是一个宏,在开发过程中使用NSAssert可以及时发现程序中的问题. NSAssert声明如下: #define NSAssert(condition, ...