深入浅出MFC第2版(PDF格式)-第116部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
推往AfxWndProc 去了。
这种看起来很迂回又怪异的作法,是为了包容新的3D Controls (细节就容我省略了吧),
并与MFC 2。5 兼容。下图把前述的hook 和subclassing 动作以流程图显示出来:
CFrameWnd::LoadFrame
CFrameWnd::LoadFrame
CFrameWnd::Create
CFrameWnd::Create
CWnd::CreateEx
CWnd::CreateEx 安装WH_CBT hook ,设定滤网函数
为_AfxCbtFilterHook
AfxHookWindowCreate(this)
AfxHookWindowCreate(this)
::SetWindowsHookEx(WH_CBT; _AfxCbtFilterHook ;。。。)
::SetWindowsHookEx(WH_CBT; _AfxCbtFilterHook ;。。。)
::CreateWindowEx
::CreateWindowEx
_AfxCbtFilterHook 窗口产生之前一刻,由于曾安装过
_AfxCbtFilterHook WH_CBT hook,所以滤网函数
_AfxCbtFilterHook 会先被唤起。
_AfxStandardSubclass
_AfxStandardSubclass
SetWindowLong(hWnd; GWL_WNDPROC;&AfxWndProc)
SetWindowLong(hWnd; GWL_WNDPROC;&AfxWndProc)
WND structure
subclassing 动作;改 各种消息,来自
变窗口函数。 extra bytes ::DispatchMessage
message mapping and 的唧送,或由操作
mand routing 系统直接送达。
(through message map) CWL_WNDPROC
。
&AfxWndProc
message handler
message handler
565
…………………………………………………………Page 628……………………………………………………………
第篇 深入 MFC 程式設計
不能稍息,我们还没有走出迷宫!AfxWndProc 只是消息两万五千里长征的第一站!
两万五千里长征消息的流动
一个消息从发生到被攫取,直至走向它的归宿,是一条漫漫长路。上一节我们来到了漫
漫长路的起头AfxWndProc ,这一节我要带你看看消息实际上如何推动。
消息的流动路线已隐隐有脉络可寻, 此脉络是指由BEGIN_MESSAGE_MAP 和
END_MESSAGE_MAP 以及许许多多ON_ WM_xxx 宏所构成的消息映射网。但是唧筒与
方向盘是如何设计的?一切的线索还是要靠源代码透露:
( )
// in WINCORE。CPP MFC 4。x
LRESULT CALLBACK AfxWndProc (HWND hWnd; UINT nMsg; WPARAM wParam; LPARAM lParam)
{
。。。
// messages route through message map
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd);
return AfxCallWndProc (pWnd; hWnd; nMsg; wParam; lParam);
}
LRESULT AFXAPI AfxCallWndProc (CWnd* pWnd; HWND hWnd; UINT nMsg;
WPARAM wParam = 0; LPARAM lParam = 0)
{
。。。
// delegate to object's WindowProc
lResult = pWnd…》WindowProc (nMsg; wParam; lParam);
。。。
return lResult;
}
整个MFC 中,拥有虚拟函数WindowProc 者包括CWnd、CControlBar、COleControl、
COlePropertyPage、CDialog、CReflectorWnd、CParkingWnd。一般窗口(例如Frame 视
窗、View 窗口)都衍生自CWnd,所以让我们看看CWnd::WindowProc。这个函数相当
于C++ 中的窗口函数:
( )
// in WINCORE。CPP MFC 4。x
LRESULT CWnd::WindowProc (UINT message; WPARAM wParam; LPARAM lParam)
566
…………………………………………………………Page 629……………………………………………………………
第9章 訊息映射與命令繞行
{
// OnWndMsg does most of the work; except for DefWindowProc call
LRESULT lResult = 0;
if (!OnWndMsg (message; wParam; lParam; &lResult))
lResult = DefWindowProc (message; wParam; lParam);
return lResult;
}
LRESULT CWnd::DefWindowProc (UINT nMsg; WPARAM wParam; LPARAM lParam)
{
if (m_pfnSuper != NULL)
return ::CallWindowProc(m_pfnSuper; m_hWnd; nMsg; wParam; lParam);
WNDPROC pfnWndProc;
if ((pfnWndProc = *GetSuperWndProcAddr()) == NULL)
return ::DefWindowProc(m_hWnd; nMsg; wParam; lParam);
else
return ::CallWindowProc(pfnWndProc; m_hWnd; nMsg; wParam; lParam);
}
直线上溯(一般Windows 消息)
CWnd::WindowProc 调用的OnWndMsg 是用来分辨并处理消息的专职机构;如果是命令
消息,就交给Onmand 处理,如果是通告消息(Notification ),就交给OnNotify 处
理。WM_ACTIVATE 和WM_SETCURSOR 也都有特定的处理函数。而一般的Windows 讯
息,就直接在消息映射表中上溯,寻找其归宿(消息处理例程)。为什么要特别区隔出
命令消息WM_MAND 和通告消息WM_NOTIFY 两类呢?因为它们的上溯路径不
是那么单纯地只往父类别去,它们可能需要拐个弯。
( )
#0001 // in WINCORE。CPP MFC 4。0
#0002 BOOL CWnd::OnWndMsg (UINT message; WPARAM wParam; LPARAM lParam; LRESULT* pResult)
#0003 {
#0004 LRESULT lResult = 0;
#0005
#0006 // special case for mands
#0007 if (message == WM_MAND)
#0008 {
#0009 Onmand (wParam; lParam);
#0010 。。。
#0011 }
#0012
567
…………………………………………………………Page 630……………………………………………………………
第篇 深入 MFC 程式設計
#0013 // special case for notifies
#0014 if (message == WM_NOTIFY)
#0015 {
#0016 OnNotify (wParam; lParam; &lResult);
#0017 。。。
#0018 }
#0019 。。。
#0020 const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap();
#0021 UINT iHash; iHash = (LOWORD((DWORD)pMessageMap) ^ message) & (iHashMax…1);
#0022 AfxLockGlobals(CRIT_WINMSGCACHE);
#0023 AFX_MSG_CACHE msgCache; msgCache = _afxMsgCache'iHash';
#0024 AfxUnlockGlobals(CRIT_WINMSGCACHE);
#0025
#0026 const AFX_MSGMAP_ENTRY* lpEntry;
#0027 if (。。。) //检查是否在chche 之中
#0028 {
#0029 // cache hit
#0030 lpEntry = msgCache。lpEntry;
#0031 if (lpEntry == NULL)
#0032 return FALSE;
#0033
#0034 // cache hit; and it needs to be handled
#0035 if (message 《 0xC000)
#0036 goto LDispatch;
#0037 else
#0038 goto LDispatchRegistered;
#0039 }
#0040 else
#0041 {
#0042 // not in cache; look for it
#0043 msgCache。nMsg = message;
#0044 msgCache。pMessageMap = pMessageMap;
#0045
#0046 for (/* pMessageMap already init'ed */; pMessageMap != NULL;
#0047 pMessageMap = pMessageMap…》pBaseMap)
#0048 {
#0049 //利用AfxFindMessageEntry 寻找消息映射表中
#0050 //对应的消息处理例程。如果找到,再依nMsg 为一般消息
#0051 // (《 0xC000)或自行注册之消息(》 0xC000)分别跳到
#0052 // LDispatch: 或LDispatchRegistered: 去执行。
#0053
#0054 // Note: catch not so mon but fatal mistake!!
#0055 // BEGIN_MESSAGE_MAP(CMyWnd; CMyWnd)
#0056
#0057 if (message 《 0xC000)
#0058 {
568
…………………………………………………………Page 631……………………………………………………………
第9章 訊息映射與命令繞行
#0059 // constant window message
#0060 if ((lpEntry = AfxFindMessageEntry (pMessageMap…》lpEntries;
#0061 message; 0; 0)) != NULL)
#0062 {
#0063 msgCache。lpEntry = lpEntry;
#0064 goto LDispatch;
#0065 }
#0066 }
#0067 else
#0068 {
#0069 // registered windows message
#0070 lpEntry = pMessageMap…》lpEntries;
#0071 while ((lpEntry = AfxFindMessageEntry (lpEntry; 0xC000; 0;