几个重要的结构体:

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. 关于Oracle中sys、system和Scott用户下的数据库连接问题

    system默认:manager sys默认:change_on_install 使用SQL Plus登录数据库时,system使用密码manager可直接登录. 由于为自己的密码时更改过的,所以我的 ...

  2. CSS学习摘要-盒子模型

    注:全文摘要自网络开发者网站,当然间隔也会整理一些思路和格式排版添加进去. CSS框模型(译者注:也被称为"盒模型")是网页布局的基础 --每个元素被表示为一个矩形的方框,框的内容 ...

  3. 开源作业调度框架 - Quartz.NET - 实战使用1

    简介: 第一步:下载Quartz.NET 下载Quartz.NET只需要打开网址选择适宜的版本进行下载解压缩即可. 目前最新版本是2.3.3,压缩包为6MB,不过鉴于国内网速.我还是加一下博客园的下载 ...

  4. 团队作业4(Alpha版本)

    项目名称:音乐播放器 项目成员: 张慧敏(201421122032) 苏晓薇(201421031033) 欧阳时康(201421122050) 会议记录:  主要讨论任务的分配和实现过程中已实现和未实 ...

  5. 如何确定PHP CLI 的php.ini文件的位置

    当我们安装扩展时,可能需要手动配置php.ini文件,把扩展加进去,所以要确认PHP CLI的php.ini文件的位置.可以运行php --ini查找PHP CLI的ini文件位置,结果类似如下(各个 ...

  6. Css中路径data用法

    Data URI scheme是在RFC2397中定义的,目的是将一些小的数据,直接嵌入到网页中,从而不用再从外部文件载入. data:,文本数据 data:text/plain,文本数据 data: ...

  7. 用python解析word文件(一):paragraph

    太长了,我决定还是拆开三篇写.   (一)段落篇(paragraph)(本篇) (二)表格篇(table) (三)样式篇(style) 选你所需即可.下面开始正文. 最近公司的项目,需要在页面上显示w ...

  8. ali验证码推送接口调用

    /** * 发送接口 * @param $info 发送信息的某些参数 * @return bool */ public function send($info) { $config = target ...

  9. PostgreSQL学习----模式schema

    PostgreSQL学习---模式schema 小序 接触PostgreSQL也有好长时间了,知识不总结梳理,似乎总不是自己的,继续努力吧少年!以此记录我的软件工艺之路! 模式(Schema) 一个 ...

  10. beautifulsoup4-4.3.2的安装

    下载地址:https://www.crummy.com/software/BeautifulSoup/bs4/download/4.5/ 安装成功,亲测可用! 参考文章http://blog.csdn ...