MFC原理第五讲.消息映射.以及如何添加消息

一丶消息映射是什么

  我们知道.Win32程序.都是通过消息去驱动的. 不断的在处理消息. 只要我们使用固定的宏.就可以让我们的框架知道一旦消息发生.该往哪一个类传递. 每一个类可以拥有一个映射表格.

也可以没有.  

  关键宏
  1. DECLARE_MESSAGE_MAP  声明宏.放在类中

  2. BEGIN_MESSAGE_MAP      实现宏放在类实现外

  3. END_MESSAGE_MAP   实现宏放在类外面

如何添加消息.

  如果我们添加了 BEGIN 跟 END 两个宏之后. 我们在中间添加他们的消息就可以.

  例如:

  

  1. BEGIN_MESSAGE_MAP(CMainWnd,CFrameWnd) //两个参数.第一个是自己的类.第二个是父类.
  2. ON_WM_LBUTTONDOWN() 我们的消息. 需要添加声明以及实现.
  3. END_MESSAGE_MAP()

我们的消息.MFC都给我们封装好了.如果实现消息. 则一律 ON_WM开头.  消息 是WM_XXX.

我们可以在 afxmsg.h 中查看.

我们在类中声明消息.并且添加消息处理函数即可.

例如以下代码:

  

上面是声明.下面是实现.

应用程序截图

    

二丶消息映射原理分析

  不管学习任何东西. 先学会用.再去学习原理.这样是最快的.

现在对我们的宏进行拆分来看.

  1.DECLARE_MESSAGE_MAP 宏查看.

  1. #define DECLARE_MESSAGE_MAP() \
  2. protected: \
  3. static const AFX_MSGMAP* PASCAL GetThisMessageMap(); \
  4. virtual const AFX_MSGMAP* GetMessageMap() const; \

这个宏一幕了然. 添加了两个方法.一个是虚方法.

