首先消息分三类,分别是窗口消息,命令消息,通告消息。其中窗口消息的“流动”是很规则的,只是纵向流动,只能从派生类流到基类,最终“流到”基类CCmdTarget...绝无“旁逸斜出”的可能。命令消息和通告消息则不同。下面以命令消息来讲述命令消息的“路由”。

当dispatch一个消息时,消息首先由AfxWndProc分发,在经由AfxCallWndProc保存消息,最终调用对应的WindowProc.在WindowProc中判断是否是命令消息或者通告消息,是的话,分别交由OnCommand和OnNotify处理。不是的话最后交给窗口过程处理。下面讨论命令消息的路由。
不妨假设调用了CFrameWnd::OnCmdMsg,
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode) { ... ... CView* pView = GetActiveView(); if (pView->OnCmdMsg(nID, nCode)) //(1) return TRUE; ... ... if (CWnd::OnCmdMsg(nID, nCode)) //(4) return TRUE; ... ... CWinApp* pApp = AfxGetApp();
if (pApp->OnCmdMsg(nID, nCode)) //(5) return TRUE; return FALSE; }
由于在CFrameWnd中有CView* m_pViewActive; GetActiveView函数返回的就是与这个框架窗口关联的视类对象。流程转到(1),
(1):pView->OnCmdMsg,于是 BOOL CView::OnCmdMsg(UINT nID, int nCode) { ... ... if (CWnd::OnCmdMsg(nID, nCode)) //(2) return TRUE; BOOL bHandled = FALSE; bHandled = m_pDocument->OnCmdMsg(nID, nCode); //(3)
return bHandled; }
消息最终由视类中的OnCmdMsg处理,而视类的OnCmdMsg并没有改写,所以最终调用CCmdTarge::OnCmdMsg(),这个函数最终会调用_AfxDispatchCmdMsg[文章的最好附注该函数的定义]对命令消息进行分发处理[其他的分析和这个类似。],如果没处理,再交由(3),由与这个视类关联的文档类处理。其中CDocument* m_pDocument;是CView的成员变量。如果(2),(3)都没处理,则流程返回(4),由框架类处理,如果框架类也没处理,则转到(5),由应用程序类处理。这就是命令消息的处理流程。

AFX_STATIC BOOL AFXAPI _AfxDispatchCmdMsg(CCmdTarget* pTarget, UINT nID, int nCode, AFX_PMSG pfn, void* pExtra, UINT nSig, AFX_CMDHANDLERINFO* pHandlerInfo) // return TRUE to stop routing { ASSERT_VALID(pTarget); UNUSED(nCode); // unused in release builds
union MessageMapFunctions mmf; mmf.pfn = pfn; BOOL bResult = TRUE; // default is ok
if (pHandlerInfo != NULL) { // just fill in the information, don't do it pHandlerInfo->pTarget = pTarget; pHandlerInfo->pmf = mmf.pfn; return TRUE; }
switch (nSig) { case AfxSig_vv: // normal command or control notification ASSERT(CN_COMMAND == 0); // CN_COMMAND same as BN_CLICKED ASSERT(pExtra == NULL); (pTarget->*mmf.pfn_COMMAND)(); break;
case AfxSig_bv: // normal command or control notification ASSERT(CN_COMMAND == 0); // CN_COMMAND same as BN_CLICKED ASSERT(pExtra == NULL); bResult = (pTarget->*mmf.pfn_bCOMMAND)(); break;
case AfxSig_vw: // normal command or control notification in a range ASSERT(CN_COMMAND == 0); // CN_COMMAND same as BN_CLICKED ASSERT(pExtra == NULL); (pTarget->*mmf.pfn_COMMAND_RANGE)(nID); break;
case AfxSig_bw: // extended command (passed ID, returns bContinue) ASSERT(pExtra == NULL); bResult = (pTarget->*mmf.pfn_COMMAND_EX)(nID); break;
case AfxSig_vNMHDRpl: { AFX_NOTIFY* pNotify = (AFX_NOTIFY*)pExtra; ASSERT(pNotify != NULL); ASSERT(pNotify->pResult != NULL); ASSERT(pNotify->pNMHDR != NULL); (pTarget->*mmf.pfn_NOTIFY)(pNotify->pNMHDR, pNotify->pResult); } break; case AfxSig_bNMHDRpl: { AFX_NOTIFY* pNotify = (AFX_NOTIFY*)pExtra; ASSERT(pNotify != NULL); ASSERT(pNotify->pResult != NULL); ASSERT(pNotify->pNMHDR != NULL); bResult = (pTarget->*mmf.pfn_bNOTIFY)(pNotify->pNMHDR, pNotify->pResult); } break; case AfxSig_vwNMHDRpl: { AFX_NOTIFY* pNotify = (AFX_NOTIFY*)pExtra; ASSERT(pNotify != NULL); ASSERT(pNotify->pResult != NULL); ASSERT(pNotify->pNMHDR != NULL); (pTarget->*mmf.pfn_NOTIFY_RANGE)(nID, pNotify->pNMHDR, pNotify->pResult); } break; case AfxSig_bwNMHDRpl: { AFX_NOTIFY* pNotify = (AFX_NOTIFY*)pExtra; ASSERT(pNotify != NULL); ASSERT(pNotify->pResult != NULL); ASSERT(pNotify->pNMHDR != NULL); bResult = (pTarget->*mmf.pfn_NOTIFY_EX)(nID, pNotify->pNMHDR, pNotify->pResult); } break; case AfxSig_cmdui: { // ON_UPDATE_COMMAND_UI or ON_UPDATE_COMMAND_UI_REFLECT case ASSERT(CN_UPDATE_COMMAND_UI == (UINT)-1); ASSERT(nCode == CN_UPDATE_COMMAND_UI || nCode == 0xFFFF); ASSERT(pExtra != NULL); CCmdUI* pCmdUI = (CCmdUI*)pExtra; ASSERT(!pCmdUI->m_bContinueRouting); // idle - not set (pTarget->*mmf.pfn_UPDATE_COMMAND_UI)(pCmdUI); bResult = !pCmdUI->m_bContinueRouting; pCmdUI->m_bContinueRouting = FALSE; // go back to idle } break;
case AfxSig_cmduiw: { // ON_UPDATE_COMMAND_UI case ASSERT(nCode == CN_UPDATE_COMMAND_UI); ASSERT(pExtra != NULL); CCmdUI* pCmdUI = (CCmdUI*)pExtra; ASSERT(pCmdUI->m_nID == nID); // sanity assert ASSERT(!pCmdUI->m_bContinueRouting); // idle - not set (pTarget->*mmf.pfn_UPDATE_COMMAND_UI_RANGE)(pCmdUI, nID); bResult = !pCmdUI->m_bContinueRouting; pCmdUI->m_bContinueRouting = FALSE; // go back to idle } break;
// general extensibility hooks case AfxSig_vpv: (pTarget->*mmf.pfn_OTHER)(pExtra); break; case AfxSig_bpv: bResult = (pTarget->*mmf.pfn_OTHER_EX)(pExtra); break;
default: // illegal ASSERT(FALSE); return 0; } return bResult;
|