本章将会对MFC的消息映射和 命令传递机制做深入探讨。

MFC规定了消息传递的路线,消息会按照这个路线传递下去,找不到归宿的话就交给DefWindowProc。

在产生窗口之前,如果我们在创建窗口时指定的窗口类为NULL时,MFC会自动注册五个默认的窗口类,每个窗口类有自己的窗口函数。不同窗口得到的消息应该交由不同的窗口函数来处理。所谓的命令传递机制是为了让消息的流动有线路可循,实现一个巨大的网,实现所有可能的路线。这就是所谓的消息映射图。

WM_COMMAND是来自菜单或工具栏,被称为命令消息。wParam记录着这一消息来自哪个菜单项目。

除了命令消息控件传给父窗口的消息,也是以WM_COMMAND类型的,但是它们被称为notification消息。

Command target即命令的目的地。因此所有派生自CCmdTarget类的类都可以处理命令消息。

派生自CWnd的类可以处理一般的windows消息和COMMAND消息。

DECLARE_MESSAGE_MAP()

BEGIN_MESSAGE_MAP

ON_COMAMND()

END_MESSAGE()

这些宏实现了消息和消息处理函数的映射,不再介绍哦。

在BEGIN和END之间除了ON_COMMAND之外,还可以有其他的形式,标准的windows消息并不需要我们指定处理函数的名称。如:

ON_WM_CHAR();WM_CHAR     OnChar

ON_WM_CLOSE();   WM_CLOSE   OnClose

ON_WM_CREATE();  WM_CREATE  OnCreate

这些宏MFC已经定义好,将标准的消息和消息处理函数对应起来。

AFX_DAT,AFX_DATADEF,AFX_MSG_CALL和afx_msg一样现在还没有被使用。

虽然所有继承自CCmdTarget的类都可以处理命令消息,都应该有DECLARE_MESSAGE_MAP。。。但是CWinThread却没有。它不参与消息处理。因此CWinApp在填写消息映射表是就会跳过CWinThread。

DECLARE_MESSAGE_MAP(CWinApp,CCmdTarget);

消息映射表有C++多态的味道,但是MFC却没有使用多态来实现它,究其原因估计是多态会导致很大的负担。

前面的介绍中,以AfxWinProc作为起点,此处MFC仍以此作为开始,但是却省略了很多的细节。通常消息是在消息队列中等待窗口抓取,但是MFC安装了钩子,就可以提前抓取或抓取不是自己的消息。这是在所有派生自CWnd的对象创建之际发生的。如:

Bool CWnd::CreateEx()

{

。。。

AfxHookWindowCreate(this);

HWND hWnd=::CreateWindowEx();

...

}

AfxHookWindowCreate安装了WH_CBT类型的钩子,任何窗口显示之前,注册的钩子函数会被调用。

细节不再深入介绍,只要知道以上这些干了些偷天换日的勾当,把注册窗口类时注册的窗口函数,更换为AfxWndProc。于是AfxWndProc便是DispatchMessage的目的地。之所以弄得这么复杂书上说是为了兼容什么3D constrols。不懂,暂且放这儿吧。记住结论就是了。

上面可以知道AfxWndProc是消息的源头,这在前面几张也提到过。在此函数内部会调用AfxClassWndProc,后者会调用pWnd->WindowProc();在整个MFC中拥有windowProc的类有CWnd,CControlBar,COleControl,CDialog......具体调用谁的WindowProc要看pWnd 的类型。

在CWnd::windowProc中会调用OnWndMsg函数,它是用来分辨并处理消息的专职机构。如果是命令就交给OnCommand处理,如果是通知消息就交给OnNotify处理。之所以要区分命令消息和通知消息是因为它们的上溯路径并不是单纯的只往父类上去,可能有其他路径。而一般的windows消息却沿着直线上溯。

在OnCommand又调用了OnCmdMsg函数。具体调用哪个OnCommand,OnCmdMsg也是不定的,也得看this指针的类型。OnCmdMsg它是专门处理命令消息的函数。

bool CFrameWnd::OnCmdMsg(UINT nID,int nCode)

