深入浅出MFC学习笔记2--消息映射和消息路由
来源:互联网 发布:一对一聊天的软件 编辑:程序博客网 时间:2024/04/30 00:12
1.消息映射【消息的简单往上传递】
struct AFX_MSGMAP{ AFX_MSGMAP* pBaseMessageMap; AFX_MSGMAP_ENTRY* lpEntries;};struct AFX_MSGMAP_ENTRY{ UINT nMessage; UINT nCode; UINT nID; UINT nLastID; UINT nSig; AFX_PMSG pfn;};typedef void (CCmdTarget::*AFX_PMSG)(void);#define DECLARE_MESSAGE_MAP()\ static AFX_MSGMAP_ENTRY _messageEntries[];\ static AFX_MSGMAP messageMap;\ virtual AFX_MSGMAP* GetMessageMap() const;#define BEGIN_MESSAGE_MAP(theClass, baseClass)\ AFX_MSGMAP*theClass::GetMessageMap() const\ {\ return &theClass::messageMap;\ }\ AFX_MSGMAP theClass::messageMap = \ {\ // 对数组名取地址得到的仍然是一个地址,只不过此时此地址的类型不是默认的指向数组元素类型的指针【AFX_MSGMAP_ENTRY*】,而是指向数组的指针 //【AFX_MSGMAP_ENTRY(*)[]】 &baseClass::messageMap, (AFX_MSGMAP_ENTRY*)&(theClass::_messageEntries) };\ AFX_MSGMAP_ENTRYtheClass::_messageEntries[] = \ {#define ON_COMMAN(id, memberFxn)\ {\ // 表面ON_COMMAND的处理函数只能是void (*)(void)类型 WM_COMMAND, 0, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)memberFxn },\#define END_MESSAGE_MAP()\ {\ 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0\ }\ };
AfxSig_xx用来描述消息处理程序menberFxn的类型【参数和返回值】
消息映射的最原始类是CCmdTarget,对此类特殊处理:
AFX_MSGMAP CCmdTarget::messageMap = { NULL, &CCmdTarget::_messageEntries[0]};AFX_MSGMAP_ENTRY CCmdTarget::_messageEntries[] = { { 0, 0, CCmdTargetid, 0, AfxSig_end, 0}};
// 1.由于此函数是CCmdTarget的虚函数,意味着你即使对一个没有采用消息映射宏的类对象用GetMessageMap,只要此类的基类有用的,你可以得到此基类的messageMap
// 2.只能对派生自CCmdTarget的类用消息映射宏,即使类的直接基类没有用消息映射宏,在本类的BEGIN_MASSAGE_MAP(theClass,baseClass)指定基类也是没问题的。
// 3.原因就是1行分析的
AFX_MSGMAP* CCmdTarget::GetMessageMap() const{ return &CCmdTarget::messageMap;}
Frame7:
CCmdTarget, CWinApp, CDocument, CWnd, CFrameWnd, CView, CMyWinApp, CMyFrameWnd, CMyDoc, CMyView分别用DECLARE_MESSAGE_MAP
// 【CCmdTarget没用下面的,使用特殊处理的】
BEGIN_MESSAGE_MAP(theClass, baseClass) ON_COMMAND(theClassid, 0)END_MESSAGE_MAP()
则会在程序开始运行之前就建立起一个消息传递网。从每一个应用上述宏的类获取其messageMap,可根据指向基类的指针依次往上找,最终都找到CCmdTarget的messageMap里。
2.命令传递【命令消息的传递过程】
上面把整个消息传递网架设起来了,消息进来时,会有一个泵推动它前进。消息如何进来,以及泵函数如何推动都属于windows程序设计的范涛。
上面的消息网中消息只能从子类流向父类,但有些消息应该有横向流动的机会。
MFC对消息循环的规定:
1.如果是一般的Windows消息(WM_xxx),则一定是派生类流向基类,不考虑横流。
2.如果是命令消息,WM_COMMAND,应有奇特的流动路线。
奇特的流动路线:
命令消息接受者的类型 处理次序
Frame窗口:View–>Frame窗口本身–>CWinApp对象
View :View本身–>Document
Document: Document本身–>Document Template
模拟消息推动引擎:
AfxWndProc是推动引擎的起点,在CWinThread::Run中被调用
1.AfxWndProc用四个参数接受消息
2.执行pWnd->WindowProc(nMsg, wParam, lParam)【这里默认pWnd要指向CWnd或其派生类,可以看出一开始的接受方一定是CWnd或其派生类】,
3.CWnd::WindowProc,根据nMsg是不是WM_COMMAND,决定是采用逐层往上的消息传递处理方式还是OnCommand
4.依据pWnd动态类型决定,执行CFrameWnd::OnCommand【最后还是到CWnd::Command】还是CWnd::Command
5.CWnd::Command,在函数体中执行OnCmdMsg(wParam, lParam),CCmdTarget,CFrameWnd,CView都有自定义OnCmdMsg
6.根据pWnd决定执行那个的OnCmdMsg。
三者的OnCmdMsg处理各不相同
// 可看出每个CFrameWnd至少有一个对应的CViewBOOL 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 FALSE;}// 可看出每个CView必有对应的CDocumentBOOL CView::OnCmdMsg(UINT nID, int nCode){ if(CWnd::OnCmdMsg(nID, nCode)) return TRUE; BOOL bHandled = FALSE; bHandled = m_pDocument->OnCmdMsg(nID, nCode); return bHandled;}BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode){ AFX_MSGMAP* pMessageMap; AFX_MSGMAP_ENTRY* lpEntry; // GetMessageMap是虚函数,这里遍历比较的起点依然根据一开始的hWnd的动态类型决定。 for(pMessageMap = GetMessageMap(); pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMessageMap) { lpEntry = pMessageMap->lpEntries; // 根据lpEntry可以遍历对应类的消息映射表,比较消息ID,如找到匹配的执行对应的消息处理函数。同时结束过程。找不到依次往上找 } return FALSE;}
总的来说,消息一开始被谁获得,决定了此消息接下去怎么走他的传递路线。
如被CFrameWnd或其派生类对象获取,
把消息交给与此CFrameWnd或其派生类相关联的活动CView对象处理【从此CView或CView派生类对象逐个往上找对应类的消息映射表】,若处理不了。
将此消息传递给与相关联的CView对象的相关联的CDocument对象处理【从此CDocument或其派生类对象逐个往上找对应类的消息映射表】,若依然处理不了。
将此消息传给CFrameWnd对象处理【从此CFrameWnd或其派生类对象逐个往上找对应类的消息映射表】,若处理不了。
将此消息传给全局App对象处理【从CWinApp或其派生类对象逐个往上找对应类的消息映射表】,若还是处理不了
用DefWindowProc处理。
如被CView或其派生类对象获取,
上面已包含此过程。
- 深入浅出MFC学习笔记2--消息映射和消息路由
- 深入浅出MFC学习笔记:MFC六大关键技术仿真之消息映射和消息流动
- 深入浅出MFC:消息路由
- MFC深入浅出--消息映射
- MFC深入浅出--消息映射
- MFC消息映射和命令路由
- MFC学习笔记2_消息映射
- MFC消息映射学习笔记
- 深入浅出MFC:对话框消息路由
- MFC深入浅出之消息映射
- MFC消息映射及路由
- 深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:消息映射)
- 深入浅出MFC学习笔记(第三章:MFC六大关键技术之仿真:消息映射)
- MFC消息映射笔记
- mfc的消息映射学习笔记
- MFC学习笔记——消息映射
- MFC学习笔记之消息映射机制
- 深入浅出MFC学习笔记(第9章:消息映射与命令传递。)
- 多态
- Android:在EditView左边加入ImageView并调试相应位置,使其好看些
- UVa 1587 - Box【水题】
- [经济学原理|宏观部分]简单国民收入决定理论
- linux memcached 安装和使用
- 深入浅出MFC学习笔记2--消息映射和消息路由
- 变量与内存空间的关系
- Android解耦库EventBus的使用和源码分析
- 在jsp页面中使用CKEditor
- 按位运算的运用实例
- [经济学原理|宏观部分]产品市场和货币市场
- [经济学原理|宏观部分]宏观经济政策分析
- Codeforces Round #319 (Div. 2)
- CH Round#55 LCA的统计