精华区 [关闭][返回]

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

主题:[转载自白云黄鹤]MFC消息机制(三)
发信人: sodo()
整理人: cobe(1999-12-17 10:27:11), 站内信件
先看一下窗口的建立过程: 
BOOL CWnd::Create(LPCTSTR lpszClassName, 
LPCTSTR lpszWindowName, DWORD dwStyle, 
const RECT& rect, 
CWnd* pParentWnd, UINT nID, 
CCreateContext* pContext) 

// can't use for desktop or pop-up windows (use CreateEx instead) 
ASSERT(pParentWnd != NULL); 
ASSERT((dwStyle & WS_POPUP) == 0); 

return CreateEx(0, lpszClassName, lpszWindowName, 
dwStyle | WS_CHILD, 
rect.left, rect.top, 
rect.right - rect.left, rect.bottom - rect.top, 
pParentWnd->GetSafeHwnd(), (HMENU)nID, (LPVOID)pContext); 


BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName, 
LPCTSTR lpszWindowName, DWORD dwStyle, 
int x, int y, int nWidth, int nHeight, 
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam) 

// allow modification of several common create parameters 
CREATESTRUCT cs; 
cs.dwExStyle = dwExStyle; 
cs.lpszClass = lpszClassName; 
cs.lpszName = lpszWindowName; 
cs.style = dwStyle; 
cs.x = x; 
cs.y = y; 
cs.cx = nWidth; 
cs.cy = nHeight; 
cs.hwndParent = hWndParent; 
cs.hMenu = nIDorHMenu; 
cs.hInstance = AfxGetInstanceHandle(); 
cs.lpCreateParams = lpParam; 

if (!PreCreateWindow(cs)) 

PostNcDestroy(); 
return FALSE; 


AfxHookWindowCreate(this); 
^^^^^^^^^^^^^^^^^^^^^^^^^^ 函数见后 
HWND hWnd = ::CreateWindowEx(cs.dwExStyle, cs.lpszClass, 
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy, 
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams); 

if (!AfxUnhookWindowCreate()) 
PostNcDestroy(); // cleanup if CreateWindowEx fails too soon 

if (hWnd == NULL) 
return FALSE; 
ASSERT(hWnd == m_hWnd); // should have been set in send msg hook 
return TRUE; 


// for child windows 
BOOL CWnd::PreCreateWindow(CREATESTRUCT& cs) 

if (cs.lpszClass == NULL) 

// make sure the default window class is registered 
if (!AfxDeferRegisterClass(AFX_WND_REG)) 
return FALSE; 

// no WNDCLASS provided - use child window default 
ASSERT(cs.style & WS_CHILD); 
cs.lpszClass = _afxWnd; 

return TRUE; 


void AFXAPI AfxHookWindowCreate(CWnd* pWnd) 

_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData(); 
if (pThreadState->m_pWndInit == pWnd) 
return; 

if (pThreadState->m_hHookOldCbtFilter == NULL) 

pThreadState->m_hHookOldCbtFilter = ::SetWindowsHookEx(WH_CBT, 
^^^^^^ 
Computer-based Training,当建立、删除、移动、最大化、最小化 
窗口时,将会调用钩子函数。 
_AfxCbtFilterHook, NULL, ::GetCurrentThreadId()); 
^^^^^^^^^^^^^^^^^ 钩子函数 
if (pThreadState->m_hHookOldCbtFilter == NULL) 
AfxThrowMemoryException(); 

ASSERT(pThreadState->m_hHookOldCbtFilter != NULL); 
ASSERT(pWnd != NULL); 
ASSERT(pWnd->m_hWnd == NULL); // only do once 

ASSERT(pThreadState->m_pWndInit == NULL); // hook not already in progr
ess 
pThreadState->m_pWndInit = pWnd; 


BOOL AFXAPI AfxUnhookWindowCreate() 

_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData(); 
#ifndef _AFXDLL 
if (afxContextIsDLL && pThreadState->m_hHookOldCbtFilter != NULL) 

::UnhookWindowsHookEx(pThreadState->m_hHookOldCbtFilter); 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
删除钩子函数 
pThreadState->m_hHookOldCbtFilter = NULL; 

