Tuesday, 0922
一、Frame8消息的打印显示
1、主函数中的代码:
// test Message Routing
cout << endl << "pMyFrame received a WM_CREATE, routing path :" << endl;
AfxWndProc(0, WM_CREATE, 0, 0, pMyFrame);
对应的执行代码:
LRESULT CMyFrameWnd::WindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)
{
AFX_MSGMAP* pMessageMap;
AFX_MSGMAP_ENTRY* lpEntry;
if (nMsg == WM_COMMAND) // special case for commands
{
if (OnCommand(wParam, lParam))
return 1L; // command handled
else
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.
}
2、MSGMAP的本质是链表
struct AFX_MSGMAP
{
AFX_MSGMAP* pBaseMessageMap;
AFX_MSGMAP_ENTRY* lpEntries;
};
AFX_MSGMAP就是一个链表Node结构
pBaseMessageMap就是next指针;
AFX_MSGMAP_ENTRY* lpEntries;就是链表Node的data。
而且这个链表只有尾部没有头部,头部无限延伸,尾部如下:
在CCmdTarget处打住,next强制为NULL:
AFX_MSGMAP* CCmdTarget::GetMessageMap() const
{
return &CCmdTarget::messageMap;
}
AFX_MSGMAP CCmdTarget::messageMap =
{
NULL,
&CCmdTarget::_messageEntries[0]
};
AFX_MSGMAP_ENTRY CCmdTarget::_messageEntries[] =
{
{ 0, 0, CCmdTargetid, 0, AfxSig_end, 0 }
};
3、链表Node的DATA
是一个指针,这只是形式,本质上DATA就是一个AFX_MSGMAP_ENTRY型的数组。
struct AFX_MSGMAP_ENTRY // MFC 4.0
{
UINT nMessage; // windows message
UINT nCode; // control code or WM_NOTIFY code
UINT nID; // control ID (or 0 for windows messages)
UINT nLastID; // used for entries specifying a range of control id's
UINT nSig; // signature type (action) or pointer to message #
AFX_PMSG pfn; // routine to call (or special value)
};
4、打印一个DATA结构的函数
void printlpEntries(AFX_MSGMAP_ENTRY* lpEntry)
{
struct {
UINT classid;
char* classname;
} classinfo[] = {
CCmdTargetid , "CCmdTarget ",
CWinThreadid , "CWinThread ",
CWinAppid , "CWinApp ",
CMyWinAppid , "CMyWinApp ",
CWndid , "CWnd ",
CFrameWndid , "CFrameWnd ",
CMyFrameWndid, "CMyFrameWnd ",
CViewid , "CView ",
CMyViewid , "CMyView ",
CDocumentid , "CDocument ",
CMyDocid , "CMyDoc ",
0 , " "
};
for (int i=0; classinfo[i].classid != 0; i++)
{
// 090922comments:AFX_MSGMAP_ENTRY* lpEntry,lpEntry是指向一个AFX_MSGMAP_ENTRY数组的第一个元素。
// 但是这个for循环只检查了lpEntry的第一个元素,没有再类似lpEntry++去进行后续遍历。
// 这个for循环只是对打印机制的循环,根本就还没开始对链表的遍历,要遍历链表也是一个O(n^2)。
if (classinfo[i].classid == lpEntry->nID)
{
cout << lpEntry->nID << " ";
cout << classinfo[i].classname << endl;
break;
}
}
}
5、printlpEntries的实现有点小问题
按照这种方式即使给CMyFrameCmd加上了WM_CREATE的消息映射,也不会被遍历到。
比如:
AFX_MSGMAP_ENTRY CMyFrameWnd::_messageEntries[] =
{
{ WM_COMMAND, 0, (WORD) CMyFrameWndid, (WORD) CMyFrameWndid, AfxSig_vv, (AFX_PMSG)0 },
// 在现有的基础上加上:
{ WM_CREATE, 0, (WORD) CMyFrameWndid, (WORD) CMyFrameWndid, AfxSig_vv, (AFX_PMSG)1 },
{ 0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
};
AfxWndProc(0, WM_CREATE, 0, 0, pMyFrame); 还是无法访问到,因为printlpEntries不会访问其入参lpEntry的第2个元素。