精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>● VB和Basic>>〓〓..技术文章连载..〓〓>>MFC消息机制>>[转载自白云黄鹤]MFC消息机制(四)

主题:[转载自白云黄鹤]MFC消息机制(四)
发信人: sodo()
整理人: cobe(1999-12-17 10:27:41), 站内信件
消息处理转入CWnd类了, 

LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 


// OnWndMsg does most of the work, except for DefWindowProc call 
LRESULT lResult = 0; 
if (!OnWndMsg(message, wParam, lParam, &lResult)) 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
处理窗口消息 

lResult = DefWindowProc(message, wParam, lParam); 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
如果没有处理,就调用DefWindowProc, 
呵呵,和我们以前用C写Windows程序一样!! 
return lResult; 


BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESUL
T* pResult) 

LRESULT lResult = 0; 

// special case for commands 
if (message == WM_COMMAND) 
{ ^^^^^^^^^^ WM_COMMAND消息? 
if (OnCommand(wParam, lParam)) 
{ ^^^^^^^^^^^^^^^^^^^^^^^^^ 
调用OnCommand函数,这是一个虚函数 
lResult = 1; 
goto LReturnTrue; 

return FALSE; 


// special case for notifies 
if (message == WM_NOTIFY) 
{ ^^^^^^^^^ 通告消息? 
NMHDR* pNMHDR = (NMHDR*)lParam; 
if (pNMHDR->hwndFrom != NULL && 
OnNotify(wParam, lParam, &lResult)) 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
调用OnNotify函数,也是一个虚函数 
goto LReturnTrue; 
return FALSE; 


// special case for activation 
if (message == WM_ACTIVATE) 
_AfxHandleActivate(this, wParam, CWnd::FromHandle((HWND)lParam)); 

// special case for set cursor HTERROR 
if (message == WM_SETCURSOR && 
_AfxHandleSetCursor(this, (short)LOWORD(lParam), HIWORD(lParam))) 

lResult = 1; 
goto LReturnTrue; 


const AFX_MSGMAP* pMessageMap; pMessageMap = GetMessageMap(); 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
GetMessageMap返回当前类的消息映射表 

UINT iHash; iHash = (LOWORD((DWORD)pMessageMap) ^ message) & (iHashMax
-1); 
AfxLockGlobals(CRIT_WINMSGCACHE); 
AFX_MSG_CACHE* pMsgCache; pMsgCache = &_afxMsgCache[iHash]; 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
为了查找消息更快,微软实现了一个消息cache! 
const AFX_MSGMAP_ENTRY* lpEntry; 
if (message == pMsgCache->nMsg && pMessageMap == pMsgCache->pMessageMa
p) 

// 消息在cache里,命中 
lpEntry = pMsgCache->lpEntry; 
AfxUnlockGlobals(CRIT_WINMSGCACHE); 
if (lpEntry == NULL) 
return FALSE; 

// cache hit, and it needs to be handled 
if (message < 0xC000)
goto LDispatch;
else
goto LDispatchRegistered;
}
else
{
// 不在cache里面,只好查找整个消息映射表
pMsgCache->nMsg = message; 
pMsgCache->pMessageMap = pMessageMap; 

#ifdef _AFXDLL 
for (/* pMessageMap already init'ed */; pMessageMap != NULL; 
pMessageMap = (*pMessageMap->pfnGetBaseMap)()) 
#else 
for (/* pMessageMap already init'ed */; pMessageMap != NULL; 
pMessageMap = pMessageMap->pBaseMap) 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
从最高层类一层一层往下找 
#endif 

// Note: catch not so common but fatal mistake!! 
// BEGIN_MESSAGE_MAP(CMyWnd, CMyWnd) 
#ifdef _AFXDLL 
ASSERT(pMessageMap != (*pMessageMap->pfnGetBaseMap)()); 
#else 
ASSERT(pMessageMap != pMessageMap->pBaseMap); 
#endif 

if (message < 0xC000)
{
// constant window message
if ((lpEntry = AfxFindMessageEntry(pMessageMap->lpEntries, 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
这是一个汇编写的查找消息处理入口的函数 
message, 0, 0)) != NULL) 

pMsgCache->lpEntry = lpEntry; 
AfxUnlockGlobals(CRIT_WINMSGCACHE); 
goto LDispatch; 


else 

// registered windows message 
lpEntry = pMessageMap->lpEntries; 
while ((lpEntry = AfxFindMessageEntry(lpEntry, 0xC000, 0, 0)) != NULL)
 

UINT* pnID = (UINT*)(lpEntry->nSig); 
ASSERT(*pnID >= 0xC000 || *pnID == 0); 
// must be successfully registered 
if (*pnID == message) 

pMsgCache->lpEntry = lpEntry; 
AfxUnlockGlobals(CRIT_WINMSGCACHE); 
goto LDispatchRegistered; 

lpEntry++; // keep looking past this one 




pMsgCache->lpEntry = NULL; 
AfxUnlockGlobals(CRIT_WINMSGCACHE); 
return FALSE; 

ASSERT(FALSE); // not reached 

LDispatch: //消息处理函数找到了就转到此处了 
ASSERT(message < 0xC000);
union MessageMapFunctions mmf;
mmf.pfn = lpEntry->pfn; 

// if we've got WM_SETTINGCHANGE / WM_WININICHANGE, we need to 
// decide if we're going to call OnWinIniChange() or OnSettingChange()
 

int nSig; 
nSig = lpEntry->nSig; 
^^^^^^^^^^^^^^^^^^^^ 
if (lpEntry->nID == WM_SETTINGCHANGE) 

DWORD dwVersion = GetVersion(); 
if (LOBYTE(LOWORD(dwVersion)) >= 4) 
nSig = AfxSig_vws; 
else 
nSig = AfxSig_vs; 


switch (nSig) 
{// nSig为消息参数类型,详细解释见后 
default: 
ASSERT(FALSE); 
break; 

case AfxSig_bD: 
lResult = (this->*mmf.pfn_bD)(CDC::FromHandle((HDC)wParam)); 
^^^ mmf就是我们在Message Map里面设的消息处理函数 
它是一个共用体(union),其中定义了 
带有各种不同参数形式的函数。 
break; 

case AfxSig_bb: // AfxSig_bb, AfxSig_bw, AfxSig_bh 
lResult = (this->*mmf.pfn_bb)((BOOL)wParam); 
break; 

case AfxSig_bWww: // really AfxSig_bWiw 
lResult = (this->*mmf.pfn_bWww)(CWnd::FromHandle((HWND)wParam), 
(short)LOWORD(lParam), HIWORD(lParam)); 
break; 

case AfxSig_bWCDS: 
lResult = (this->*mmf.pfn_bWCDS)(CWnd::FromHandle((HWND)lParam), 
(COPYDATASTRUCT*) lParam); 
break; 

case AfxSig_bHELPINFO: 
lResult = (this->*mmf.pfn_bHELPINFO)((HELPINFO*)lParam); 
break; 

case AfxSig_hDWw: 

// special case for OnCtlColor to avoid too many temporary objects 
ASSERT(message == WM_CTLCOLOR); 
AFX_CTLCOLOR* pCtl = (AFX_CTLCOLOR*)lParam; 
CDC dcTemp; dcTemp.m_hDC = pCtl->hDC; 
CWnd wndTemp; wndTemp.m_hWnd = pCtl->hWnd; 
UINT nCtlType = pCtl->nCtlType; 
// if not coming from a permanent window, use stack temporary 
CWnd* pWnd = CWnd::FromHandlePermanent(wndTemp.m_hWnd); 
if (pWnd == NULL) 

#ifndef _AFX_NO_OCC_SUPPORT 
// determine the site of the OLE control if it is one 
COleControlSite* pSite; 
if (m_pCtrlCont != NULL && (pSite = (COleControlSite*) 
m_pCtrlCont->m_siteMap.GetValueAt(wndTemp.m_hWnd)) != NULL) 

wndTemp.m_pCtrlSite = pSite; 

#endif 
pWnd = &wndTemp; 

HBRUSH hbr = (this->*mmf.pfn_hDWw)(&dcTemp, pWnd, nCtlType); 
// fast detach of temporary objects 
dcTemp.m_hDC = NULL; 
wndTemp.m_hWnd = NULL; 
lResult = (LRESULT)hbr; 

break; 

case AfxSig_hDw: 

// special case for CtlColor to avoid too many temporary objects 
ASSERT(message == WM_REFLECT_BASE+WM_CTLCOLOR); 
AFX_CTLCOLOR* pCtl = (AFX_CTLCOLOR*)lParam; 
CDC dcTemp; dcTemp.m_hDC = pCtl->hDC; 
UINT nCtlType = pCtl->nCtlType; 
HBRUSH hbr = (this->*mmf.pfn_hDw)(&dcTemp, nCtlType); 
// fast detach of temporary objects 
dcTemp.m_hDC = NULL; 
lResult = (LRESULT)hbr; 

break; 

case AfxSig_iwWw: 
lResult = (this->*mmf.pfn_iwWw)(LOWORD(wParam), 
CWnd::FromHandle((HWND)lParam), HIWORD(wParam)); 
break; 

case AfxSig_iww: 
lResult = (this->*mmf.pfn_iww)(LOWORD(wParam), HIWORD(wParam)); 
break; 

case AfxSig_iWww: // really AfxSig_iWiw 
lResult = (this->*mmf.pfn_iWww)(CWnd::FromHandle((HWND)wParam), 
(short)LOWORD(lParam), HIWORD(lParam)); 
break; 

case AfxSig_is: 
lResult = (this->*mmf.pfn_is)((LPTSTR)lParam); 
break; 

case AfxSig_lwl: 
lResult = (this->*mmf.pfn_lwl)(wParam, lParam); 
break; 

case AfxSig_lwwM: 
lResult = (this->*mmf.pfn_lwwM)((UINT)LOWORD(wParam), 
(UINT)HIWORD(wParam), (CMenu*)CMenu::FromHandle((HMENU)lParam)); 
break; 

case AfxSig_vv: 
(this->*mmf.pfn_vv)(); 
break; 

case AfxSig_vw: // AfxSig_vb, AfxSig_vh 
(this->*mmf.pfn_vw)(wParam); 
break; 

case AfxSig_vww: 
(this->*mmf.pfn_vww)((UINT)wParam, (UINT)lParam); 
break; 

case AfxSig_vvii: 
(this->*mmf.pfn_vvii)((short)LOWORD(lParam), (short)HIWORD(lParam)); 

break; 

case AfxSig_vwww: 
(this->*mmf.pfn_vwww)(wParam, LOWORD(lParam), HIWORD(lParam)); 
break; 

case AfxSig_vwii: 
(this->*mmf.pfn_vwii)(wParam, LOWORD(lParam), HIWORD(lParam)); 
break; 

case AfxSig_vwl: 
(this->*mmf.pfn_vwl)(wParam, lParam); 
break; 

case AfxSig_vbWW: 
(this->*mmf.pfn_vbWW)(m_hWnd == (HWND)lParam, 
CWnd::FromHandle((HWND)lParam), 
CWnd::FromHandle((HWND)wParam)); 
break; 

case AfxSig_vD: 
(this->*mmf.pfn_vD)(CDC::FromHandle((HDC)wParam)); 
break; 

case AfxSig_vM: 
(this->*mmf.pfn_vM)(CMenu::FromHandle((HMENU)wParam)); 
break; 

case AfxSig_vMwb: 
(this->*mmf.pfn_vMwb)(CMenu::FromHandle((HMENU)wParam), 
LOWORD(lParam), (BOOL)HIWORD(lParam)); 
break; 

case AfxSig_vW: 
(this->*mmf.pfn_vW)(CWnd::FromHandle((HWND)wParam)); 
break; 

case AfxSig_vW2: 
(this->*mmf.pfn_vW)(CWnd::FromHandle((HWND)lParam)); 
break; 

case AfxSig_vWww: 
(this->*mmf.pfn_vWww)(CWnd::FromHandle((HWND)wParam), LOWORD(lParam), 

HIWORD(lParam)); 
break; 

case AfxSig_vWp: 

CPoint point((DWORD)lParam); 
(this->*mmf.pfn_vWp)(CWnd::FromHandle((HWND)wParam), point); 

break; 

case AfxSig_vWh: 
(this->*mmf.pfn_vWh)(CWnd::FromHandle((HWND)wParam), 
(HANDLE)lParam); 
break; 

case AfxSig_vwW: 
(this->*mmf.pfn_vwW)(wParam, CWnd::FromHandle((HWND)lParam)); 
break; 

case AfxSig_vwWb: 
(this->*mmf.pfn_vwWb)((UINT)(LOWORD(wParam)), 
CWnd::FromHandle((HWND)lParam), (BOOL)HIWORD(wParam)); 
break; 

case AfxSig_vwwW: 
case AfxSig_vwwx: 

// special case for WM_VSCROLL and WM_HSCROLL 
ASSERT(message == WM_VSCROLL || message == WM_HSCROLL || 
message == WM_VSCROLL+WM_REFLECT_BASE || message == WM_HSCROLL+WM_REFL
ECT_BASE); 
int nScrollCode = (short)LOWORD(wParam); 
int nPos = (short)HIWORD(wParam); 
if (lpEntry->nSig == AfxSig_vwwW) 
(this->*mmf.pfn_vwwW)(nScrollCode, nPos, 
CWnd::FromHandle((HWND)lParam)); 
else 
(this->*mmf.pfn_vwwx)(nScrollCode, nPos); 

break; 

case AfxSig_vs: 
(this->*mmf.pfn_vs)((LPTSTR)lParam); 
break; 

case AfxSig_vws: 
(this->*mmf.pfn_vws)((UINT) wParam, (LPCTSTR)lParam); 
break; 

case AfxSig_vOWNER: 
(this->*mmf.pfn_vOWNER)((int)wParam, (LPTSTR)lParam); 
lResult = TRUE; 
break; 

case AfxSig_iis: 
lResult = (this->*mmf.pfn_iis)((int)wParam, (LPTSTR)lParam); 
break; 

case AfxSig_wp: 

CPoint point((DWORD)lParam); 
lResult = (this->*mmf.pfn_wp)(point); 

break; 

case AfxSig_wv: // AfxSig_bv, AfxSig_wv 
lResult = (this->*mmf.pfn_wv)(); 
break; 

case AfxSig_vCALC: 
(this->*mmf.pfn_vCALC)((BOOL)wParam, (NCCALCSIZE_PARAMS*)lParam); 
break; 

case AfxSig_vPOS: 
(this->*mmf.pfn_vPOS)((WINDOWPOS*)lParam); 
break; 

case AfxSig_vwwh: 
(this->*mmf.pfn_vwwh)(LOWORD(wParam), HIWORD(wParam), (HANDLE)lParam);
 
break; 

case AfxSig_vwp: 

CPoint point((DWORD)lParam); 
(this->*mmf.pfn_vwp)(wParam, point); 
break; 

case AfxSig_vwSIZING: 
(this->*mmf.pfn_vwl)(wParam, lParam); 
lResult = TRUE; 
break; 

case AfxSig_bwsp: 
lResult = (this->*mmf.pfn_bwsp)(LOWORD(wParam), (short) HIWORD(wParam)

CPoint(LOWORD(lParam), HIWORD(lParam))); 
if (!lResult) 
return FALSE; 

goto LReturnTrue; 

LDispatchRegistered: // for registered windows messages 
ASSERT(message >= 0xC000); 
mmf.pfn = lpEntry->pfn; 
lResult = (this->*mmf.pfn_lwl)(wParam, lParam); 

LReturnTrue: 
if (pResult != NULL) 
*pResult = lResult; 
return TRUE; 


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); 


enum AfxSig // 消息处理函数的参数类型 

AfxSig_end = 0, // [marks end of message map] 

AfxSig_bD, // BOOL (CDC*) 
^^ 
|+--------------- D表示CDC* 
+---------------- b表示返回值为bool型 
AfxSig_bb, // BOOL (BOOL) 
AfxSig_bWww, // BOOL (CWnd*, UINT, UINT) 
AfxSig_hDWw, // HBRUSH (CDC*, CWnd*, UINT) 
AfxSig_hDw, // HBRUSH (CDC*, UINT) 
AfxSig_iwWw, // int (UINT, CWnd*, UINT) 
AfxSig_iww, // int (UINT, UINT) 
AfxSig_iWww, // int (CWnd*, UINT, UINT) 
AfxSig_is, // int (LPTSTR) 
AfxSig_lwl, // LRESULT (WPARAM, LPARAM) 
AfxSig_lwwM, // LRESULT (UINT, UINT, CMenu*) 
AfxSig_vv, // void (void) 
^^^^^^^^^ 举个例子,如WM_PAINT消息, 
在BEGIN_MESSAGE_MAP里面我们定义的消息处理函数为 
ON_WM_PAINT() 
察看我们前面剖析过程,知道 
#define ON_WM_PAINT() \ 
{ WM_PAINT, 0, 0, 0, AfxSig_vv, \ 

所以处理函数的形式即为 
OnPaint() 
即没有参数,没有返回值。 
采用这种方法,就可以避免把没用的wParam和lParam参数传给用户 

AfxSig_vw, // void (UINT) 
AfxSig_vww, // void (UINT, UINT) 
AfxSig_vvii, // void (int, int) // wParam is ignored 
AfxSig_vwww, // void (UINT, UINT, UINT) 
AfxSig_vwii, // void (UINT, int, int) 
AfxSig_vwl, // void (UINT, LPARAM) 
AfxSig_vbWW, // void (BOOL, CWnd*, CWnd*) 
AfxSig_vD, // void (CDC*) 

AfxSig_vM, // void (CMenu*) 
AfxSig_vMwb, // void (CMenu*, UINT, BOOL) 

AfxSig_vW, // void (CWnd*) 
AfxSig_vWww, // void (CWnd*, UINT, UINT) 
AfxSig_vWp, // void (CWnd*, CPoint) 
AfxSig_vWh, // void (CWnd*, HANDLE) 
AfxSig_vwW, // void (UINT, CWnd*) 
AfxSig_vwWb, // void (UINT, CWnd*, BOOL) 
AfxSig_vwwW, // void (UINT, UINT, CWnd*) 
AfxSig_vwwx, // void (UINT, UINT) 
AfxSig_vs, // void (LPTSTR) 
AfxSig_vOWNER, // void (int, LPTSTR), force return TRUE 
AfxSig_iis, // int (int, LPTSTR) 
AfxSig_wp, // UINT (CPoint) 
AfxSig_wv, // UINT (void) 
AfxSig_vPOS, // void (WINDOWPOS*) 
AfxSig_vCALC, // void (BOOL, NCCALCSIZE_PARAMS*) 
AfxSig_vNMHDRpl, // void (NMHDR*, LRESULT*) 
AfxSig_bNMHDRpl, // BOOL (NMHDR*, LRESULT*) 
AfxSig_vwNMHDRpl, // void (UINT, NMHDR*, LRESULT*) 
AfxSig_bwNMHDRpl, // BOOL (UINT, NMHDR*, LRESULT*) 
AfxSig_bHELPINFO, // BOOL (HELPINFO*) 
AfxSig_vwSIZING, // void (UINT, LPRECT) -- return TRUE 

// signatures specific to CCmdTarget 
AfxSig_cmdui, // void (CCmdUI*) 
AfxSig_cmduiw, // void (CCmdUI*, UINT) 
AfxSig_vpv, // void (void*) 
AfxSig_bpv, // BOOL (void*) 

// Other aliases (based on implementation) 
AfxSig_vwwh, // void (UINT, UINT, HANDLE) 
AfxSig_vwp, // void (UINT, CPoint) 
AfxSig_bw = AfxSig_bb, // BOOL (UINT) 
AfxSig_bh = AfxSig_bb, // BOOL (HANDLE) 
AfxSig_iw = AfxSig_bb, // int (UINT) 
AfxSig_ww = AfxSig_bb, // UINT (UINT) 
AfxSig_bv = AfxSig_wv, // BOOL (void) 
AfxSig_hv = AfxSig_wv, // HANDLE (void) 
AfxSig_vb = AfxSig_vw, // void (BOOL) 
AfxSig_vbh = AfxSig_vww, // void (BOOL, HANDLE) 
AfxSig_vbw = AfxSig_vww, // void (BOOL, UINT) 
AfxSig_vhh = AfxSig_vww, // void (HANDLE, HANDLE) 
AfxSig_vh = AfxSig_vw, // void (HANDLE) 
AfxSig_viSS = AfxSig_vwl, // void (int, STYLESTRUCT*) 
AfxSig_bwl = AfxSig_lwl, 
AfxSig_vwMOVING = AfxSig_vwSIZING, // void (UINT, LPRECT) -- return TR
UE 

AfxSig_vW2, // void (CWnd*) (CWnd* comes from lParam) 
AfxSig_bWCDS, // BOOL (CWnd*, COPYDATASTRUCT*) 
AfxSig_bwsp, // BOOL (UINT, short, CPoint) 
AfxSig_vws, 
}; 

*** Finished *** 

--
十年磨一剑,霜寒未曾试;
今日拔剑问,谁有不平事?
        ----老猫

※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.103.47.234]

[关闭][返回]