#endif 
if (pThreadState->m_pWndInit != NULL) 

pThreadState->m_pWndInit = NULL; 
return FALSE; // was not successfully hooked 

return TRUE; 


// Window creation hooks 
LRESULT CALLBACK 
_AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam) 

_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData(); 
if (code != HCBT_CREATEWND) 
{ ^^^^^^^^^^^^^^^^^^^^^^ 是要建立窗口吗? 
// wait for HCBT_CREATEWND just pass others on... 
return CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code, 
wParam, lParam); 


ASSERT(lParam != NULL); 
LPCREATESTRUCT lpcs = ((LPCBT_CREATEWND)lParam)->lpcs; 
ASSERT(lpcs != NULL); 

// this hook exists to set the SendMessage hook on window creations 
// (but this is only done for MFC windows or non-child windows) 
// the subclassing cannot be done at this point because on Win32s 
// the window does not have the WNDPROC set yet 
CWnd* pWndInit = pThreadState->m_pWndInit; 
if (pWndInit != NULL || (!(lpcs->style & WS_CHILD) && !afxContextIsDLL
)) 

ASSERT(wParam != NULL); // should be non-NULL HWND 
HWND hWnd = (HWND)wParam; 
WNDPROC oldWndProc; 
if (pWndInit != NULL) 
{ ^^^^^^^^^^^^^^^^ 窗口建立来自一个CWnd? 
// the window should not be in the permanent map at this time 
ASSERT(CWnd::FromHandlePermanent(hWnd) == NULL); 

// connect the HWND to pWndInit... 
pWndInit->Attach(hWnd); 
// allow other subclassing to occur first 
pWndInit->PreSubclassWindow(); 

WNDPROC *pOldWndProc = pWndInit->GetSuperWndProcAddr(); 
ASSERT(pOldWndProc != NULL); 

#ifndef _MAC 
_AFX_CTL3D_STATE* pCtl3dState; 
DWORD dwFlags; 
if (!afxData.bWin4 && !afxContextIsDLL && 
(pCtl3dState = _afxCtl3dState.GetDataNA()) != NULL && 
pCtl3dState->m_pfnSubclassDlgEx != NULL && 
(dwFlags = AfxCallWndProc(pWndInit, hWnd, WM_QUERY3DCONTROLS)) != 0) 


// was the class registered with AfxWndProc? 
WNDPROC afxWndProc = AfxGetAfxWndProc(); 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
函数见后 
BOOL bAfxWndProc = ((WNDPROC) 
GetWindowLong(hWnd, GWL_WNDPROC) == afxWndProc); 

pCtl3dState->m_pfnSubclassDlgEx(hWnd, dwFlags); 

// subclass the window if not already wired to AfxWndProc 
if (!bAfxWndProc) 

// subclass the window with standard AfxWndProc 
oldWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, 
(DWORD)afxWndProc); // 修改窗口的WndProc!!! 

ASSERT(oldWndProc != NULL); 
*pOldWndProc = oldWndProc; 


else 
#endif 

// subclass the window with standard AfxWndProc 
WNDPROC afxWndProc = AfxGetAfxWndProc(); 
oldWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC, 
(DWORD)afxWndProc); 
ASSERT(oldWndProc != NULL); 
if (oldWndProc != afxWndProc) 
*pOldWndProc = oldWndProc; 

pThreadState->m_pWndInit = NULL; 

else 

ASSERT(!afxContextIsDLL); // should never get here 

// subclass the window with the proc which does gray backgrounds 
oldWndProc = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC); 
if (oldWndProc != NULL) 

ASSERT(GetProp(hWnd, szAfxOldWndProc) == NULL); 
SetProp(hWnd, szAfxOldWndProc, oldWndProc); 
if ((WNDPROC)GetProp(hWnd, szAfxOldWndProc) == oldWndProc) 

SetWindowLong(hWnd, GWL_WNDPROC, 
(DWORD)(pThreadState->m_bDlgCreate ? 
_AfxGrayBackgroundWndProc : _AfxActivationWndProc)); 
ASSERT(oldWndProc != NULL); 





