MFC消息的路由

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

你可能感兴趣的:(MFC消息的路由)