深入显出MFC笔记(3)
MFC六大关键技术之六消息的绕行:command routing (消息的二万五千里长征)
LRESULT AfxWndProc (HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam,CWnd *pWnd)
{//推动引擎的起始点。在CWinThread:: Run 中被调用
return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam);
}
LRESULT AfxCallWndProc(CWnd* pWnd,,HWND hWnd, UINT nMsg,WPARAM wParam, LPARAM lParam)
{
LRESULT lResult = pWnd->WindowProc(nMsg, wParam, lParam);
return lResult;
} //pWnd-> Window是虚拟函数,调用pWnd指向对象的函数,但子类没有改写其实是CWnd:: WindowProc
LRESULT CWnd::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam){
AFX_MSGMAP* pMessageMap;
AFX_MSGMAP_ENTRY* lpEntry;
if (nMsg == WM_COMMAND) { // 判断消息是否为WM_COMMAND
if (OnCommand(wParam, lParam)) return 1L; //①调用 OnCommand是一个CWnd的虚拟函数
else return (LRESULT) DefWindowProc (nMsg, wParam, lParam);⑨
}//消息往父类别推去
pMessageMap = GetMessageMap();
for (; pMessageMap != NULL;pMessageMap = pMessageMap->pBaseMessageMap){
lpEntry = pMessageMap->lpEntries;
printlpEntries(lpEntry);
}
return 0;
}
1. 如果①指向CMyFrameWnd 对象,那么调用的是CFrameWnd:: OnCommand。
2. 如果①指向CMyView 对象,那么调用的是CView:: OnCommand。而因为CView并没有改写OnCommand,所以调用的其实是CWnd:: OnCommand。
BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam){//以第1种情况为例
return CWnd::OnCommand(wParam, lParam); //②
}
BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam){
return OnCmdMsg(0, 0); //③是CCmdTarget 的虚拟函数
}//③CMyFrameWnd/CMyView/CMyDoc的对象使用CFrameWnd/CView/CDoc::OnCmdMsg
//CMyWinApp对象并没有改写OnCmdMsg ,所以调用的是CCmdTarget::OnCmdMsg
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode){
CView* pView = GetActiveView();
if (pView->OnCmdMsg(nID, nCode)) return TRUE;//④
if (CWnd::OnCmdMsg(nID, nCode)) return TRUE;//⑦
CWinApp* pApp = AfxGetApp();
if (pApp->OnCmdMsg(nID, nCode)) return TRUE;//⑧
return FALSE;
}//Frame窗口处理WM_COMMAND 的次序。最先调用的是pView-> OnCmdMsg ④
BOOL CView::OnCmdMsg(UINT nID, int nCode){
if (CWnd::OnCmdMsg(nID, nCode)) return TRUE;//⑤
BOOL bHandled = FALSE;
bHandled = m_pDocument->OnCmdMsg(nID, nCode); //⑥
return bHandled;
}//View窗口处理WM_COMMAND 的次序。最先调用⑤CWnd::OnCmdMsg,CCmdTarget:: OnCmdMsg:
BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode){
AFX_MSGMAP* pMessageMap;
AFX_MSGMAP_ENTRY* lpEntry;
for (pMessageMap = GetMessageMap() ; pMessageMap != NULL;
pMessageMap = pMessageMap->pBaseMessageMap){
lpEntry = pMessageMap->lpEntries;
printlpEntries(lpEntry);
}
return FALSE; // not handled
}
如果在映射表中找到了对应的消息,就调用对应的处理例程,然后也就结束了二万五千里长征。如果没找到,长征还没有结束,这时候退守回到CView:: OnCmdMsg ,调用⑥CDocument:: OnCmdMsg:
BOOL CDocument::OnCmdMsg(UINT nID, int nCode){
if (CCmdTarget::OnCmdMsg(nID, nCode) return TRUE;
return FALSE;
}
如果在映射表中还是没找到对应消息,这时候退到CFrameWnd::OnCmdMsg,调用⑦CWnd:: OnCmdMsg (也就是CCmdTarge t:: OnCmdMsg)
如果在映射表中还是没找到对应消息,再退回到CFrameWnd:: OnCmdMsg,调用⑧CWinApp :: OnCmdMsg(亦即CCmdTarge t:: OnCmdMsg )
还是没找到对应的消息,退回到⑨CWnd::WindowProc,调用 CWnd:: DefWindowProc。你可以想象,在真正的MFC 中这个成员函数必是调用Windows API 函数:: DefWindowProc。
分别从frame 对象和view 对象中推动消息,消息分一般Windows 消息WM_COMMAND
// test Message Routing
AfxWndProc(0, WM_CREATE, 0, 0, pMyFrame);
AfxWndProc(0, WM_PAINT, 0, 0, pMyView);
AfxWndProc(0, WM_COMMAND, 0, 0, pMyView);
AfxWndProc(0, WM_COMMAND, 0, 0, pMyFrame);