这里我们基于atlwin定义的窗口类SampleWindow继承自CWindowImpl(定义见atlwin.h),并注册了WM_PAINT消息处理函数OnPaint,注意,我们在OnPaint函数中并没有直接处理WM_PAINT消息,而是直接返回了FALSE。
1 class SampleWindow : public CWindowImpl<SampleWindow> 2 { 3 public: 4 SampleWindow(): 5 6 7 DECLARE_WND_SUPERCLASS(_T("SampleWindow"), NULL) 8 9 BEGIN_MSG_MAP(SampleWindow) 10 11 MESSAGE_HANDLER(WM_PAINT, OnPaint) 12 13 END_MSG_MAP() 14 15 LRESULT OnPaint(UINT msg, WPARAM wparam, LPARAM lparam, BOOL &handled) 16 { 17 return FALSE; 18 } 19 20 }
参考MESSAGE_HANDLER的宏定义就会发现,在执行对应的消息响应函数之前,bHandled默认被赋值为了TRUE(所以通常情况下WM_PAINT消息需要在这里处理),但是参照上述代码,OnPaint函数并未对WM_PAINT消息处理,并且直接返回了FALSE,而MESSAGE_HANDLER默认是返回TRUE的。
1 #define MESSAGE_HANDLER(msg, func) \ 2 if(uMsg == msg) \ 3 { \ 4 bHandled = TRUE; \ 5 lResult = func(uMsg, wParam, lParam, bHandled); \ 6 if(bHandled) \ 7 return TRUE; \ 8 }
在代码执行到WindowProc后,pThis->ProcessWindowMessage函数会依次执行上述注册的消息响应函数,在执行到WM_PAINT消息后,bRet为TRUE,导致代码不能够执行lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
,而是执行了pThis->m_pCurrentMsg = pOldMsg;,消息处理过程函数WindowProc返回结果lRes为0,导致系统不停的发送WM_PAINT消息(导致消息不停发送的原因并不是WindowProc返回0,是WM_PAINT消息未得到处理),造成死循环。
1 template <class TBase, class TWinTraits> 2 LRESULT CALLBACK CWindowImplBaseT< TBase, TWinTraits >::WindowProc( 3 _In_ HWND hWnd, 4 _In_ UINT uMsg, 5 _In_ WPARAM wParam, 6 _In_ LPARAM lParam) 7 { 8 CWindowImplBaseT< TBase, TWinTraits >* pThis = (CWindowImplBaseT< TBase, TWinTraits >*)hWnd; 9 // set a ptr to this message and save the old value 10 _ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam); 11 const _ATL_MSG* pOldMsg = pThis->m_pCurrentMsg; 12 pThis->m_pCurrentMsg = &msg; 13 // pass to the message map to process 14 LRESULT lRes = 0; 15 BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0); 16 // restore saved value for the current message 17 ATLASSERT(pThis->m_pCurrentMsg == &msg); 18 19 // do the default processing if message was not handled 20 if(!bRet) 21 { 22 if(uMsg != WM_NCDESTROY) 23 lRes = pThis->DefWindowProc(uMsg, wParam, lParam); 24 else 25 { 26 // unsubclass, if needed 27 LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC); 28 lRes = pThis->DefWindowProc(uMsg, wParam, lParam); 29 if(pThis->m_pfnSuperWindowProc != ::DefWindowProc && ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc) 30 ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc); 31 // mark window as destryed 32 pThis->m_dwState |= WINSTATE_DESTROYED; 33 } 34 } 35 if((pThis->m_dwState & WINSTATE_DESTROYED) && pOldMsg== NULL) 36 { 37 // clear out window handle 38 HWND hWndThis = pThis->m_hWnd; 39 pThis->m_hWnd = NULL; 40 pThis->m_dwState &= ~WINSTATE_DESTROYED; 41 // clean up after window is destroyed 42 pThis->m_pCurrentMsg = pOldMsg; 43 pThis->OnFinalMessage(hWndThis); 44 }else { 45 pThis->m_pCurrentMsg = pOldMsg; 46 } 47 return lRes; 48 }
所以,我们要么就不要注册消息对应的响应函数,注册了最好就在对应的响应函数中处理。如果非得注册而且不处理的话,就在对应的响应函数中显式的将bHandled设置为FALSE,让消息处理过程函数WindowProc执行默认的消息处理函数DefWindowProc。