首先消息分三類,分別是窗口消息,命令消息,通告消息。其中窗口消息的“流動(dòng)”是很規(guī)則的,只是縱向流動(dòng),只能從派生類流到基類,最終“流到”基類CCmdTarget...絕無“旁逸斜出”的可能。命令消息和通告消息則不同。下面以命令消息來講述命令消息的“路由”。

當(dāng)dispatch一個(gè)消息時(shí),消息首先由AfxWndProc分發(fā),在經(jīng)由AfxCallWndProc保存消息,最終調(diào)用對(duì)應(yīng)的WindowProc.在WindowProc中判斷是否是命令消息或者通告消息,是的話,分別交由OnCommand和OnNotify處理。不是的話最后交給窗口過程處理。下面討論命令消息的路由。
?不妨假設(shè)調(diào)用了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函數(shù)返回的就是與這個(gè)框架窗口關(guān)聯(lián)的視類對(duì)象。流程轉(zhuǎn)到(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并沒有改寫,所以最終調(diào)用CCmdTarge::OnCmdMsg(),這個(gè)函數(shù)最終會(huì)調(diào)用_AfxDispatchCmdMsg[文章的最好附注該函數(shù)的定義]對(duì)命令消息進(jìn)行分發(fā)處理[其他的分析和這個(gè)類似。],如果沒處理,再交由(3),由與這個(gè)視類關(guān)聯(lián)的文檔類處理。其中CDocument* m_pDocument;是CView的成員變量。如果(2),(3)都沒處理,則流程返回(4),由框架類處理,如果框架類也沒處理,則轉(zhuǎn)到(5),由應(yīng)用程序類處理。這就是命令消息的處理流程。

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;