浅析Windows消息在mfc中的传递路线------(Command rounting)
来源:互联网 发布:直线职能制和矩阵值 编辑:程序博客网 时间:2024/06/06 17:47
我写的每一遍文章都是有准备和有原因的,我绝不是凭个人的心情去做这件事。
Windows消息的传递路线是MFC最神秘的地带之一,MFC的这种机制曾经困扰着无数的编程爱好者。长期以来,我也被它所困扰,而且让我很不爽。当然,很多前辈都对此有过比较深入的剖析,我也看过很多,但是我天生愚钝,看过各种版本任然不能彻底明白其中的机制到底是怎么样实现的。随着我对MFC的理解更加深入,我终于理清了它的头绪。当然,在这个时代还去分析MFC的内部机制是很愚蠢的,因为肯定有些人会站出来跟我说:你傻了,MFC是什么时候的东西啊,你现在还在纠结它,闲得蛋疼吧。但是我还是想搞清楚MFC的这种机制,我相信我的这篇文章在某个时候会帮到一些人,即使不能,我也不会感到遗憾,我尽力了。
即使你刚开始学习MFC,那也没关系,我相信你仍能从下面的文字和代码中有所收获。其中,我会贴出关键的MFC底层代码,这样更有利于我们的理解。
分析流程如下:
1.分析Windows消息在MFC中的总体传递路线;
2.分析Window命令消息WM_COMMAND的传递路线。
一.Windows消息在MFC中的总体传递路线
传递路线:AfxWndProc-----AfxCallWndProc-----WindowProc-----OnWndMsg-----DefWindowProc-----::DefWindowProc。AfxWndProc是消息的起点,为什么呢?请看MFC源代码:
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,LPCTSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam){
...... AfxHookWindowCreate(this); HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass, cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
}
//安装hook的函数
void AFXAPI AfxHookWindowCreate(CWnd* pWnd){
.......
pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT,_AfxCbtFilterHook, NULL, ::GetCurrentThreadId());
......}
//HookPorc钩子过程
LRESULT CALLBACK_AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam){
......
WNDPROC afxWndProc = AfxGetAfxWndProc(); oldWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC,(DWORD)afxWndProc);
......
return lResult;
}
WNDPROC AFXAPI AfxGetAfxWndProc(){
......
return &AfxWndProc;
}
从上面的代码中我们可以知道,在创建窗口之前,MFC安装了一个WH_CBT类型的钩子。在每个窗口对象产生之际,将窗口所属类的窗口函数替换为AfxWndProc,::DispatchMessage就把消息都传送到AfxWndProc中去了。所以,消息的起点是AfxWndProc。继续看MFC中的源代码:
//消息的起点
LRESULT CALLBACKAfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam){......
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);ASSERT(pWnd != NULL);ASSERT(pWnd->m_hWnd == hWnd);return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);}LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg,WPARAM wParam = 0, LPARAM lParam = 0){......
lResult = pWnd->WindowProc(nMsg, wParam, lParam);
......
return lResult;}LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam){LRESULT lResult = 0;if (!OnWndMsg(message, wParam, lParam, &lResult))lResult = DefWindowProc(message, wParam, lParam);return lResult;}LRESULT CWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam){ ......
return ::DefWindowProc(m_hWnd, nMsg, wParam, lParam); ......
}
分析上面的代码,MFC中的消息沿着上面的路线走就顺理成章了。
那么消息到底在哪儿被处理的?如何被处理的呢?请看MFC源代码:
//大部分消息在这个函数中处理
BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam,
LRESULT* pResult){
if (message == WM_COMMAND) { if (OnCommand(wParam, lParam)) {
...... } return FALSE; }
if (message == WM_NOTIFY) {
...... if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult)) return FALSE; }
//比较消息映射表
const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap(); UINT iHash; iHash = (LOWORD((DWORD)pMessageMap) ^ message) &
(iHashMax-1); AfxLockGlobals(CRIT_WINMSGCACHE); AFX_MSG_CACHE* pMsgCache; pMsgCache = &_afxMsgCache[iHash]; const AFX_MSGMAP_ENTRY* lpEntry;
......
}
Windows消息分为三类:命令消息WM_COMMAND,控件的通告消息WM_NOTIFY,标准消息WM_XXX。MFC中的消息经过此路线一步一步传递,到达OnWndMsg,如果消息是命令消息WM_COMMAND,则交由虚函数OnCommand处理;如果是通告消WM_NOTIFY,则交由虚函数OnNotify处理;如果是标准消息WM_XXX,就比较消息映射表Message Map,找到消息处理函数。
二.WM_COMMAND消息在MFC中的传递路线
WM_COMMAND消息交由OnCommand这个函数处理,我们假设消息是从CFrameWnd进来为例子来分析WM_COMMAND消息的传递路线。
首先看MFC中的源代码:
BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam){
......
return CWnd::OnCommand(wParam, lParam);}
BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam){
......
return OnCmdMsg(nID, nCode, NULL, NULL);
}
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo){
if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE;
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE;
CWinApp* pApp = AfxGetApp(); if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)) return TRUE;
return FALSE;}
BOOL CView::OnCmdMsg(UINT nID, int nCode, void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo){ if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))//其实就是调用CCmdTarget::OnCmdMsg return TRUE;
if (m_pDocument != NULL) {
...... return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); }
return FALSE;}
BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode, void* pExtra,AFX_CMDHANDLERINFO*pHandlerInfo)
{
......
for (pMessageMap = GetMessageMap(); pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMap) { ASSERT(pMessageMap != pMessageMap->pBaseMap);
lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, nMsg, nCode, nID); if (lpEntry != NULL) { return _AfxDispatchCmdMsg(this, nID, nCode, lpEntry->pfn, pExtra, lpEntry->nSig, pHandlerInfo); }
......
}
从上面的代码可以看到,当消息WM_COMMAND从CFrameWnd进来时消息传递路径如下:View----Document----FrameWnd--WinApp.
- 浅析Windows消息在mfc中的传递路线------(Command rounting)
- MFC中的命令传递(Command Routing)
- MFC消息响应路线
- 浅析Android中的Handler的消息传递机制
- mfc 消息传递
- MFC消息传递顺序
- MFC消息传递顺序
- MFC消息传递
- MFC多线程消息传递
- MFC中消息传递
- MFC 多线程消息传递
- 消息传递在VB中的应用
- 消息传递在VB中的应用
- 浅析Command模式,反射工厂在系统中的应用
- MFC消息详解 消息传递
- MFC用PostMessage在窗体间传递消息
- MFC 自定义消息四步曲与在参数中传递变量
- 如何在MFC对话框之间自定义消息传递
- 浅谈近来国产CPU的成就
- Struts1的一个例子
- RedHat使用Centos的yum源
- ASP.NET中固定DataGrid的表头
- javascript实现的listview效果
- 浅析Windows消息在mfc中的传递路线------(Command rounting)
- 传参时的中文问题
- asp fso 功能代码部分
- Android UI开发第二十九篇——Android中五种常用的menu(菜单)
- PowerDesigner的使用安装和数据库创建
- FSO删除文件
- CvArr、Mat、CvMat、IplImage、BYTE转换(总结而来)
- Python日期操作date,计算到特定日期的时间。
- asp之字符串函数示例