从调用栈分析看貌似DispatchMsg直接就能调用窗口过程
但我们仔细看窗口过程上的HWND值
template <class TBase, class TWinTraits>
LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)hWnd;
// set a ptr to this message and save the old value
_ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam);
const _ATL_MSG* pOldMsg = pThis->m_pCurrentMsg;
pThis->m_pCurrentMsg = &msg;
// pass to the message map to process
LRESULT lRes;
BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
// restore saved value for the current message
ATLASSERT(pThis->m_pCurrentMsg == &msg);
// do the default processing if message was not handled
if(!bRet)
{
if(uMsg != WM_NCDESTROY)
lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
else
{
// unsubclass, if needed
LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC);
lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc)
::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);
// mark window as destryed
pThis->m_dwState |= WINSTATE_DESTROYED;
}
}
if((pThis->m_dwState & WINSTATE_DESTROYED) && pOldMsg== NULL)
{
// clear out window handle
HWND hWndThis = pThis->m_hWnd;
pThis->m_hWnd = NULL;
pThis->m_dwState &= ~WINSTATE_DESTROYED;
// clean up after window is destroyed
pThis->m_pCurrentMsg = pOldMsg;
pThis->OnFinalMessage(hWndThis);
}else {
pThis->m_pCurrentMsg = pOldMsg;
}
return lRes;
}
第一句 CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)hWnd;
这个仿佛在说HWND就是窗口对象了!,
这简直不可能吧!
其实是这样的,
ATL的注册窗口类时,用的不是这个函数,而是
template <class TBase, class TWinTraits>
LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::StartWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)_AtlWinModule.ExtractCreateWndData();
ATLASSERT(pThis != NULL);
if(!pThis)
{
return 0;
}
pThis->m_hWnd = hWnd;
// Initialize the thunk. This is allocated in CWindowImplBaseT::Create,
// so failure is unexpected here.
pThis->m_thunk.Init(pThis->GetWindowProc(), pThis);
WNDPROC pProc = pThis->m_thunk.GetWNDPROC();
WNDPROC pOldProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pProc);
#ifdef _DEBUG
// check if somebody has subclassed us already since we discard it
if(pOldProc != StartWindowProc)
ATLTRACE(atlTraceWindowing, 0, _T("Subclassing through a hook discarded.\n"));
#else
(pOldProc); // avoid unused warning
#endif
return pProc(hWnd, uMsg, wParam, lParam);
}
这里我们看到了,首先在Create期间,本线程内就会调用一次初始的窗口过程,这个期间窗口对象的地址是通过类似TLS方法传递的
接下来的
pThis->m_thunk.Init(pThis->GetWindowProc(), pThis);
WNDPROC pProc = pThis->m_thunk.GetWNDPROC();
WNDPROC pOldProc = (WNDPROC)::SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)pProc);
这3句话是重点,ATL为每个窗口搞了一个Trunk对象,然后就将窗口函数替换成Trunk里的函数
Trunk是个什么呢
就是一个汇编代码,用来进行跳转到实际窗口函数的