{

CView*pView=GetActiveView();

if(pView->OnCmdMsg(nID,nCode))//处理则返回否则继续传递。

return true;

if(CWnd::OnCmdMsg(nID,nCode))

return true;

CWinApp*pApp=AfxGetApp();

if(pApp->OnCmdMsg(nID,nCode)

return true;

return fasle;

}

bool CView::OnCmdMsg(UINT nID,int nCode)

{

cout<<"CView::OnCmdMsg()"<<endl;

if(CWnd::OnCmdMsg(nID,nCode))

return true;

bool bHandled=false;

bHandled=m_pDocument->OnCmdMsg(nID,nCode);

return bHandled;

}

Bool CDocument::OnCmdMsg(UINT nID,int nCode)

{

cout<<"CDocument::OnCmdMsg()"<<endl;

if(CCmdTarget::OnCmdMsg(nID,nCode))

return true;

return false;

}

以上就是消息的传递路线,这里跟第三章模拟的命令传递路线是相同的,具体可以第三章。

OnCmdMsg是各类专门对付命令消息的函数。本类处理过后又会调用下一个类的OnCmdMsg,这样命令消息就会不断传递下去。

如果MDI主窗口接收到一个命令消息,主窗口会把消息传递给CMDIChildWnd子窗口。子窗口传递给它对应的视图,视图检查自己的消息映射表,如果没有找到对应项,将其传递给document。Document检查自己的消息 映射表,找到对应项则调用该函数,消息传递 结束。如果没有找到继续传递,document把该消息传递到document template对象。如果还是没有找到,则传回到view,view将其传递给MDI子窗口本身。继续传递给CWinApp,交给 默认的消息处理函数。

在定义CRuntimeClass时,MessageMapEntries内定义了消息函数的指针类型,

typedef void(AFX_MSG_CALL

CCmdTarget:::*AFX_PMSG)(void);

此时消息处理函数指针类型为返回值为空,参数为空,这是不符合实际的,实际使用中会经过类型转换,使其可以接收参数和返回值。

由于消息处理函数的类型各异,MFC使用了AfxSig_来说明消息处理函数的类型。在找到某消息的消息处理函数之后,判断其类型再进行响应转换。

union MessageMapFunctions mmf;

mmf.pfn=lpEntry->pfn;

switch(lpEntry->nSig)

{

case AfxSig_isg:

lResult=(this->*mmf.pfn_is)(LPTSTR)lParam);

break;

case Afx_Sig_lwl:

lResult=(this->*mmf.pfn_lwl)(wParam,lParam);

break;

case AfxSig_vv:

(this->*mmf.pfn_vv)();

break;

........

}

AfxSig_is代表参数为LPTSTR字符串,返回值为int.

Afx_lwl代表参数wiewParam和lParam。返回值为LRESULT。

Afx_vv代表参数和返回值都为void.

(this->*mmf.pfn_vv)();中的pfn_vv是union MessageMapFunctions的一个成员。如

union MessageMapFunctions

{

AFX_PMSG  pfn;

bool (AFX_MSG_CALL CWnd::*pfn_bD)(CDC*);

void (AFX_MSG_CALL CWnd::*pfn_VV)(CDC*);

.............

};

注意MessageMapFunctions是union类型的哦。

真是佩服当年MFC开发人员的智慧!!!!!