LRESULT lResult = CallNextHookEx(pThreadState->m_hHookOldCbtFilter, co
de, 
wParam, lParam); 

#ifndef _AFXDLL 
if (afxContextIsDLL) 

::UnhookWindowsHookEx(pThreadState->m_hHookOldCbtFilter); 
pThreadState->m_hHookOldCbtFilter = NULL; 

#endif 
return lResult; 


// always indirectly accessed via AfxGetAfxWndProc 
WNDPROC AFXAPI AfxGetAfxWndProc() 

#ifdef _AFXDLL 
return AfxGetModuleState()->m_pfnAfxWndProc; 
// 如果MFC是动态连入,返回的地址是AfxWndProcBase 
#else 
return &AfxWndProc; // 否则返回AfxWndProc 
#endif 


// The WndProc for all CWnd's and derived classes 

LRESULT CALLBACK 
AfxWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) 

// special message which identifies the window as using AfxWndProc 
if (nMsg == WM_QUERYAFXWNDPROC) 
^^^^^^^^^^^^^^^^^^ 查询是否为AFX的窗口过程 
return 1; 

// all other messages route through message map 
CWnd* pWnd = CWnd::FromHandlePermanent(hWnd); 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
FromHandlePermanent函数用于返回一个和hWnd句柄对应的 
永久的CWnd类,所谓永久的,就是CWnd调用了Attach函数 
连上了一个窗口句柄。 

ASSERT(pWnd != NULL); 
ASSERT(pWnd->m_hWnd == hWnd); 
return AfxCallWndProc(pWnd, hWnd, nMsg, wParam, lParam); 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 函数见后 


#ifdef _AFXDLL 
#undef AfxWndProc 
LRESULT CALLBACK 
AfxWndProcBase(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) 

AFX_MANAGE_STATE(_afxBaseModuleState.GetData()); 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
// 由于MFC是动态连入的,所以必须要这条语句! 
return AfxWndProc(hWnd, nMsg, wParam, lParam); 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
调用MFC静态连入时使用的函数 

#endif 

// 微软官方规定的发送消息给CWnd的函数 
LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg, 
WPARAM wParam = 0, LPARAM lParam = 0) 

_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData(); 
MSG oldState = pThreadState->m_lastSentMsg; // save for nesting 
pThreadState->m_lastSentMsg.hwnd = hWnd; 
pThreadState->m_lastSentMsg.message = nMsg; 
pThreadState->m_lastSentMsg.wParam = wParam; 
pThreadState->m_lastSentMsg.lParam = lParam; 

#ifdef _DEBUG 
if (afxTraceFlags & traceWinMsg) 
_AfxTraceMsg(_T("WndProc"), &pThreadState->m_lastSentMsg); 
#endif 

// Catch exceptions thrown outside the scope of a callback 
// in debug builds and warn the user. 
LRESULT lResult; 
TRY 

#ifndef _AFX_NO_OCC_SUPPORT 
// special case for WM_DESTROY 
if ((nMsg == WM_DESTROY) && (pWnd->m_pCtrlCont != NULL)) 
pWnd->m_pCtrlCont->OnUIActivate(NULL); 
#endif 

// special case for WM_INITDIALOG 
CRect rectOld; 
DWORD dwStyle; 
if (nMsg == WM_INITDIALOG) 
_AfxPreInitDialog(pWnd, &rectOld, &dwStyle); 

// delegate to object's WindowProc 
lResult = pWnd->WindowProc(nMsg, wParam, lParam); 
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
调用CWnd类的WindowProc函数,函数见后 

// more special case for WM_INITDIALOG 
if (nMsg == WM_INITDIALOG) 
_AfxPostInitDialog(pWnd, rectOld, dwStyle); 

CATCH_ALL(e) 

lResult = AfxGetThread()->ProcessWndProcException(e, &pThreadState->m_
lastSentMsg); 
TRACE1("Warning: Uncaught exception in WindowProc (returning %ld).\n",
 
lResult); 
DELETE_EXCEPTION(e); 

END_CATCH_ALL 

pThreadState->m_lastSentMsg = oldState; 
return lResult; 


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

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

[关闭][返回]