那么这个是声明宏.那么另外两个应该就有实现宏了.看下实现宏的拆解.

  2.BEGIN_MESSAGE_MAP(字节类名.父类名)

  

  1. #define BEGIN_MESSAGE_MAP(theClass, baseClass) \
  2. PTM_WARNING_DISABLE \
  3. const AFX_MSGMAP* theClass::GetMessageMap() const \
  4. { return GetThisMessageMap(); } \
  5. const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \
  6. { \
  7. typedef theClass ThisClass; \
  8. typedef baseClass TheBaseClass; \
  9. static const AFX_MSGMAP_ENTRY _messageEntries[] = \
  10. {

可以看得出.拆解开是一个一半的东西. 这里需要添加我们的消息了.所以下面是END_MESSAGE_MAP

所以两个一起解析.

  

  1. const AFX_MSGMAP* CMainWnd::GetMessageMap() const
  2. {
  3. return GetThisMessageMap();
  4. }
  5.  
  6. const AFX_MSGMAP* PASCAL CMainWnd::GetThisMessageMap()
  7. {
  8. typedef CMainWnd ThisClass;
  9. typedef CFrameWnd TheCFrameWnd;
  10. static const AFX_MSGMAP_ENTRY _messageEntries[] =
  11. {
  12. //这里添加我们的消息
  13.  
  14. {, , , , AfxSig_end, (AFX_PMSG) } //END_MESSAGE_MAP 宏.下面都是.
  15. };
  16. static const AFX_MSGMAP messageMap =
  17. {
  18. &TheCFrameWnd::GetThisMessageMap, &_messageEntries[]
  19. };
  20. return &messageMap;
  21. }

可以看出.这两个宏就是对声明的两个宏的实现. 而上面我们添加的ON_WM_LBUTTONDOWN 就是放在 END_MESSAGE_MAP 上面的. 我们看一下格式.

  1. const AFX_MSGMAP* CMainWnd::GetMessageMap() const
  2. {
  3. return GetThisMessageMap();
  4. }
  5.  
  6. const AFX_MSGMAP* PASCAL CMainWnd::GetThisMessageMap()
  7. {
  8. typedef CMainWnd ThisClass;
  9. typedef CFrameWnd TheCFrameWnd;
  10. static const AFX_MSGMAP_ENTRY _messageEntries[] =
  11. {
  12. //这里添加我们的消息
  13. ON_WM_LBUTTONDOWN() //我们要解析这个消息
  14. {, , , , AfxSig_end, (AFX_PMSG) }
  15. };
  16. static const AFX_MSGMAP messageMap =
  17. {
  18. &TheCFrameWnd::GetThisMessageMap, &_messageEntries[]
  19. };
  20. return &messageMap;
  21. }
  1. #define ON_WM_LBUTTONDOWN() \
  2. { WM_LBUTTONDOWN, , , , AfxSig_vwp, \
  3. (AFX_PMSG)(AFX_PMSGW) \
  4. (static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > ( &ThisClass :: OnLButtonDown)) },

其实上面可以看出.其实是一个 _messageEntries数组.保存着我们的消息. 我们替换这个宏看一下.

  1. {
  2. WM_LBUTTONDOWN, , , , AfxSig_vwp,
  3. (AFX_PMSG)(AFX_PMSGW)(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > ( &ThisClass :: OnLButtonDown))
  4. },

解析完成可以看到.第一个是 WM_LBUTTONDOWN 对应着他的处理函数 OnLButtonDown 也就是最后一个参数.

所以现在明白了我们添加消息的时候.为什么要按照规定的格式. 因为这个宏已经使消息一一对应了.

因为上面是一个结构体数组用来保存.所以我们可以看一下这个数组是什么格式的.

  1. struct AFX_MSGMAP_ENTRY
  2. {
  3. UINT nMessage; // windows message
  4. UINT nCode; // control code or WM_NOTIFY code
  5. UINT nID; // control ID (or 0 for windows messages)
  6. UINT nLastID; // used for entries specifying a range of control id's
  7. UINT_PTR nSig; // signature type (action) or pointer to message #
  8. AFX_PMSG pfn; // routine to call (or special value)
  9. };

注释也给我们写的很清楚了. 消息.  消息控制代码.什么消息类型  控制ID  pfn函数的返回值类型 pfn 消息处理对应函数.

但是我们要具体解释一下. 第5个跟第6个参数.

第五个参数指明了我们函数的返回值

比如上图:

  AfxSig_vwp 类型. 我们可以点击F12取头文件中查看.例如下图:

所以我们知道了我们的函数定义的返回以及参数类型了.

我是按照VS2015下的MFC讲解. 如果是VC6.0下. 那么 需要添加三个成员方法. 不过实现是类似了. 具体可以查看VC60的MFC源码.

根据VS2015给我们添加了两个成员方法. 可以看到返回值也是一个结构体.那么看下这个结构体内容吧.

  1. struct AFX_MSGMAP
  2. {
  3. const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)(); 父类的MAP
  4. const AFX_MSGMAP_ENTRY* lpEntries; 存放自己当前的消息结构.
  5. };

上面总结一下.

  1.首先声明宏会为我们添加两个方法.  获取消息映射表

  2.实现宏则实现这两个方法.   而且还有两个结构. 一个是存放消息信息的结构. 另一个结构则是存放父类的MessageMap .以及自己当前存放信息的结构

那么知道了消息映射表.我们可以在按钮点击的时候. 按一下打印出我们消息的时候对应的地址了. 这个对于逆向很有帮助. 学到最后我们可以写一个工具. 可以有很好的切入点了.

具体代码如下:

  

  1. void CMainWnd::OnMyLButtonDown(UINT flag, CPoint point) //知道了结构我们自己改也可以.
  2. {
  3. //获取消息映射表.看看消息传递.
  4. const AFX_MSGMAP * pMsg = GetMessageMap();
  5. //打印出自己当前按钮点击的时候的地址.
  6. CString str;
  7. str.Format(TEXT("地址 = %p\r\n"), pMsg->lpEntries->pfn); 从消息映射表中获取我们的函数地址. 其实应该遍历.并且判断是否是消息.这里直接就偷懒了.因为只有一个消息.
  8. OutputDebugString(str);
  9. AfxMessageBox(TEXT("OnLButtonDown"));
  10. }

应用程序截图:

 

很方便的看到了地址. 我们可以使用逆向工具 到这个地址查看.看看是否是我们点击的时候的消息.

因为是Dbg版本.所以有Jmp跳转的一层.我们直接跳转进去查看.

可以很简单的看到.就是我们编写的代码的位置.

下一讲讲解消息传递.

链接:https://pan.baidu.com/s/1HQo3muBivkRcM0koKjICeQ 密码:p5dj

MFC原理第五讲.消息映射.以及如何添加消息的更多相关文章

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

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

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

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

  3. MFC消息映射机制

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

  4. VS2010-MFC(MFC消息映射机制概述)

    转自:http://www.jizhuomi.com/software/147.html 前面已经说过,Windows应用程序是消息驱动的.在MFC软件开发中,界面操作或者线程之间通信都会经常用到消息 ...

  5. mfc---单文档工程添加消息响应

    写消息映射:.h中些函数头文件afx_mag … .cpp中写函数体 .cpp中写消息映射 给toolbar添加消息: .h中添加头文件afx_msg …. .cpp中添加函数体,消息映射ON_COM ...

  6. 图解MFC基本框架(深入消息映射机制)

    首先,先看整体的消息流向图: 上图解释: 起点是消息循环,在winmain函数中(mfc中winmain函数是隐含的调用的,在app全局对象构造完后紧接着调用winmain函数),while循环中不断 ...

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

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

  8. 【转】MFC消息映射详解(整理转载)

    消息:主要指由用户操作而向应用程序发出的信息,也包括操作系统内部产生的消息.例如,单击鼠标左按钮,windows将产WM_LBUTTONDOWN消息,而释放鼠标左按钮将产生WM_LBUTTONUP消息 ...

  9. VC-基础:VS2010/MFC-1MFC消息映射

    Windows消息分类 Windows消息分为系统消息和用户自定义消息.Windows系统消息有三种: 1.标准Windows消息.除WM_COMMAND外以WM_开头的消息是标准消息.例如,WM_C ...

随机推荐

  1. python (创建虚拟环境)

    Python python 介绍 Python是一门计算机编程语言.是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的 ...

  2. selenium中maven的使用

    一.maven的下载.解压以及环境变量配置 1.下载maven: 官网下载地址:http://maven.apache.org/download.cgi 在Files下面下载对应的maven版本(官网 ...

  3. SpringCloud消息总线

    我们在springcloud(七):配置中心svn示例和refresh中讲到,如果需要客户端获取到最新的配置信息需要执行refresh,我们可以利用webhook的机制每次提交代码发送请求来刷新客户端 ...

  4. SSH通过密钥登陆

    A服务器上操作 ssh-keygen -t rsa/dsa 后面所带参数rsa/dsa为加密方式,默认为dsa [root@localhost ~]# ssh-keygen Generating pu ...

  5. Python开发——16.HTML

    一.HTML 1.服务端 import socket def main(): sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM) sock. ...

  6. How to setup Visual Studio without pain

    Visual Studio (VS) can be very hard to install. If you are lucky, one whole day may be enough to ins ...

  7. TopicsExtraction with NMF & LDA

    """ ================================================================================= ...

  8. now

  9. Eclipse项目里面看源码和文档

    Eclipse项目里面看源码 1.新建项目列表 2.进入struts2-core-2.3.20.jar,双击之后,看不到源码 3.右键struts2-core-2.3.20.jar,选择propert ...

  10. 数据的描述性分析_R

    1. 生成二维数据(类别型数据)的列联表 (1) mytable<-table(data)/prop.table(概率) addmargins(mytable) (2) library(gmod ...