深入浅出MFC学习笔记 消息的更多相关文章

  1. 深入浅出MFC学习笔记 第三章 MFC六大关键技术之仿真

    0:MFC类层次结构 1:MFC程序的初始化过程CWinApp::InitApplication()CMyWinApp::InitInstance()CMyFrameWnd::CMyFrameWnd( ...

  2. MFC 学习笔记

    MFC 学习笔记 一.MFC编程基础: 概述: 常用头文件: MFC控制台程序: MFC库程序: 规则库可以被各种程序所调用,扩展库只能被MFC程序调用. MFC窗口程序: 示例: MFC库中类的简介 ...

  3. Storm学习笔记 - 消息容错机制

    Storm学习笔记 - 消息容错机制 文章来自「随笔」 http://jsynk.cn/blog/articles/153.html 1. Storm消息容错机制概念 一个提供了可靠的处理机制的spo ...

  4. objc_msgSend消息传递学习笔记 – 消息转发

    该文是 objc_msgSend消息传递学习笔记 – 对象方法消息传递流程 的基础上继续探究源码,请先阅读上文. 消息转发机制(message forwarding) Objective-C 在调用对 ...

  5. MFC学习笔记1---准备工作

    什么是MFC MFC,全称Microsoft Foundation Classes,微软基础类库,顾名思义,是微软的攻城狮们将一些常用的基础的Windows API 函数用C++的形式封装成类,简化程 ...

  6. 【MFC学习笔记-作业7-小型画图软件】【】

    作业要求: 按下鼠标右键画圆. 按下鼠标左键移动曲线. 丝毫没有思路..网上教程又比这个程序复杂100倍... 好吧 总算找到一个合适的了... 转载至:http://blog.chinaunix.n ...

  7. Nodejs全站开发学习系列 & 深入浅出Node学习笔记 & Spider抓取

    https://course.tianmaying.com/node 这个系列的文章看起来很不错,值得学习一下. /Users/baidu/Documents/Data/Interview/Web-S ...

  8. MFC学习笔记2---简单计算器

    前言 学习了鸡啄米网页的前三部分后,我们就可以做一个小软件出来了,我选择先做一个计算器. 这是Win7系统自带的计算器: 为了提升成就感,我将计算器的大部分内容去除,于是就变成这样: 这样就只剩下了1 ...

  9. MFC学习笔记(一)

    个人对MFC技术一直都很感兴趣,因为能够做出漂亮绚丽的界面应该是一件十分有成就感的事情. 学习的参考课本为北京博彦科技发展有限责任公司翻译的Jeff Prosise著的<MFC Windows程 ...

随机推荐

  1. LeetCode——Diameter of Binary Tree

    LeetCode--Diameter of Binary Tree Question Given a binary tree, you need to compute the length of th ...

  2. js里面如何才能让成员方法去调用类中其他成员

    function fun(){ var _this = this; //如果函数是用var定义的私有函数,如下 var func1 = function(){ } //那么类中其他函数都可以直接通过f ...

  3. Treflection03_getFields_getField

    1. package reflectionZ; import java.lang.reflect.Constructor; import java.lang.reflect.Field; public ...

  4. window cmd

    切换目录盘  直接 d:  (e:  f:) 在目录下切换文件用cd   文件名(可以加绝对路径 绝对路径可以到复制   也可以加相对路径) javac     XXX.java  编译成字节码 Ja ...

  5. D3.js学习笔记(三)——创建基于数据的SVG元素

    目标 在这一章,你将会使用D3.js,基于我们的数据来把SVG元素添加到网页中.这一过程包括:把数据绑定到元素上,然后在使用这些元素来可视化我们的数据. 注意:不同于前几章,我们从一个完整的代码开始, ...

  6. 新东方雅思词汇---6.3、brilli

    新东方雅思词汇---6.3.brilli 一.总结 一句话总结: 发光 brilliant 英 [ˈbrɪlɪənt]  美 ['brɪljənt]  adj. 灿烂的,闪耀的:杰出的:有才气的:精彩 ...

  7. ES6相关文章

    1.https://www.cnblogs.com/xiaotanke/p/7448383.html (export ,export default 和 import 区别 以及用法)

  8. webservice SOAP WSDL UDDI简介

    WebServices简介 先给出一个概念 SOA ,即Service Oriented Architecture ,中文一般理解为面向服务的架构, 既然说是一种架构的话,所以一般认为 SOA 是包含 ...

  9. Activity Process Task Application 专题讲解

    Activity Process Task Application 专题讲解 Activity.和进程 为了阅读方便,将文档转成pdf http://files.cnblogs.com/franksu ...

  10. [置顶] Kubernetes1.7新特性:新增自动伸缩条件和参数

    一.核心概念 Horizontal Pod Autoscaling,简称HPA,是Kubernetes中实现POD水平自动伸缩的功能.云计算具有水平弹性的特性,这个是云计算区别于传统IT技术架构的主要 ...