Wednesday, September 23, 2009
一、Frame8中Command消息的分发
cout << endl << "pMyView received a WM_COMMAND, routing path :" << endl;
AfxWndProc(0, WM_COMMAND, 0, 0, pMyView);
1,函数调用栈:
AfxCallWndProc(pMyView, 0, WM_COMMAND, 0, 0);
pMyView ->WindowProc(WM_COMMAND, 0, 0);
2,代码进入:
注意this指针指向CMyView,
LRESULT CWnd::WindowProc(WM_COMMAND, 0, 0)
{
AFX_MSGMAP* pMessageMap;
AFX_MSGMAP_ENTRY* lpEntry;
if (nMsg == WM_COMMAND) // special case for commands
{
L5: if (OnCommand(wParam, lParam))
return 1L; // command handled
else
L8: return (LRESULT)DefWindowProc(nMsg, wParam, lParam);
}
pMessageMap = GetMessageMap();
for (; pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMessageMap)
{
lpEntry = pMessageMap->lpEntries;
printlpEntries(lpEntry);
}
return 0; // add by JJHou. if find, should call lpEntry->pfn,
// otherwise should call DefWindowProc.
}
3,Line5,OnCommand的执行
if (OnCommand(wParam, lParam))详细看看这个句子:
pMyView-> OnCommand
CMyView与CView类都没有重写OnCommand
再基类CWnd有OnCommand函数的定义,this指针还是指向CMyView:
BOOL CWnd::OnCommand(WPARAM wParam, LPARAM lParam)
{
// ...
return OnCmdMsg(0, 0);
}
4,OnCommand的执行
于是上面的一句OnCommand(0,0);
实际上是调用CMyView:OnCommand;
但是CMyView没有重写这个重写这个虚函数,CView重写了,继续调用:
BOOL CView::OnCmdMsg(UINT nID, int nCode) // this指针还是CMyView
{
L1: if (CWnd::OnCmdMsg(nID, nCode))
return TRUE;
BOOL bHandled = FALSE;
L4: bHandled = m_pDocument->OnCmdMsg(nID, nCode);
return bHandled;
}
5,看看上面CWnd::OnCmdMsg(0, 0)的执行过程
CWnd并没有复习OnCmdMsg函数,
执行的代码是:this指针仍然是指向pMyView的,这决定了GetMessageMap返回的内容。
BOOL CCmdTarget::OnCmdMsg(UINT nID, int nCode)
{
// Now look through message map to see if it applies to us
AFX_MSGMAP* pMessageMap;
AFX_MSGMAP_ENTRY* lpEntry;
for (pMessageMap = GetMessageMap(); pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMessageMap)
{
lpEntry = pMessageMap->lpEntries;
printlpEntries(lpEntry); // 继续那个只能打印第一条的打印函数
}
return FALSE; // not handled
}
于是第4项目,L1的输出是:
1221 CMyView
122 CView
12 CWnd
1 CCmdTarget
6,第4项目L4的执行
bHandled = m_pDocument->OnCmdMsg(nID, nCode);
CMyDocument是被CMyView聚合的,自然可以能用上面的方式增强功能。
CMyDocument没有重写OnCmdMsg,其基类进行了重写
BOOL CDocument::OnCmdMsg(UINT nID, int nCode)
{
if (CCmdTarget::OnCmdMsg(nID, nCode)) // 按照代码看,加入了返回值的判断。
return TRUE;
return FALSE;
}
由于这些函数在执行时this指针一直是指向CMyDoc的,所以
打印结果:
131 CMyDoc
13 CDocument
1 CCmdTarget
7,由于OnCmdMsg的代码都是调用CCmdTarget::OnCmdMsg实现的,这个函数默认返回FALSE,调用者保持返回值不变,一路返回FALSE,WindowProc进入L8分支:
LRESULT CWnd::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
return TRUE;
}
CWnd::WindowProc返回了。
8,总结
消息分开在两个线索中处理是写在
CView::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;
}
意思是如果CView系的类没有出来Cmd消息,返回先不返回,再给下面被聚合的CMyDocument看看是不是需要处理。