据说是在Run中调用AfxWndProc(侯捷说的我在源码中找了会没找到,也不晓得是哪个间接调用的),在该函数里面接着调用AfxCallWndProc,然后AfxCallWndProc中有这么一段
// special case for WM_INITDIALOG
CRect rectOld;
DWORD dwStyle = 0;
if (nMsg == WM_INITDIALOG)
_AfxPreInitDialog(pWnd, &rectOld, &dwStyle);
// delegate to object's WindowProc
lResult = pWnd->WindowProc(nMsg, wParam, lParam);
// more special case for WM_INITDIALOG
if (nMsg == WM_INITDIALOG)
_AfxPostInitDialog(pWnd, rectOld, dwStyle);
如果不是WM_INITDIALOG消息则调用CWnd的WindowProc,这时就有点迷惑了,应该说CCmdTarget是处理消息的基类其中的OnCmdMsg为什么不先调用呢,其实我也不清楚,查看了源代码后发现在WindowProc中会判断消息的类型里面有这么段:
CWnd::WindowProc
if (message == WM_COMMAND)
{
if (OnCommand(wParam, lParam))
{
lResult = 1;
goto LReturnTrue;
}
return FALSE;
}
CWnd::OnCommand
如果是命令消息加速键等用户接口对象的WM_COMMAND通知消息(有些控件也会发送此消息比如按钮的单击),则调用OnCommand处理,而在OnCommand中会判断是一般命令消息还是控件消息,其中如果不是控件消息的话会调用OnCmdMsg(nID, CN_UPDATE_COMMAND_UI, &state, NULL);看到了吧这里就调用了从CCmdTarget继承来的虚函数(我只找到了CWnd的这个地方调用了改消息)。
接着是控件消息
// special case for notifies
if (message == WM_NOTIFY)
{
NMHDR* pNMHDR = (NMHDR*)lParam;
if (pNMHDR->hwndFrom != NULL && OnNotify(wParam, lParam, &lResult))
goto LReturnTrue;
return FALSE;
}
关于WM_NOTIFY的一点说明: Win32使用新的WM_NOFITY来处理复杂的通知消息。WM_COMMAND类型的通知消息仅仅能传递一个控制窗口句柄(lparam)、控制窗ID和通知代码(wparam)。WM_NOTIFY能传递任意复杂的信息。
因此控件消息也得以处理,WindowProc后面的消息处理可想而知了即其他WM开头的Windows标准消息。
CFrameWnd中改写了OnCmdMsg
BOOL CFrameWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
AFX_CMDHANDLERINFO* pHandlerInfo)
{
CPushRoutingFrame push(this);
// pump through current view FIRST
CView* pView = GetActiveView();
if (pView != NULL && pView->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// then pump through frame
if (CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// last but not least, pump through app
CWinApp* pApp = AfxGetApp();
if (pApp != NULL && pApp->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
return FALSE;
}
由于在CFrameWnd中产生的消息一般都是WM_COMMAND消息,因此当CWnd::WindowProc被调用时会转到OnCommand而CFrameWnd又改写了CWnd的OnCommand那么CFrameWnd的OnCmdMsg是如何被调用的呢,原来在CFrameWnd::OnCommand中调用了CWnd的OnCommand,显然CFrameWnd::OnCmdMsg就被调用了,由上面的CFrameWnd::OnCmdMsg可以清楚的看到CFrameWnd对标准消息传递的过程的改写首先让当前的活动视图处理,通过查看视图的源代码可以发现视图的OnCmdMsg先让CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)处理(最终就是调用CCmdTarget::OnCmdMsg,通过查看源代码可以发现// look through message map to see if it applies to us,其实就是查找此视图及相关基类的消息映射表进行相应的处理),接着是让m_pDocument->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);处理,不用查看文档的代码也可以猜到文档模板的OnCmdMsg会调用,当视图的OnCmdMsg返回后如果没有处理的话又会调用CWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo)(此时是CFrameWnd处理),最后如果还没有处理的话又给App对象处理,一直到让DefWindowProc处理。
对话框的消息处理与此不同,具体可以根据源代码追踪
呵呵,第一次跟踪查找MFC源代码,不知道以上结论正确与否,不过对我理解消息传递的过程还是有点帮助,写下来以免忘了。
评论