按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
AfxFindMessageEntry
WM_MAND regular window message AfxFindMessageEntry
CFrameWnd::Onmand
CFrameWnd::Onmand
msg handler
CWnd::Onmand
CWnd::Onmand
CFrameWnd::OnCmdMsg
CFrameWnd::OnCmdMsg
CView::OnCmdMsg
CView::OnCmdMsg CWnd::OnCmdMsg
CWnd::OnCmdMsg
(CCmdTarget::OnCmdMsg)
(CCmdTarget::OnCmdMsg)
CWnd::OnCmdMsg CDocument::OnCmdMsg
CWnd::OnCmdMsg CDocument::OnCmdMsg CWinApp::OnCmdMsg
CWinApp::OnCmdMsg
(CCmdTarget::OnCmdMsg)
(CCmdTarget::OnCmdMsg) (CCmdTarget::OnCmdMag)
(CCmdTarget::OnCmdMag)
CCmdTarget::OnCmdMsg
CCmdTarget::OnCmdMsg
DispatchCmdMsg
DispatchCmdMsg
DispatchCmdMsg DispatchCmdMsg
DispatchCmdMsg DispatchCmdMsg
DispatchCmdMsg
DispatchCmdMsg
msg handler FALSE FALSE FALSE
FALSE msg handler msg handler
msg handler
图9…6 构成 「消息邦浦」之各个函数的调用次序
579
…………………………………………………………Page 642……………………………………………………………
第篇 深入 MFC 程式設計
罗塞达碑石:AfxSig_xx 的奥秘
大架构建立起来了,但我还没有很仔细地解释在消息映射「网」中的_messageEntries ''
数组内容。为什么消息经由推动引擎(上一节谈的那整套家伙)推过这些数组,就可以
找到它的处理例程?
Paul DiLascia 在他的文章(! ¨ Meandering Through the Maze of MFC Message and mand
Routing! ¨,Microsoft Systems Journal ,1995/07)中形容这些数组之内一笔一笔的记录像
是罗塞达碑石,呵呵,就靠它们揭开消息映射的最后谜底了。
罗塞达碑石(Rosetta Stone ),1799 年拿破仑远征埃及时,由一名官员在尼罗河口罗塞
达发现,揭开了古埃及象形文字之谜。石碑是黑色玄武岩,高114 公分,厚28 公分,宽
72 公分。经法国学者Jean…Francois Champollion 研究后,世人因得顺利研读古埃及文献。
消息映射表的每一笔记录是这样的形式:
struct AFX_MSGMAP_ENTRY
{
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)
};
内中包括一个Windows 消息、其控制组件ID 以及通告码(notification code ,对消息的
更多描述,例如EN_CHANGED 或CBN_DROPDIOWN 等)、一个签名记号、以及一个
CCmdTarget 衍生类别的成员函数。任何一个ON_ 宏会把这六个项目初始化起来。例
如:
#define ON_WM_CREATE ()
{ WM_CREATE; 0; 0; 0; AfxSig_is;
(AFX_PMSG)(AFX_PMSGW)(int (AFX_MSG_CALL CWnd::*)(LPCREATESTRUCT))OnCreate };
你看到了可怕的类型转换动作,这完全是为了保持类型安全(type…safe )。
580
…………………………………………………………Page 643……………………………………………………………
第9章 訊息映射與命令繞行
有一个很莫名其妙的东西:AfxSig_ 。要了解它作什么用,你得先停下来几分钟,想想另
一个问题:当上一节的推动引擎比对消息并发现吻合之后,就调用对应的处理例程,但
它怎么知道要交给消息处理例程哪些参数呢?要知道,不同的消息处理例程需要不同的
参数(包括个数和类型),而其函数指针(AFX_PMSG )却都被定义为这付德行:
typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);
这么简陋的信息无法表现应该传递什么样的参数,而这正是AfxSig_ 要贡献的地方。当
推动引擎比对完成,欲调用某个消息处理例程lpEntry…》pfn 时,动作是这样子地(出现
在CWnd::OnWndMsg 和DispatchCmdMsg 中):
union MessageMapFunctions mmf;
mmf。pfn = lpEntry…》pfn;
switch (lpEntry…》nSig)
{
case AfxSig_is:
lResult = (this…》*mmf。pfn_is)((LPTSTR)lParam);
break;
case AfxSig_lwl:
lResult = (this…》*mmf。pfn_lwl)(wParam; lParam);
break;
case AfxSig_vv:
(this…》*mmf。pfn_vv)();
break;
。。。
}
注意两样东西:MessageMapFunctions 和AfxSig_ 。AfxSig_ 定义于AFXMSG_。H 档:
enum AfxSig
{
AfxSig_end = 0; // 'marks end of message map'
AfxSig_bD; // BOOL (CDC*)
AfxSig_bb; // BOOL (BOOL)
AfxSig_bWww; // BOOL (CWnd*; UINT; UINT)
AfxSig_hDWw; // HBRUSH (CDC*; CWnd*; UINT)
AfxSig_hDw; // HBRUSH (CDC*; UINT)
581
…………………………………………………………Page 644……………………………………………………………
第篇 深入 MFC 程式設計
AfxSig_i