atlwin中不停发WM_PAINT消息原因分析

这里我们基于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。

原文地址:https://www.cnblogs.com/chenyangchun/p/6782052.html