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

一丶消息映射是什么

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

也可以没有.  

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

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

  3. END_MESSAGE_MAP   实现宏放在类外面

如何添加消息.

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

  例如:

  

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

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

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

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

例如以下代码:

  

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

应用程序截图

    

二丶消息映射原理分析

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

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

  1.DECLARE_MESSAGE_MAP 宏查看.

#define DECLARE_MESSAGE_MAP() \
protected: \
static const AFX_MSGMAP* PASCAL GetThisMessageMap(); \
virtual const AFX_MSGMAP* GetMessageMap() const; \

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

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

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

  

#define BEGIN_MESSAGE_MAP(theClass, baseClass) \
PTM_WARNING_DISABLE \
const AFX_MSGMAP* theClass::GetMessageMap() const \
{ return GetThisMessageMap(); } \
const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \
{ \
typedef theClass ThisClass; \
typedef baseClass TheBaseClass; \
static const AFX_MSGMAP_ENTRY _messageEntries[] = \
{

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

所以两个一起解析.

  

const AFX_MSGMAP* CMainWnd::GetMessageMap() const
{
return GetThisMessageMap();
} const AFX_MSGMAP* PASCAL CMainWnd::GetThisMessageMap()
{
typedef CMainWnd ThisClass;
typedef CFrameWnd TheCFrameWnd;
static const AFX_MSGMAP_ENTRY _messageEntries[] =
{
//这里添加我们的消息 {, , , , AfxSig_end, (AFX_PMSG) } //END_MESSAGE_MAP 宏.下面都是.
};
static const AFX_MSGMAP messageMap =
{
&TheCFrameWnd::GetThisMessageMap, &_messageEntries[]
};
return &messageMap;
}

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

const AFX_MSGMAP* CMainWnd::GetMessageMap() const
{
return GetThisMessageMap();
} const AFX_MSGMAP* PASCAL CMainWnd::GetThisMessageMap()
{
typedef CMainWnd ThisClass;
typedef CFrameWnd TheCFrameWnd;
static const AFX_MSGMAP_ENTRY _messageEntries[] =
{
//这里添加我们的消息
ON_WM_LBUTTONDOWN() //我们要解析这个消息
{, , , , AfxSig_end, (AFX_PMSG) }
};
static const AFX_MSGMAP messageMap =
{
&TheCFrameWnd::GetThisMessageMap, &_messageEntries[]
};
return &messageMap;
}
#define ON_WM_LBUTTONDOWN() \
{ WM_LBUTTONDOWN, , , , AfxSig_vwp, \
(AFX_PMSG)(AFX_PMSGW) \
(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > ( &ThisClass :: OnLButtonDown)) },

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

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

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

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

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

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

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

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

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

比如上图:

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

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

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

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

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

上面总结一下.

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

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

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

具体代码如下:

  

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

应用程序截图:

 

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

因为是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. window下github的学习心得

    准备工作: 安装git: 1.下载地址:http://msysgit.github.io/ 2.安装:本人是一路next的,现在没发现有什么问题.详细的安装过程参考:https://jingyan.b ...

  2. sjms-4 行为型模式

    行为型模式 责任链模式 内容:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止.角色:抽象处理者(Hand ...

  3. 现网环境业务不影响,但是tomcat启动一直有error日志,ERROR org.apache.catalina.startup.ContextConfig- Unable to process Jar entry [module-info.class] from Jar [jar:file:/home/iufs/apache-tomcat/webapps/iufs/WEB-INF/lib/asm

    完整的错误日志信息: 2019-03-19 15:30:42,021 [main] INFO org.apache.catalina.core.StandardEngine- Starting Ser ...

  4. java中的接口与继承,接口的例子讲解

    extends 继承类:implements 实现接口. 简单说: 1.extends是继承父类,只要那个类不是声明为final或者那个类定义为abstract的就能继承, 2.JAVA中不支持多重继 ...

  5. 文件上传的三种模式-Java

    文件上传的三种方式-Java 前言:因自己负责的项目(jetty内嵌启动的SpringMvc)中需要实现文件上传,而自己对java文件上传这一块未接触过,且对 Http 协议较模糊,故这次采用渐进的方 ...

  6. ASCII记录

    符号 十进制 + 43 - 45

  7. 与我们息息相关的internet服务(2)---WWW服务

    在起步一个公司,从组建的技术上,可能要准备很多东西,其中一个就是我们熟悉的公司网站    网站,在初中,那时浏览一个网页可叫网上冲浪,听起来似乎比洗澡还爽快,可现在这词就是土鳖,网上冲浪火起来主要是应 ...

  8. C# WebAPI系列(2)

    上篇中简单介绍了一下WebApi,本章主要介绍一下Controller相关的知识. 在实际应用中,Controller是WebAPI的链接服务器和客户端的窗口.Controller的好坏影响整个系统的 ...

  9. 报错:Maximum call stack size exceeded

    最后通过查看一篇别人的博客,通过对照,发现我把参数值写反了,把参数a的值写成了参数b的值.详情可以看如下博客: https://www.cnblogs.com/dunitian/p/5865725.h ...

  10. submit插件安装的问题与集成了插件的submit

    写在最前面,方法有二种.一种是在线安装,这种办法我尝试过,受网速和软件卡顿的问题,进行不顺利.第二种就是我下面介绍的这种,手动安装. 最精华的在后面,可以直接跳转到最后.我找了很久的,最新版的汉化,而 ...