mfc 消息隐射机制

2021-09-27  本文已影响0人  突然的自我_39c1

一.引言
VC++的MFC类库实际上是Windows下C++编程的一套最为流行的类库。它合理的封装了WIN32 API函数,并设计了一套方便的消息映射机制。
二.SDK下的消息机制实现
Windows的消息都是和线程相对应的。即Windows会把消息发送给和该消息相对应的线程。在SDK的模式下,程序是通过GetMessage函数从和某个线程相对应的消息队列里面把消息取出来并放到一个特殊的结构里面,一个消息的结构是一个如下的STRUCTURE。

typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
}MSG;

三.MFC的消息实现机制
在MFC的框架结构下,可以进行消息处理的类的头文件里面都会含有DECLARE_MESSAGE_MAP()宏,这里主要进行消息映射和消息处理函数的声明。可以进行消息处理的类的实现文件里一般都含有如下的结构。
下面主要进行消息映射的实现和消息处理函数的实现。能够进行消息处理的类都是基于CCmdTarget类的,也就是说CCmdTarget类是所有可以进行消息处理类的父类。CCmdTarget类是MFC处理命令消息的基础和核心。
BEGIN_MESSAGE_MAP(CInheritClass, CBaseClass)
//{{AFX_MSG_MAP(CInheritClass)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

MFC定义了下面的两个主要结构:

  1. AFX_MSGMAP_ENTRY
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 nSig;       
// signature type (action) or pointer to message #
AFX_PMSG pfn;    // routine to call (or special value)
};
  1. AFX_MSGMAP_ENTRY结构包含了一个消息的所有相关信息,其中:
  struct AFX_MSGMAP
  {
    #ifdef _AFXDLL
    const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
    #else
    const AFX_MSGMAP* pBaseMap;
    #endif
    const AFX_MSGMAP_ENTRY* lpEntries;
  };

AFX_MSGMAP主要作用是两个:

MFC把所有的消息一条条填入到AFX_MSGMAP_ENTRY结构中去,形成一个数组,该数组存放了所有的消息和与它们相关的参数。同时通过AFX_MSGMAP能得到该数组的首地址,同时得到基类的消息映射入口地址,这是为了当本身对该消息不响应的时候,就调用其基类的消息响应。

MFC是如何让窗口过程来处理消息的

  1. 所有MFC的窗口类都通过钩子函数_AfxCbtFilterHook截获消息,并且在钩子函数_AfxCbtFilterHook中把窗口过程设定为AfxWndProc。原来的窗口过程保存在成员变量m_pfnSuper中
  2. 所以在MFC框架下,一般一个消息的处理过程

所以如果正常的消息处理的话,MFC窗口类是完全脱离了原来的窗口过程,用自己的一套体系结构实现消息的映射和处理。即先调用MFC窗口类挂上去的窗口过程,再调用原先的窗口过程。并且用户面对和消息相关的参数不再是死板的wParam和lParam,而是和消息类型具体相关的参数。比如和消息WM_LbuttonDown相对应的方法OnLButtonDown的两个参数是nFlags和point。nFlags表示在按下鼠标左键的时候是否有其他虚键按下,point更简单,就是表示鼠标的位置。

MFC窗口类消息传递中还提供了两个函数: WalkPreTranslateTree:、 PreTranslateMessage;他们是这样工作的:

  1. 利用MFC框架生成的程序,都是从CWinApp开始执行的,而CWinapp实际继承了CWinThread类。在CWinThread的运行过程中会调用窗口类中的WalkPreTranslateTree方法。而WalkPreTranslateTree方法实际上就是从当前窗口开始查找愿意进行消息翻译的类,直到找到窗口没有父类为止。
  2. 在WalkPreTranslateTree方法中调用了PreTranslateMessage方法。实际上PreTranslateMessage最大的好处是我们在消息处理前可以在这个方法里面先做一些事情。举一个简单的例子,比如我们希望在一个CEdit对象里,把所有的输入的字母都以大写的形式出现。我们只需要在PreTranslateMessage方法中判断message是否为WM_CHAR,如果是的话,把wParam(表示键值)由小写字母的值该为大写字母的值就实现了这个功能。

三.MFC的消息响应顺序

  1. 几个消息函数解释
  1. 创建窗口的顺序
  1. 关闭窗口的顺序(非模态窗口)
  1. 打开模态对话框的顺序
  1. 关闭模态对话框的顺序
上一篇下一篇

猜你喜欢

热点阅读