|

楼主 |
发表于 2007-4-6 17:09:12
|
显示全部楼层
该源代码有整整700行,不知道是不是MFC源码中最长的一个函数,在这里我只列出部分有代表性的源码。从源代码中大家也可以看得出该函数主要用于分辨消息并将消息交于其处理函数。MFC为了加快消息得分检速度在AfxFindMessageEntry函数中甚至使用了汇编代码。<br/>在CWnd::OnWndMsg中得不到处理的消息则交给CWnd: efWindowProc(相当于MFC的默认DefWindowProc函数)处理,其代码为:<br/> // Default CWnd implementation<br/> LRESULT CWnd: efWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)<br/> {<br/> if (m_pfnSuper != NULL)<br/> return ::CallWindowProc(m_pfnSuper, m_hWnd, nMsg, wParam, lParam);<p> WNDPROC pfnWndProc;<br/> if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL)<br/> return : efWindowProc(m_hWnd, nMsg, wParam, lParam);<br/> else<br/> return ::CallWindowProc(pfnWndProc, m_hWnd, nMsg, wParam, lParam);<br/> }<br/> CWnd: efWindowProc这调用了传统win32程序员熟悉的: efWindowProc(m_hWnd, nMsg, wParam, lParam);<br/>在挖掘上面源代码的同时你也看到了消息的传递路线。在MFC中CWnd以及派生于CWnd的类都拥有虚函数<br/>CWnd::WndProc(...)。</p><p><br/> /////////////////////////////////////////////////////<br/> /* 9.MFC各类消息的"行走路径 " */<br/> /////////////////////////////////////////////////////<br/> 在篇头我就将消息分了类而且到目前我们已经了解了消息的传递机制了,下面我就具体的某类消息来看看其传递路径。<br/> 无论什么消息都有AfxWndProc进入,到达CWnd::OnWndMsg函数分检消息;<br/> 对于标准消息:<br/> 标准消息一般都沿其消息映射表从本类到父类逐层查找其处理函数,若没查到着交给: efWindowProc 处理。<br/> 对于命令消息:<br/> 命令消息除了能像标准消息一样从本类到父类逐层查找其处理函数外,有时他们可能还要拐弯。<br/> 再回头看看CWnd::OnWndMsg源码是如何处理WM_COMMAND消息的:<br/> if (message == WM_COMMAND)<br/> {<br/> if (OnCommand(wParam, lParam))<br/> {<br/> lResult = 1;<br/> goto LReturnTrue;<br/> }<br/> return FALSE;<br/> }<br/> 原来交给了CWnd::OnCommand(wParam, lParam)<br/> 下面看看一个SDI程序中命令消息在Frame,View,Document以及CWinApp对象之间的传递路线。<br/> //in winfrm.cpp<br/> BOOL CFrameWnd::OnCommand(WPARAM wParam, LPARAM lParam)<br/> // return TRUE if command invocation was attempted<br/> {<br/> HWND hWndCtrl = (HWND)lParam;<br/> UINT nID = LOWORD(wParam);</p><p> CFrameWnd* pFrameWnd = GetTopLevelFrame();<br/> ASSERT_VALID(pFrameWnd);<br/> if (pFrameWnd->m_bHelpMode && hWndCtrl == NULL &&<br/> nID != ID_HELP && nID != ID_DEFAULT_HELP && nID != ID_CONTEXT_HELP)<br/> {<br/> // route as help<br/> if (!SendMessage(WM_COMMANDHELP, 0, HID_BASE_COMMAND+nID))<br/> SendMessage(WM_COMMAND, ID_DEFAULT_HELP);<br/> return TRUE;<br/> }</p><p> // route as normal command<br/> return CWnd::OnCommand(wParam, lParam);<br/> }<br/> <br/> //in wincore.cpp<br/> // CWnd command handling<br/> BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam)<br/> // return TRUE if command invocation was attempted<br/> { ...//<br/> return OnCmdMsg(nID, nCode, NULL, NULL);//CFrameWnd::OnCmdMsg<br/> }<br/> <br/> // CFrameWnd command/message routing<br/> BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,<br/> AFX_CMDHANDLERINFO* pHandlerInfo)<br/> {<br/> CPushRoutingFrame push(this);</p><p> // pump through current view FIRST<br/> CView* pView = GetActiveView();<br/> if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))<br/> return TRUE;</p><p> // then pump through frame<br/> if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))<br/> return TRUE;</p><p> // last but not least, pump through app<br/> CWinApp* pApp = AfxGetApp();<br/> if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))<br/> return TRUE;</p><p> return FALSE;<br/> }<br/> Frame的COMMAND传递顺序是View--->Frame本身-->CWinApp对象。<br/> <br/> //in viewcore.cpp<br/> BOOL CView::OnCmdMsg(UINT nID, int nCode, void* pExtra,<br/> AFX_CMDHANDLERINFO* pHandlerInfo)<br/> {<br/> // first pump through pane<br/> if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))<br/> return TRUE;</p><p> // then pump through document<br/> if (m_pDocument != NULL)<br/> {<br/> // special state for saving view before routing to document<br/> CPushRoutingView push(this);<br/> return m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);<br/> }</p><p> return FALSE;<br/> }<br/> View的COMMAND传递顺序是View本身--->Document</p><p> //in doccore.cpp<br/> BOOL CDocument::OnCmdMsg(UINT nID, int nCode, void* pExtra,<br/> AFX_CMDHANDLERINFO* pHandlerInfo)<br/> {<br/> if (CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))<br/> return TRUE;</p><p> // otherwise check template<br/> if (m_pDocTemplate != NULL &&<br/> m_pDocTemplate->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))<br/> return TRUE;</p><p> return FALSE;<br/> }<br/> Document的COMMAND传递顺序是Document本身--->Document Template<br/> 由这个例子我们可以清楚地看到WM_COMMAND的传递路径了。<br/> <br/> 对于子窗口通知:由于子窗口通知通常以WM_COMMAND形式出现,所以它的传递路径也大致与WM_COMMAND相同,这里就不详述了。 </p><p> ///////////////////////////////////////////<br/> /* 10.收尾工作 */<br/> /////////////////////////////////////////<br/> 至此,MFC消息映射与消息传递的内幕已基本被揭开,若想更深刻的理解,你就得在平时的程序开发中夺观察多思考了。</p> |
|