首先消息分三类,分别是窗口消息,命令消息,通告消息。其中窗口消息的“流动”是很规则的,只是纵向流动,只能从派生类流到基类,最终“流到”基类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;
网友评论