本章将会对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学习笔记 ithzhang CSDN博客:http://blog.csdn.net/ithzhang/article/category/1159054 转载于:https://blog. ...

  2. 21、深入浅出MFC学习笔记,Application Framework简介

    1.Application Framework是一个完整的程序模型:是一组合作无间的对象,彼此藉消息的流动而沟通,并且互相调用对方的函数以求完成任务.<?xml:namespace prefix ...

  3. 28、深入浅出MFC学习笔记,View功能的加强和重绘效率的提高

    1.同一份Document的多个views,在Document的一个view改变了后,如何同步其它view呢? 让所有的Views 同步更新资料的关键在于两个函数: 1)CDocument::Upda ...

  4. 深入浅出MFC学习笔记(第6章 :MFC程序的生死因果)

    第六章:MFC程序的生死因果 本章主要是从MFC程序代码中,找出一个windows程序原本该有的程序入口点.窗口类注册.窗口产生.消息循环.窗口函数等操作.抽丝剥茧彻底理解一个MFC程序的诞生与结束. ...

  5. 深入浅出mfc学习笔记——六大关键技术之仿真_运行时和动态创建

    1:PS88:MFC的类层次结构 <1>CObject <2>CCmdTarget,CDocument <3>CCmdTarget_CWinThread_CWinA ...

  6. 深入浅出MFC学习笔记:MFC六大关键技术仿真之RTTI运行时类型识别

    RTTI(运行时类型识别) 参考文献:深入浅出MFC-侯捷 怎样去构造类别型录网? 一.定义数据结构: 其中pFirstClass指针属于痊愈变量,所以它应该以static修饰之. 而且我们最终希望达 ...

  7. MFC 学习笔记(一):MFC单文档程序运行流程梳理与总结

    MFC 学习笔记(一):MFC单文档程序运行流程梳理与总结 1.MFC单文档程序运行流程 1.首先利用全局变量对象 theApp 启动应用程序 (这是因为这个全局对象,基类CWinApp中 this ...

  8. C++ MFC 学习笔记+小型通讯录系统实现

    MFC 最详细入门教程 [MFC常用函数总结](https://www.cnblogs.com/jiu0821/p/4606639.html) [C++ & MFC]https://www.c ...

  9. 深入浅出SSD 学习笔记整理——Johnathan Sung

    SSD ( Solid State Drive),即固态硬盘,是一种以半导体闪存( NAND Flash)作为介质的存储设备.和传统机械硬盘(Hard Disk Drive,HDD)不同,SSD以半导 ...

最新文章

  1. 将HTMLCollection转换为数组的最有效方法
  2. 第四节:python if语句用法
  3. 增加 oracle服务名,oracle本地服务名配置说明
  4. 思考ANDROID架构(4):HOW-TO, 如何从API洞悉软件的话语权
  5. 《码出高效:Java开发手册》背后的故事
  6. 8597 石子划分问题 dpdp,只考虑第一次即可
  7. nodejs应用转换png,jpg,gif为webp图片格式
  8. 牛客多校第六场G Is Today Friday?(吉姆拉尔森/蔡勒公式 + 思维)题解
  9. maven编译时出现读取XXX时出错invalid LOC header bad signature
  10. python 运行出现flask运行时提示出错了或者报服务器出错,ValueError: View function did not return a response...
  11. 【bzoj1022】[SHOI2008]小约翰的游戏John 博弈论
  12. matlab2014a VS2010混合编程
  13. C语言程序设计流程图详解
  14. 网络编程 : 基于UDP的网络群聊聊天室
  15. 生产环境下服务器台账
  16. 【docx4j】docx4j操作docx,实现替换内容、转换pdf、html等操作
  17. 编译时内核栈溢出:the frame size of 1928 bytes is larger than 1024 bytes
  18. 手机ping软件测试网速,网速测试 - wifi测网速,网络ping test
  19. 英语四级词汇量测试软件,大学英语四级词汇量要求及自测卷
  20. Firefox使用大全

热门文章

  1. r语言plot函数设置y轴的范围及刻度_R语言之简单绘图
  2. 构造函数与toString
  3. 获取mysql 时钟,员工时钟的MySQL数据库结构
  4. mysql优化php面试_php面试专题---18、MySQL查询优化考点
  5. easyui tab 引用html,jQuery插件EasyUI获取当前Tab中iframe窗体对象的方法
  6. Navicat 复制多条数据
  7. Python与Redis交互
  8. ssh 将22端口换为其它 防火墙设置
  9. 2016.6.29 tomcat卸载后在安装出现错误:failed to install tomcat7 service
  10. Direct2D教程(五)复合图形