网站开发用什么字体,查询域名备案,营销型网站建设的指导原则不包括,asp网站安全吗目录
消息映射机制概述
宏展开
宏展开的作用
消息映射机制的执行流程
消息处理 消息映射机制概述
MFC的消息映射映射机制是可以在不重写WindowProc虚函数的大前提下#xff0c;仍然可以处理消息。
类必须具备的要件
类内必须添加声明宏 DECLARE_MESSAGE_MAP()
类外…目录
消息映射机制概述
宏展开
宏展开的作用
消息映射机制的执行流程
消息处理 消息映射机制概述
MFC的消息映射映射机制是可以在不重写WindowProc虚函数的大前提下仍然可以处理消息。
类必须具备的要件
类内必须添加声明宏 DECLARE_MESSAGE_MAP()
类外必须添加实现宏
BEGIN_MESSAGE_MAP(theClass , baseClass)END_MESSAGE_MAP()
总结当一个类具备上述两个要件这个类就可以按照消息映射机制来处理消息。
MFC利用消息映射机制处理消息以处理WM_CREATE消息为例
类内
添加声明宏 DECLARE_MESSAGE_MAP()添加处理WM_CREATE消息的函数声明
类外
添加宏BEGIN_MESSAGE_MAP(theClass , baseClass) END_MESSAGE_MAP()实现处理WM_CREATE消息的函数定义 宏展开
对宏代码进行展开得到下面的成果
#include afxwin.h
class CMyFrameWnd : public CFrameWnd {// DECLARE_MESSAGE_MAP()
protected:static const AFX_MSGMAP* PASCAL GetThisMessageMap();virtual const AFX_MSGMAP* GetMessageMap() const;
public:LRESULT OnCreate(WPARAM wParam, LPARAM lParam);
};
//BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)
// ON_MESSAGE( WM_CREATE, OnCreate )
//END_MESSAGE_MAP()const AFX_MSGMAP* CMyFrameWnd::GetMessageMap() const
{return GetThisMessageMap();
}
const AFX_MSGMAP* PASCAL CMyFrameWnd::GetThisMessageMap()
{static const AFX_MSGMAP_ENTRY _messageEntries[] {{ WM_CREATE, 0, 0, 0, AfxSig_lwl, (AFX_PMSG)(AFX_PMSGW)(static_castLRESULT(AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) (OnCreate)) },{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }};static const AFX_MSGMAP messageMap { CFrameWnd::GetThisMessageMap, _messageEntries[0] };return messageMap;
}LRESULT CMyFrameWnd::OnCreate(WPARAM wParam, LPARAM lParam) {AfxMessageBox(WM_CREATE);return 0;
}class CMyWinApp : public CWinApp {
public:virtual BOOL InitInstance();
};
CMyWinApp theApp;//爆破点
BOOL CMyWinApp::InitInstance() {CMyFrameWnd* pFrame new CMyFrameWnd;pFrame-Create(NULL, MFCCreate);m_pMainWnd pFrame;pFrame-ShowWindow(SW_SHOW);pFrame-UpdateWindow();return TRUE;
}声明了两个成员函数
DECLARE_MESSAGE_MAP()
声明两个函数
protected:static const AFX_MSGMAP* PASCAL GetThisMessageMap();virtual const AFX_MSGMAP* GetMessageMap() const; 拓展在C中static修饰函数可以有以下两种含义 (1) 静态成员函数特点包括 不属于类的任何特定对象而是属于整个类。可以访问类的静态成员变量和其他静态成员函数但不能直接访问类的非静态成员变量和非静态成员函数。不能使用this指针因为this指针指向类的对象实例而静态成员函数并不属于任何特定对象。静态成员函数可以直接通过作用域解析运算符(::)访问类的静态成员变量和静态成员函数无需通过对象。 静态成员函数通常用于执行与类相关的操作而不依赖于特定对象的状态。例如可以在静态成员函数中计算或处理类的静态成员变量或者实现与类相关的全局操作。 (2) 文件作用域的静态函数 文件作用域的静态函数是指在C或C中使用static关键字声明的函数这种函数的作用域限定在当前文件内不能被其他文件访问或调用。在文件中使用static修饰的函数通常用于实现模块内部的辅助函数或者限制函数的作用域以减少全局命名空间的污染。 拓展在C中const修饰函数可以分为两种情况const成员函数和const修饰的非成员函数。 (1) const成员函数const成员函数是指在函数声明或定义的末尾加上const关键字用于表示该成员函数不会修改对象的状态。在const成员函数中不能修改成员变量的值也不能调用非const成员函数以确保该函数不会改变对象的状态。 (2) const修饰的非成员函数 const修饰的非成员函数是指在函数声明或定义的末尾加上const关键字用于表示函数的返回值是常量。 示例 const int getValue() { return 10; // 返回一个常量值 } const string getName() { static const string name John; return name; // 返回一个常量引用 } 实现了两个函数
BEGIN_MESSAGE_MAP(CMyFrameWnd, CFrameWnd)END_MESSAGE_MAP()
第一个函数的返回值是第二个函数的返回值
const AFX_MSGMAP* CMyFrameWnd::GetMessageMap() const
{return GetThisMessageMap();
}
const AFX_MSGMAP* PASCAL CMyFrameWnd::GetThisMessageMap()
{static const AFX_MSGMAP_ENTRY _messageEntries[] {{ WM_CREATE, 0, 0, 0, AfxSig_lwl, (AFX_PMSG)(AFX_PMSGW)(static_castLRESULT(AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) (OnCreate)) },{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }};static const AFX_MSGMAP messageMap { CFrameWnd::GetThisMessageMap, _messageEntries[0] };return messageMap;
}
ON_MESSAGE( WM_CREATE, OnCreate ) 相当于
{ WM_CREATE, 0, 0, 0, AfxSig_lwl, (AFX_PMSG)(AFX_PMSGW)(static_castLRESULT(AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) (OnCreate)) }, 宏展开的作用
首先学习两个数据结构
这个结构体与我们需要处理的消息有关主要需要关注第一个与最后一个即可
struct AFX_MSGMAP_ENTRY
{UINT nMessage; UINT nCode; UINT nID; UINT nLastID; UINT_PTR nSig; AFX_PMSG pfn;
};
这个结构体的成员表示如下
消息ID用于标识Windows消息类型的整数值。通知码标识控件ID值命令ID用于区分控件的不同命令比如有一个“打开”菜单项和一个“保存”菜单项它们分别对应着打开文件和保存文件的操作。在程序内部为了识别用户点击了哪个菜单项就需要为每个菜单项分配一个唯一的命令ID。当用户点击“打开”菜单项时程序就会根据这个命令ID来执行打开文件的操作当用户点击“保存”菜单项时程序则会根据另一个命令ID来执行保存文件的操作。最后一个命令ID用于标识此消息关联的前一个命令的整数值。处理消息的函数类型处理消息的函数名(地址) 这个结构体主要和遍历链表有关
struct AFX_MSGMAP
{const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();const AFX_MSGMAP_ENTRY* lpEntries;
};
这个结构体的成员表示如下
父类宏展开的静态变量地址本类宏展开的静态数组首地址 宏展开各部分的作用
局部静态变量与普通的局部变量不同之处在于其生存期和作用域。当函数被调用时静态局部变量不会被销毁而是保留其数值直到程序运行结束。此外在函数内部静态局部变量的作用域仅限于声明它的函数内部。 GetThisMessageMap()静态函数 作用定义静态变量和静态数组并返回本类静态变量地址(获取链表头) _messageEntries[]静态数组(进程级声明周期) 作用数组每个元素保存为 消息ID 和 处理消息的函数名(地址) messageMap静态变量(进程级声明周期) 作用第一个成员保存父类宏展开的静态变量地址(负责连接链表) 第二个成员保存本类的静态数组首地址 GetMessageMap()虚函数 作用返回本类静态变量地址(获取链表头) 两个结构体在消息映射机制实现的作用
messageMap第一个是父类GetThisMessageMap函数地址第二个是本类的_messageEntries数组地址_messageEntries结构体数组地址中的每一个元素都是消息和对应处理函数地址 CMyFrameWnd有一套这样的局部静态本类CFrameWndCWnd都有到此为止CWnd的父类就没有了
这就构成一个链表的结构 在 CFrameWndCWnd 类中都有对消息的处理函数 消息映射机制的执行流程
下载WM_CREATE消息处理函数下断点 消息产生进入窗口处理函数(AfxWndProc)对此函数下断点开始分析前三个消息不是WM_CREATE消息先F5放过直到 nMsg 值为1
通过句柄拿到框架窗口对象
CWnd* pWnd CWnd::FromHandlePermanent(hWnd);
之后调用AfxCallWndProc在之后调用WindowProc
lResult pWnd-WindowProc(nMsg, wParam, lParam);
再之后调用OnWndMsg if (!OnWndMsg(message, wParam, lParam, lResult))lResult DefWindowProc(message, wParam, lParam);
在这里对不同的消息处理都不一样 获取本类宏站开的静态变量的地址链表头结点
const AFX_MSGMAP* pMessageMap; pMessageMap GetMessageMap();
F11回到我们的代码了 开始遍历结构体数组循环中每次迭代条件就是获得父类GetThisMessageMap函数地址 如果找到返回找到的数组元素的地址如果没找到返回NULL找到之后goto跳出循环
if ((lpEntry AfxFindMessageEntry(pMessageMap-lpEntries,message, 0, 0)) ! NULL)
{pMsgCache-lpEntry lpEntry;winMsgLock.Unlock();goto LDispatch;
}
lpEntry-pfn; //CMyFrameWnd::OnCreate
调用CMyFrameWnd::OnCreate函数完成消息的处理
LRESULT CMyFrameWnd::OnCreate(WPARAM wParam, LPARAM lParam) {AfxMessageBox(WM_CREATE);return 0;
}
执行完后再次会到这里 总结
消息产生进入窗口处理函数(AfxWndProc )根据已知窗口句柄找到和它绑定在一起的框架类对象地址( pFrame )。利用框架类对象地址( pFrame )调用框架类成员虚函数WindowProc获取本类对应的静态变量并到对应数组中匹配查找。如果没有找到获取父类对应的静态变量并到对应数组中匹配查找。如果找到了利用找到的数组元素的最后一个成员并调用之完成消息处理。 消息分类
主要有以下三类
标准windows消息ON_WM_XXX自定义消息ON_MESSAGE命令消息ON_COMMAND暂且不管 第一类消息处理函数的返回值参数都是固定的第二类就不是了。这些规定可以再MSDN中查到