source: trunk/Common/alax.info/rowindows.h @ 792

Last change on this file since 792 was 482, checked in by roman, 9 years ago

Updated copyright notice

  • Property svn:keywords set to Id
File size: 32.2 KB
Line 
1////////////////////////////////////////////////////////////
2// Template class library; extends Widnows SDK, ATL, WTL
3//
4// Copyright (C) Roman Ryltsov, 2006-2015
5// Created by Roman Ryltsov roman@alax.info
6//
7// A permission to re-use this source code is granted as long as copyright notice and
8// reference to source website http://alax.info is retained.
9
10#pragma once
11
12#include <atltypes.h>
13#include <atlcrack.h>
14#include "rores.h"
15#include "roatlcollections.h"
16
17////////////////////////////////////////////////////////////
18// CGdiSelector
19
20class CGdiSelector
21{
22public:
23        CDCHandle m_Dc;
24        HGDIOBJ m_hObject;
25
26public:
27// CGdiSelector
28        CGdiSelector(HDC hDc, HGDIOBJ hObject) throw()
29        {
30                m_Dc = hDc;
31                m_hObject = SelectObject(m_Dc, hObject);
32        }
33        ~CGdiSelector() throw()
34        {
35                SelectObject(m_Dc, m_hObject);
36        }
37        operator HDC () const throw()
38        {
39                return m_Dc;
40        }
41};
42
43////////////////////////////////////////////////////////////
44// _GdiHelper
45
46class _GdiHelper
47{
48public:
49// _GdiHelper
50        static SIZE_T GetDibSection(HBITMAP hBitmap, DIBSECTION& DibSection) throw()
51        {
52                _A(hBitmap);
53                ZeroMemory(&DibSection, sizeof DibSection);
54                return GetObject(hBitmap, sizeof DibSection, &DibSection);
55        }
56        static DIBSECTION GetDibSection(HBITMAP hBitmap)
57        {
58                DIBSECTION DibSection;
59                const SIZE_T nDibSectionSize = GetDibSection(hBitmap, DibSection);
60                __E(nDibSectionSize == sizeof DibSection || nDibSectionSize == sizeof (BITMAP));
61                return DibSection;
62        }
63        static ICONINFO GetIconInformation(HICON hIcon)
64        {
65                _A(hIcon);
66                ICONINFO IconInformation;
67                __E(CIconHandle(hIcon).GetIconInfo(&IconInformation));
68                return IconInformation;
69        }
70        static CIconHandle InternalOverlayIcon(CIconHandle BaseIcon, CIconHandle OverlayIcon, CDCHandle SampleDc, const ICONINFO& BaseIconInformation, CDCHandle Dc, CDCHandle SourceDc)
71        {
72                const ICONINFO OverlayIconInformation = GetIconInformation(OverlayIcon);
73                _A(BaseIconInformation.fIcon && OverlayIconInformation.fIcon);
74                const DIBSECTION BaseMaskDibSection = GetDibSection(BaseIconInformation.hbmMask);
75                const DIBSECTION BaseColorDibSection = GetDibSection(BaseIconInformation.hbmColor);
76#if defined(_DEBUG)
77                const DIBSECTION OverlayMaskDibSection = GetDibSection(OverlayIconInformation.hbmMask);
78                const DIBSECTION OverlayColorDibSection = GetDibSection(OverlayIconInformation.hbmColor);
79                CWindowDC DesktopDc(GetDesktopWindow());
80#endif // defined(_DEBUG)
81                const CSize Size(BaseColorDibSection.dsBm.bmWidth, BaseColorDibSection.dsBm.bmHeight);
82                _A(BaseMaskDibSection.dsBm.bmHeight == Size.cy); // Not a colorless icon
83                CBitmap MaskBitmap;
84                __E(MaskBitmap.CreateBitmap(Size.cx, Size.cy, 1, 1, NULL));
85                {
86                        CGdiSelector BitmapSelector(Dc, MaskBitmap);
87                        {
88                                CGdiSelector BitmapSelector(SourceDc, BaseIconInformation.hbmMask);
89                                __E(Dc.BitBlt(0, 0, Size.cx, Size.cy, SourceDc, 0, 0, SRCCOPY));
90                        }
91                        {
92                                CGdiSelector BitmapSelector(SourceDc, OverlayIconInformation.hbmMask);
93                                __E(Dc.BitBlt(0, 0, Size.cx, Size.cy, SourceDc, 0, 0, SRCAND));
94                        }
95                }
96#if defined(_DEBUG) && FALSE
97                _W(DesktopDc.StretchBlt(0, 0 * Size.cy, Size.cx * 4, Size.cy * 4, CGdiSelector(Dc, BaseIconInformation.hbmMask), 0, 0, Size.cx, Size.cy, SRCCOPY));
98                _W(DesktopDc.StretchBlt(5 * Size.cx, 0 * Size.cy, Size.cx * 4, Size.cy * 4, CGdiSelector(Dc, OverlayIconInformation.hbmMask), 0, 0, Size.cx, Size.cy, SRCCOPY));
99                _W(DesktopDc.StretchBlt(10 * Size.cx, 0 * Size.cy, Size.cx * 4, Size.cy * 4, CGdiSelector(Dc, MaskBitmap), 0, 0, Size.cx, Size.cy, SRCCOPY));
100#endif // defined(_DEBUG)
101                CBitmap ColorBitmap;
102#if TRUE
103                BITMAPINFOHEADER ColorBitmapInfoHeader;
104                ZeroMemory(&ColorBitmapInfoHeader, sizeof ColorBitmapInfoHeader);
105                ColorBitmapInfoHeader.biSize = sizeof ColorBitmapInfoHeader;
106                ColorBitmapInfoHeader.biWidth = Size.cx;
107                ColorBitmapInfoHeader.biHeight = Size.cy;
108                ColorBitmapInfoHeader.biPlanes = 1;
109                ColorBitmapInfoHeader.biBitCount = 32;
110                ColorBitmapInfoHeader.biCompression = BI_RGB;
111                VOID* pvColorBits = NULL;
112                ColorBitmap = CreateDIBSection(SampleDc, (const BITMAPINFO*) &ColorBitmapInfoHeader, DIB_RGB_COLORS, &pvColorBits, NULL, 0);
113                __E(ColorBitmap);
114#else
115                __E(ColorBitmap.CreateBitmap(Size.cx, Size.cy, 1, 32, NULL)); //__E(ColorBitmap.CreateCompatibleBitmap(SampleDc, Size.cx, Size.cy));
116#endif
117                {
118                        CGdiSelector BitmapSelector(Dc, ColorBitmap);
119                        {
120                                CGdiSelector BitmapSelector(SourceDc, BaseIconInformation.hbmColor);
121                                __E(Dc.BitBlt(0, 0, Size.cx, Size.cy, SourceDc, 0, 0, SRCCOPY));
122                        }
123#if defined(_DEBUG) && FALSE
124                        _W(DesktopDc.StretchBlt(0, 5 * Size.cy, Size.cx * 4, Size.cy * 4, CGdiSelector(Dc, BaseIconInformation.hbmColor), 0, 0, Size.cx, Size.cy, SRCCOPY));
125                        _W(DesktopDc.StretchBlt(5 * Size.cx, 5 * Size.cy, Size.cx * 4, Size.cy * 4, BitmapSelector, 0, 0, Size.cx, Size.cy, SRCCOPY));
126#endif // defined(_DEBUG)
127#if (WINVER >= 0x0400)
128                        // NOTE: Windows XP's DrawIconEx destroys Dc's alpha channel
129                        BOOL bHandled = FALSE;
130                        if(BaseColorDibSection.dsBm.bmBitsPixel >= 32)
131                        {
132                                // HOTFIX: Icons load from paletted formats (?) may have broken alpha channel
133                                if(BaseColorDibSection.dsBm.bmBitsPixel == 32)
134                                {
135                                        _A(pvColorBits);
136                                        BOOL bPositiveAlphaValueFound = FALSE;
137                                        for(SIZE_T nIndex = Size.cy * Size.cx; nIndex > 0; nIndex--)
138                                                if(((const RGBQUAD*) pvColorBits)[nIndex - 1].rgbReserved)
139                                                {
140                                                        bPositiveAlphaValueFound = TRUE;
141                                                        break;
142                                                }
143                                        if(!bPositiveAlphaValueFound)
144                                        {
145                                                _Z4(atlTraceWindowing, 4, _T("bPositiveAlphaValueFound %d\n"), bPositiveAlphaValueFound);
146                                                // WARN: GetPixel is slow
147                                                CGdiSelector BitmapSelector(SourceDc, BaseIconInformation.hbmMask);
148                                                RGBQUAD* pnPointer = (RGBQUAD*) pvColorBits;
149                                                for(LONG nY = Size.cy - 1; nY >= 0; nY--)
150                                                        for(LONG nX = 0; nX < Size.cx; nX++, pnPointer++)
151                                                                if(Dc.GetPixel(nX, nY))
152                                                                        pnPointer->rgbReserved = 0xFF;
153                                        }
154                                }
155                                CGdiSelector BitmapSelector(SourceDc, OverlayIconInformation.hbmColor);
156                                BLENDFUNCTION BlendFunction = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
157                                bHandled = AlphaBlend(Dc, 0, 0, Size.cx, Size.cy, SourceDc, 0, 0, Size.cx, Size.cy, BlendFunction);
158                                _A(bHandled);
159                        }
160                        if(!bHandled)
161#endif // (WINVER >= 0x0400)
162                                __E(OverlayIcon.DrawIconEx(Dc, CPoint(0, 0), Size));
163#if defined(_DEBUG) && FALSE
164                        _W(DesktopDc.StretchBlt(10 * Size.cx, 5 * Size.cy, Size.cx * 4, Size.cy * 4, CGdiSelector(Dc, OverlayIconInformation.hbmColor), 0, 0, Size.cx, Size.cy, SRCCOPY));
165                        _W(DesktopDc.StretchBlt(15 * Size.cx, 5 * Size.cy, Size.cx * 4, Size.cy * 4, BitmapSelector, 0, 0, Size.cx, Size.cy, SRCCOPY));
166#endif // defined(_DEBUG)
167                }
168                ICONINFO IconInformation;
169                IconInformation = BaseIconInformation;
170                IconInformation.hbmMask = MaskBitmap;
171                IconInformation.hbmColor = ColorBitmap;
172                CIcon Icon;
173                __E(Icon.CreateIconIndirect(&IconInformation));
174#if defined(_DEBUG) && FALSE
175                _W(DesktopDc.StretchBlt(0, 10 * Size.cy, Size.cx * 4, Size.cy * 4, CGdiSelector(Dc, MaskBitmap), 0, 0, Size.cx, Size.cy, SRCCOPY));
176                _W(DesktopDc.StretchBlt(5 * Size.cx, 10 * Size.cy, Size.cx * 4, Size.cy * 4, CGdiSelector(Dc, ColorBitmap), 0, 0, Size.cx, Size.cy, SRCCOPY));
177                IconInformation = GetIconInformation(Icon);
178                _W(DesktopDc.StretchBlt(0, 15 * Size.cy, Size.cx * 4, Size.cy * 4, CGdiSelector(Dc, IconInformation.hbmMask), 0, 0, Size.cx, Size.cy, SRCCOPY));
179                _W(DesktopDc.StretchBlt(5 * Size.cx, 15 * Size.cy, Size.cx * 4, Size.cy * 4, CGdiSelector(Dc, IconInformation.hbmColor), 0, 0, Size.cx, Size.cy, SRCCOPY));
180                _W(DesktopDc.DrawIcon(0, 20 * Size.cy, Icon));
181#endif // defined(_DEBUG)
182                return Icon.Detach();
183        }
184        static CIconHandle OverlayIcon(CIconHandle BaseIcon, CIconHandle OverlayIcon)
185        {
186                CClientDC SampleDc(NULL);
187                CDC Dc, SourceDc;
188                __E(Dc.CreateCompatibleDC(SampleDc));
189                __E(SourceDc.CreateCompatibleDC(Dc));
190                return InternalOverlayIcon(BaseIcon, OverlayIcon, (HDC) SampleDc, GetIconInformation(BaseIcon), (HDC) Dc, (HDC) SourceDc);
191        }
192        static VOID OverlayIcons(CIconHandle BaseIcon, CIconHandle* pOverlayIcons, SIZE_T nOverlayIconCount, CIcon* pIcons)
193        {
194                _A(!IsBadWritePtr(pIcons, sizeof *pIcons * nOverlayIconCount));
195                CClientDC SampleDc(NULL);
196                CDC Dc, SourceDc;
197                __E(Dc.CreateCompatibleDC(SampleDc));
198                __E(SourceDc.CreateCompatibleDC(Dc));
199                for(SIZE_T nIndex = 0; nIndex < nOverlayIconCount; nIndex++)
200                        pIcons[nIndex] = InternalOverlayIcon(BaseIcon, pOverlayIcons[nIndex], (HDC) SampleDc, GetIconInformation(BaseIcon), (HDC) Dc, (HDC) SourceDc);
201        }
202        static VOID OverlayIcons(CIconHandle BaseIcon, HICON* phOverlayIcons, SIZE_T nOverlayIconCount, CIcon* pIcons)
203        {
204                OverlayIcons(BaseIcon, reinterpret_cast<CIconHandle*>(phOverlayIcons), nOverlayIconCount, pIcons);
205        }
206        static VOID OverlayIcons(CIconHandle BaseIcon, CIcon* pOverlayIcons, SIZE_T nOverlayIconCount, CIcon* pIcons)
207        {
208                OverlayIcons(BaseIcon, reinterpret_cast<CIconHandle*>(pOverlayIcons), nOverlayIconCount, pIcons);
209        }
210};
211
212////////////////////////////////////////////////////////////
213// CWindowRedraw
214
215class CWindowRedraw
216{
217public:
218        CWindow m_Window;
219        LONG m_nCount;
220
221public:
222// CWindowRedraw
223        CWindowRedraw(HWND hWindow, LONG nSetCount = -1) throw() : 
224                m_Window(hWindow),
225                m_nCount(0)
226        {
227                // SUGG: Make more flexible on demand
228                _A(nSetCount == -1);
229                m_Window.SetRedraw(FALSE);
230                m_nCount = nSetCount;
231        }
232        ~CWindowRedraw() throw()
233        {
234                _A(m_nCount <= 0);
235                if(m_nCount == 0)
236                        return;
237                for(; m_nCount < 0; m_nCount++)
238                        m_Window.SetRedraw(TRUE);
239                // FIX: Workaround API GUI glitches
240                TCHAR pszClassName[64] = { 0 };
241                if(GetClassName(m_Window, pszClassName, DIM(pszClassName)))
242                {
243                        if(_tcsicmp(pszClassName, CComboBox::GetWndClassName()) == 0)
244                                m_Window.Invalidate();
245                }
246        }
247};
248
249////////////////////////////////////////////////////////////
250// BEGIN_MSG_MAP_EX, MESSAGE_TRACE_EX,
251// REGISTERED_MESSAGE_HANDLER_EX
252
253#undef BEGIN_MSG_MAP_EX
254
255#define BEGIN_MSG_MAP_EX(T) \
256public: \
257        BOOL m_bATL3MsgHandled; \
258        BOOL IsMsgHandled() const throw() \
259        { \
260                return m_bATL3MsgHandled; \
261        } \
262        VOID SetMsgHandled(BOOL bHandled) throw() \
263        { \
264                m_bATL3MsgHandled = bHandled; \
265        } \
266        __if_exists(T::m_hWnd) \
267        { \
268                INT_PTR AtlExceptionMessageBox(const CAtlException& Exception, UINT nType = MB_ICONERROR | MB_OK) \
269                { \
270                        return ::AtlExceptionMessageBox(static_cast<T*>(this)->m_hWnd, Exception, nType); \
271                } \
272        } \
273        BOOL ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID = 0) throw() \
274        { \
275                BOOL bHandled = m_bATL3MsgHandled; \
276                BOOL bResult = FALSE; \
277                _ATLTRY \
278                { \
279                        __if_exists(T::BeforeProcessWindowMessage) \
280                        { \
281                                static_cast<T*>(this)->BeforeProcessWindowMessage(); \
282                        } \
283                        bResult = _ProcessWindowMessage(hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); \
284                } \
285                _ATLCATCH(Exception) \
286                { \
287                        Exception; _Z_ATLEXCEPTION(Exception); \
288                        __if_exists(T::HandleException) \
289                        { \
290                                HandleException(Exception); \
291                        } \
292                        __if_not_exists(T::HandleException) \
293                        { \
294                                __if_exists(T::m_hWnd) \
295                                { \
296                                        AtlMessageBoxEx(static_cast<T*>(this)->m_hWnd, (LPCTSTR) AtlFormatSystemMessage(Exception.m_hr), IDS_ERROR, MB_ICONERROR | MB_OK); \
297                                } \
298                        } \
299                } \
300                _ATLCATCHALL() \
301                { \
302                        _Z_EXCEPTION(); \
303                        __if_exists(T::HandleException) \
304                        { \
305                                HandleException(CAtlException(E_UNEXPECTED)); \
306                        } \
307                        __if_not_exists(T::HandleException) \
308                        { \
309                                __if_exists(T::m_hWnd) \
310                                { \
311                                        AtlMessageBoxEx(static_cast<T*>(this)->m_hWnd, (LPCTSTR) AtlFormatSystemMessage(E_UNEXPECTED), IDS_ERROR, MB_ICONERROR | MB_OK); \
312                                } \
313                        } \
314                } \
315                m_bATL3MsgHandled = bHandled; \
316                return bResult; \
317        } \
318        BOOL _ProcessWindowMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lResult, DWORD dwMsgMapID) \
319        { \
320                BOOL bHandled = TRUE; \
321                hWnd; \
322                uMsg; \
323                wParam; \
324                lParam; \
325                lResult; \
326                bHandled; \
327                switch(dwMsgMapID) \
328                { \
329                case 0:
330
331#define MESSAGE_TRACE_EX()      \
332        ATLTRACE(atlTraceWindowing, 4, _T("hWnd 0x%08x, uMsg %d (0x%x), wParam %d (0x%x), lParam %d (0x%x)\n"), hWnd, uMsg, uMsg, wParam, wParam, lParam, lParam);
333
334#define NOTIFY_TRACE_EX()       \
335        if(uMsg == WM_NOTIFY) \
336                ATLTRACE(atlTraceWindowing, 4, _T("hWnd 0x%08x, WM_NOTIFY, wParam %d (0x%x), lParam { hwndFrom 0x%08x, idFrom %d (0x%x), code %d (0x%x) }\n"), hWnd, wParam, wParam, ((NMHDR*) lParam)->hwndFrom, ((NMHDR*) lParam)->idFrom, ((NMHDR*) lParam)->idFrom, ((NMHDR*) lParam)->code, ((NMHDR*) lParam)->code);
337
338////////////////////////////////////////////////////////////
339// REGISTERED_MESSAGE_HANDLER_EX
340
341#define REGISTERED_MESSAGE_HANDLER_EX(msgname, func) \
342        if(uMsg >= 0xC000 && uMsg <= 0xFFFF && uMsg == RegisterWindowMessage(msgname)) \
343        { \
344                SetMsgHandled(TRUE); \
345                lResult = func(uMsg, wParam, lParam); \
346                if(IsMsgHandled()) \
347                        return TRUE; \
348        }
349
350////////////////////////////////////////////////////////////
351// CMessageOnlyWindowImpl
352
353template <typename T, typename _Window = CWindow, typename _WinTraits = CFrameWinTraits>
354class CMessageOnlyWindowImpl : 
355        public CWindowImpl<T, _Window, _WinTraits>
356{
357public:
358// CMessageOnlyWindowImpl
359        static HWND GetParentWindow() throw()
360        {
361                return HWND_MESSAGE; // Windows 2000+
362        }
363        HWND Create(HWND hParentWindow = GetParentWindow(), _U_RECT Position = NULL, LPCTSTR pszWindowName = NULL, DWORD nStyle = 0, DWORD nExStyle = 0, _U_MENUorID Menu = 0U, VOID* pvCreateParameter = NULL)
364        {
365                return __super::Create(hParentWindow, Position, pszWindowName, nStyle, nExStyle, Menu, pvCreateParameter);
366        }
367};
368
369////////////////////////////////////////////////////////////
370// CWindowMessageParameterMapT
371
372template <typename _Parameter>
373class CWindowMessageParameterMapT
374{
375private:
376        mutable CRoCriticalSection m_DataCriticalSection;
377        UINT_PTR m_nCounter;
378        CAtlMap<UINT_PTR, CAutoPtr<_Parameter> > m_ParameterMap;
379
380public:
381// CWindowMessageParameterMapT
382        CWindowMessageParameterMapT() throw() :
383                m_nCounter(0)
384        {
385        }
386        UINT_PTR AddParameter(CAutoPtr<_Parameter>& pParameter)
387        {
388                CRoCriticalSectionLock DataLock(m_DataCriticalSection);
389                const UINT_PTR nCookie = ++m_nCounter;
390                _A(!m_ParameterMap.Lookup((UINT) nCookie));
391                m_ParameterMap[nCookie] = pParameter;
392                return nCookie;
393        }
394        UINT_PTR AddParameter(const _Parameter& Parameter)
395        {
396                CAutoPtr<_Parameter> pParameter(new _Parameter);
397                *pParameter = Parameter;
398                return AddParameter(pParameter);
399        }
400        CAutoPtr<_Parameter> RemoveParameter(UINT_PTR nCookie) throw()
401        {
402                CRoCriticalSectionLock DataLock(m_DataCriticalSection);
403                const POSITION Position = m_ParameterMap.Lookup(nCookie);
404                CAutoPtr<_Parameter> pParameter;
405                if(!Position)
406                        return pParameter; // Nothing
407                pParameter = m_ParameterMap.GetValueAt(Position);
408                m_ParameterMap.RemoveAtPos(Position);
409                return pParameter;
410        }
411        SIZE_T RemoveAllParameters() throw()
412        {
413                CRoCriticalSectionLock DataLock(m_DataCriticalSection);
414                const SIZE_T nCount = m_ParameterMap.GetCount();
415                m_ParameterMap.RemoveAll();
416                return nCount;
417        }
418};
419
420////////////////////////////////////////////////////////////
421// CWindowWithPrivateMessagesT
422
423template <typename T>
424class CWindowWithPrivateMessagesT
425{
426protected:
427        typedef CWindowWithPrivateMessagesT<T> CWindowWithPrivateMessages;
428
429public:
430
431BEGIN_MSG_MAP_EX(CWindowWithPrivateMessagesT<T>)
432        REGISTERED_MESSAGE_HANDLER_EX(T::GetPrivateMessageName(), OnPrivate)
433END_MSG_MAP()
434
435public:
436// CWindowWithPrivateMessagesT
437        static LPCTSTR GetPrivateMessageName() throw()
438        {
439                return _T("WM_PRIVATE");
440        }
441        static UINT GetPrivateMessageIdentifier() throw()
442        {
443                return RegisterWindowMessage(T::GetPrivateMessageName());
444        }
445        BOOL IsPrivateMessagePending() const throw()
446        {
447                const T* pT = static_cast<const T*>(this);
448                MSG Message;
449                UINT nPrivateMessageIdentifier = T::GetPrivateMessageIdentifier();
450                return PeekMessage(&Message, pT->m_hWnd, nPrivateMessageIdentifier, nPrivateMessageIdentifier, PM_NOREMOVE);
451        }
452        BOOL PostPrivateMessage(UINT nMessage, WPARAM wParam = 0) throw()
453        {
454                T* pT = static_cast<T*>(this);
455                return pT->PostMessage(T::GetPrivateMessageIdentifier(), (WPARAM) nMessage, (LPARAM) wParam);
456        }
457        SIZE_T RemovePrivateMessages(BOOL (T::*pMessageHandler)(const MSG& Message) = NULL) throw()
458        {
459                T* pT = static_cast<T*>(this);
460                MSG Message;
461                UINT nPrivateMessageIdentifier = T::GetPrivateMessageIdentifier();
462                SIZE_T nMessageCount = 0;
463                while(PeekMessage(&Message, pT->m_hWnd, nPrivateMessageIdentifier, nPrivateMessageIdentifier, PM_REMOVE))
464                {
465                        nMessageCount++;
466                        if(!pMessageHandler)
467                                continue;
468                        BOOL bContinue = (pT->*pMessageHandler)(Message);
469                        if(!bContinue)
470                                break;
471                }
472                return nMessageCount;
473        }
474        BOOL DispatchPrivateMessage(const MSG& Message) throw()
475        {
476                DispatchMessage(&Message);
477                return TRUE;
478        }
479        SIZE_T DispatchPrivateMessages() throw()
480        {
481                return RemovePrivateMessages(&T::DispatchPrivateMessage);
482        }
483        LRESULT HandlePostedPrivateMessage(WPARAM wParam, LPARAM lParam) throw()
484        {
485                T* pT = static_cast<T*>(this);
486                return pT->SendMessage((UINT) wParam, (WPARAM) lParam);
487        }
488
489// Window message handlers
490        LRESULT OnPrivate(UINT, WPARAM wParam, LPARAM lParam) throw()
491        {
492                T* pT = static_cast<T*>(this);
493                return pT->HandlePostedPrivateMessage(wParam, lParam);
494        }
495};
496
497inline SSIZE_T WaitForMultipleObjectsDispatchingMessages(SIZE_T nObjectCount, const HANDLE* phObjects, BOOL bWaitAllObjects = FALSE, ULONG nTimeoutTime = INFINITE, DWORD nWakeMask = QS_ALLINPUT | QS_ALLPOSTMESSAGE)
498{
499        _A(phObjects && nObjectCount);
500        const ULONG nReturnTime = GetTickCount() + nTimeoutTime;
501        DWORD nWaitResult;
502        for(; ; )
503        {
504                ULONG nCurrentTimeoutTime;
505                if(nTimeoutTime != INFINITE)
506                {
507                        nCurrentTimeoutTime = nReturnTime - GetTickCount();
508                        if((LONG) nCurrentTimeoutTime <= 0)
509                                return WAIT_TIMEOUT;
510                } else
511                        nCurrentTimeoutTime = INFINITE;
512                nWaitResult = MsgWaitForMultipleObjects((DWORD) nObjectCount, phObjects, bWaitAllObjects, nCurrentTimeoutTime, nWakeMask);
513                _Z5_WAITRESULT(nWaitResult);
514                _A(nWaitResult - WAIT_OBJECT_0 <= nObjectCount || nWaitResult == WAIT_TIMEOUT && nCurrentTimeoutTime != INFINITE);
515                if(nWaitResult - WAIT_OBJECT_0 != nObjectCount)
516                        break;
517                MSG Message;
518                while(PeekMessage(&Message, NULL, WM_NULL, WM_NULL, PM_REMOVE))
519                {
520                        TranslateMessage(&Message);
521                        DispatchMessage(&Message);
522                }
523        }
524        return nWaitResult;
525}
526
527////////////////////////////////////////////////////////////
528// CWindowedTimedEventDaemonWindow
529
530class CWindowedTimedEventDaemonWindow :
531        public CMessageOnlyWindowImpl<CWindowedTimedEventDaemonWindow>//,
532        //public CWindowWithPrivateMessagesT<CWindowedTimedEventDaemonWindow>
533{
534        typedef VOID (*HANDLER)(UINT_PTR, DWORD_PTR);
535
536public:
537
538BEGIN_MSG_MAP_EX(CStubWindow)
539        //CHAIN_MSG_MAP(CWindowWithPrivateMessagesT<CWindowedTimedEventDaemonWindow>)
540        MSG_WM_TIMER(OnTimer)
541END_MSG_MAP()
542
543        ////////////////////////////////////////////////////////
544        // CTimedEvent
545
546        class CTimedEvent
547        {
548        public:
549                ULONG m_nDelay;
550                HANDLER m_pHandler;
551                DWORD_PTR m_nParameter;
552
553        public:
554        // CTimedEvent
555                CTimedEvent() throw()
556                {
557                }
558                CTimedEvent(ULONG nDelay, HANDLER pHandler, DWORD_PTR nParameter) throw() :
559                        m_nDelay(nDelay),
560                        m_pHandler(pHandler), 
561                        m_nParameter(nParameter)
562                {
563                }
564        };
565
566        ////////////////////////////////////////////////////////
567        // CTimedEventList
568
569        class CTimedEventList :
570                public CRoListT<CTimedEvent>
571        {
572        public:
573        // CTimedEventList
574                BOOL IsValidPosition(POSITION Position) const throw()
575                {
576                        for(POSITION CurrentPosition = GetHeadPosition(); CurrentPosition; GetNext(CurrentPosition))
577                                if(CurrentPosition == Position)
578                                        return TRUE;
579                        return FALSE;
580                }
581        };
582
583private:
584        static CRoListT<CWindowedTimedEventDaemonWindow> g_WindowList;
585        LONG m_nReferenceCount;
586        CTimedEventList m_TimedEventList;
587
588public:
589// CWindowedTimedEventDaemonWindow
590        static CWindowedTimedEventDaemonWindow* GetWindow(HWND hParentWindow)
591        {
592                _A(_pAtlModule);
593                CComCritSecLock<CComCriticalSection> GlobalLock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
594                CWindowedTimedEventDaemonWindow* pWindow = NULL;
595                for(POSITION Position = g_WindowList.GetHeadPosition(); Position; g_WindowList.GetNext(Position))
596                        if(g_WindowList.GetAt(Position).GetParent() == hParentWindow)
597                        {
598                                pWindow = &g_WindowList.GetAt(Position);
599                                break;
600                        }
601                if(!pWindow)
602                {
603                        const POSITION Position = g_WindowList.AddTail();
604                        _A(Position);
605                        pWindow = &g_WindowList.GetAt(Position);
606                        _ATLTRY
607                        {
608                                __E(pWindow->Create(hParentWindow));
609                        }
610                        _ATLCATCHALL()
611                        {
612                                g_WindowList.RemoveAt(Position);
613                                _ATLRETHROW;
614                        }
615                }
616                _A(pWindow->GetWindowThreadID() == GetCurrentThreadId());
617                pWindow->AddRef();
618                return pWindow;
619        }
620        static BOOL ReleaseWindow(CWindowedTimedEventDaemonWindow* pWindow) throw()
621        {
622                if(!pWindow)
623                        return FALSE;
624                _A(_pAtlModule);
625                CComCritSecLock<CComCriticalSection> GlobalLock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
626                for(POSITION Position = g_WindowList.GetHeadPosition(); Position; g_WindowList.GetNext(Position))
627                        if(&g_WindowList.GetAt(Position) == pWindow)
628                        {
629                                const LONG nReferenceCount = pWindow->Release();
630                                _A(nReferenceCount >= 0);
631                                if(nReferenceCount <= 0)
632                                {
633                                        if(pWindow->IsWindow())
634                                                _W(pWindow->DestroyWindow());
635                                        g_WindowList.RemoveAt(Position);
636                                }
637                                return TRUE;
638                        }
639                return FALSE;
640        }
641        CWindowedTimedEventDaemonWindow() throw() :
642                m_nReferenceCount(0)
643        {
644        }
645        LONG AddRef() throw()
646        {
647                return ++m_nReferenceCount;
648        }
649        LONG Release() throw()
650        {
651                return --m_nReferenceCount;
652        }
653        UINT_PTR SetEvent(ULONG nInterval, HANDLER pHandler, DWORD_PTR nParameter)
654        {
655                _A(IsWindow());
656                _A(GetWindowThreadID() == GetCurrentThreadId());
657                const POSITION Position = m_TimedEventList.AddTail(CTimedEvent(nInterval, pHandler, nParameter));
658                _A(Position);
659                const UINT_PTR nEvent = (UINT_PTR) Position;
660                _W(SetTimer(nEvent, nInterval));
661                return nEvent;
662        }
663        BOOL KillEvent(UINT_PTR nEvent) throw()
664        {
665                const POSITION Position = (POSITION) nEvent;
666                if(!m_TimedEventList.IsValidPosition(Position))
667                        return FALSE;
668                m_TimedEventList.RemoveAt(Position);
669                if(!IsWindow())
670                        return TRUE;
671                _A(GetWindowThreadID() == GetCurrentThreadId());
672                _W(KillTimer(nEvent));
673                return TRUE;
674        }
675
676// Window message handlers
677        LRESULT OnTimer(UINT_PTR nEvent) throw()
678        {
679                const POSITION Position = (POSITION) nEvent;
680                if(!m_TimedEventList.IsValidPosition(Position))
681                {
682                        SetMsgHandled(FALSE);
683                        return 0;
684                }
685                CTimedEvent& TimedEvent = m_TimedEventList.GetAt(Position);
686                _ATLTRY
687                {
688                        (*TimedEvent.m_pHandler)(nEvent, TimedEvent.m_nParameter);
689                }
690                _ATLCATCHALL()
691                {
692                        _Z_EXCEPTION();
693                }
694                return 0;
695        }
696};
697
698__declspec(selectany) CRoListT<CWindowedTimedEventDaemonWindow> CWindowedTimedEventDaemonWindow::g_WindowList;
699
700////////////////////////////////////////////////////////////
701// CWindowedTimedEventExT, CWindowedTimedEventT
702
703template <typename T, typename _Owner>
704class CWindowedTimedEventExT
705{
706        typedef VOID (_Owner::*HANDLER)(T*);
707
708public:
709        CWindowedTimedEventDaemonWindow* m_pWindowedTimedEventDaemonWindow;
710        UINT_PTR m_nEvent;
711        _Owner* m_pOwner;
712        HANDLER m_pHandler;
713        ULONG m_nOrdinalNumber;
714
715        VOID InternalHandler(UINT_PTR nEvent)
716        {
717                if(m_nEvent == nEvent)
718                {
719                        _A(m_pOwner && m_pHandler);
720                        m_nOrdinalNumber++;
721                        (m_pOwner->*m_pHandler)(static_cast<T*>(this));
722                }
723        }
724        static VOID InternalHandler(UINT_PTR nEvent, DWORD_PTR nUser)
725        {
726                _ATLTRY
727                {
728                        ((CWindowedTimedEventExT*) nUser)->InternalHandler(nEvent);
729                }
730                _ATLCATCHALL()
731                {
732                        _Z_EXCEPTION();
733                }
734        }
735
736public:
737// CWindowedTimedEventExT
738        CWindowedTimedEventExT() throw() :
739                m_pWindowedTimedEventDaemonWindow(NULL),
740                m_nEvent(0)
741        {
742        }
743        ~CWindowedTimedEventExT() throw()
744        {
745                Destroy();
746                if(m_pWindowedTimedEventDaemonWindow)
747                        _W(CWindowedTimedEventDaemonWindow::ReleaseWindow(m_pWindowedTimedEventDaemonWindow));
748        }
749        UINT_PTR GetEvent() const throw()
750        {
751                return m_nEvent;
752        }
753        BOOL IsActive() const throw()
754        {
755                return m_nEvent != 0;
756        }
757        CWindowedTimedEventDaemonWindow* GetEventDaemonWindow() const throw()
758        {
759                return m_pWindowedTimedEventDaemonWindow;
760        }
761        VOID CreateDaemonWindow(HWND hParentWindow)
762        {
763                if(m_pWindowedTimedEventDaemonWindow)
764                        return;
765                m_pWindowedTimedEventDaemonWindow = CWindowedTimedEventDaemonWindow::GetWindow(hParentWindow);
766                _A(m_pWindowedTimedEventDaemonWindow);
767                m_nEvent = 0;
768        }
769        VOID CreateDaemonWindow(_Owner* pOwner)
770        {
771                CreateDaemonWindow(pOwner->m_hWnd);
772        }
773        VOID Create(HWND hParentWindow, _Owner* pOwner, HANDLER pHandler, UINT nInterval)
774        {
775                _A(hParentWindow && pOwner && pHandler);
776                Destroy();
777                CreateDaemonWindow(hParentWindow);
778                m_nEvent = m_pWindowedTimedEventDaemonWindow->SetEvent(nInterval, InternalHandler, (DWORD_PTR) this);
779                m_pOwner = pOwner;
780                m_pHandler = pHandler;
781                m_nOrdinalNumber = 0;
782        }
783        VOID Create(_Owner* pOwner, HANDLER pHandler, UINT nInterval)
784        {
785                Create(pOwner->m_hWnd, pOwner, pHandler, nInterval);
786        }
787        VOID Destroy() throw()
788        {
789                if(m_pWindowedTimedEventDaemonWindow && m_nEvent)
790                {
791                        m_pWindowedTimedEventDaemonWindow->KillEvent(m_nEvent);
792                        m_nEvent = 0;
793                }
794        }
795        ULONG GetOrdinalNumber() const throw()
796        {
797                return m_nOrdinalNumber;
798        }
799};
800
801template <typename _Owner>
802class CWindowedTimedEventT :
803        public CWindowedTimedEventExT<CWindowedTimedEventT<_Owner>, _Owner>
804{
805public:
806// CWindowedTimedEventExT
807};
808
809////////////////////////////////////////////////////////////
810// CDeferWindowPos
811
812class CDeferWindowPos
813{
814private:
815        HDWP m_hWinPosInfo;
816
817public:
818// CDeferWindowPos
819        CDeferWindowPos() throw() :
820                m_hWinPosInfo(NULL)
821        {
822        }
823        CDeferWindowPos(INT nCapacity) throw() :
824                m_hWinPosInfo(NULL)
825        {
826                _W(Begin(nCapacity));
827        }
828        ~CDeferWindowPos() throw()
829        {
830                _A(!m_hWinPosInfo);
831        }
832        operator HDWP () const throw()
833        {
834                return m_hWinPosInfo;
835        }
836        BOOL Begin(INT nCapacity = 10) throw()
837        {
838                _A(!m_hWinPosInfo);
839                m_hWinPosInfo = BeginDeferWindowPos(nCapacity);
840                return m_hWinPosInfo != NULL;
841        }
842        BOOL SetWindowPos(HWND hWindow, HWND hWndInsertAfter, INT nX, INT nY, INT nWidth, INT nHeight, UINT nFlags) throw()
843        {
844                _A(m_hWinPosInfo);
845                m_hWinPosInfo = CWindow(hWindow).DeferWindowPos(m_hWinPosInfo, hWndInsertAfter, nX, nY, nWidth, nHeight, nFlags);
846                return m_hWinPosInfo != NULL;
847        }
848        BOOL SetWindowPos(HWND hWindow, HWND hWndInsertAfter, const RECT* pPosition, UINT nFlags) throw()
849        {
850                _A(pPosition);
851                const CRect& Position = reinterpret_cast<const CRect&>(*pPosition);
852                return SetWindowPos(hWindow, hWndInsertAfter, Position.left, Position.top, Position.Width(), Position.Height(), nFlags);
853        }
854        BOOL End() throw()
855        {
856                _A(m_hWinPosInfo);
857                const BOOL bResult = EndDeferWindowPos(m_hWinPosInfo);
858                m_hWinPosInfo = NULL;
859                return bResult;
860        }
861};
862
863////////////////////////////////////////////////////////////
864// CThreadHookData
865
866class CThreadHookData
867{
868public:
869        DWORD m_nThreadIdentifier;
870        HHOOK m_hHook;
871
872public:
873// CThreadHookData
874        CThreadHookData() :
875                m_hHook(NULL)
876        {
877        }
878};
879       
880////////////////////////////////////////////////////////////
881// CThreadGetMessageHookTraits
882
883class CThreadGetMessageHookTraits
884{
885public:
886        typedef MSG CMessageData;
887
888public:
889// CThreadPreMessageHookTraits
890        static INT GetHookIdentifier()
891        {
892                return WH_GETMESSAGE;
893        }
894};
895
896////////////////////////////////////////////////////////////
897// CThreadPreMessageHookTraits
898
899class CThreadPreMessageHookTraits
900{
901public:
902        typedef CWPSTRUCT CMessageData;
903
904public:
905// CThreadPreMessageHookTraits
906        static INT GetHookIdentifier()
907        {
908                return WH_CALLWNDPROC;
909        }
910};
911       
912////////////////////////////////////////////////////////////
913// CThreadPostMessageHookTraits
914
915class CThreadPostMessageHookTraits
916{
917public:
918        typedef CWPRETSTRUCT CMessageData;
919
920public:
921// CThreadPostMessageHookTraits
922        static INT GetHookIdentifier()
923        {
924                return WH_CALLWNDPROCRET;
925        }
926};
927       
928////////////////////////////////////////////////////////////
929// CThreadMessageHookT
930       
931template <typename T, typename CTraits, typename CHookData = CThreadHookData>
932class CThreadMessageHookT
933{
934private:
935        static CRoListT<CHookData>* g_pHookDataList;
936        CHookData* m_pHookData;
937
938        static BOOL FindHook(POSITION& Position, DWORD nThreadIdentifier = GetCurrentThreadId())
939        {
940                _A(_pAtlModule);
941                CComCritSecLock<CComCriticalSection> DataLock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
942                if(g_pHookDataList)
943                        for(POSITION CurrentPosition = g_pHookDataList->GetTailPosition(); CurrentPosition; g_pHookDataList->GetPrev(CurrentPosition))
944                        {
945                                const CHookData& HookData = g_pHookDataList->GetAt(CurrentPosition);
946                                if(HookData.m_nThreadIdentifier != nThreadIdentifier)
947                                        continue;
948                                Position = CurrentPosition;
949                                return TRUE;
950                        }
951                return FALSE;
952        }
953        static BOOL FindHook(HHOOK& hHook, DWORD nThreadIdentifier = GetCurrentThreadId())
954        {
955                _A(_pAtlModule);
956                CComCritSecLock<CComCriticalSection> DataLock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
957                POSITION Position;
958                if(!FindHook(Position, nThreadIdentifier))
959                        return FALSE;
960                _A(g_pHookDataList);
961                hHook = g_pHookDataList->GetAt(Position).m_hHook;
962                return TRUE;
963        }
964        static LRESULT CALLBACK HookProc(INT nCode, WPARAM wParam, LPARAM lParam)
965        {
966                HHOOK hHook;
967                if(!FindHook(hHook))
968                        return 0;
969                if(nCode == HC_ACTION)
970                        T::HandleMessage(wParam, *((CTraits::CMessageData*) lParam));
971                return CallNextHookEx(hHook, nCode, wParam, lParam);
972        }
973
974protected:
975        static BOOL CheckClassName(HWND hWindow, LPCTSTR pszClassName)
976        {
977                TCHAR pszWindowClassName[64] = { 0 };
978                _W(GetClassName(hWindow, pszWindowClassName, _countof(pszWindowClassName)));
979                return _tcscmp(pszWindowClassName, pszClassName) == 0;
980        }
981        static CString GetWindowText(HWND hWindow)
982        {
983                CString sWindowText;
984                CWindow(hWindow).GetWindowText(sWindowText);
985                return sWindowText;
986        }
987        static BOOL FindHookData(CHookData*& pHookData, DWORD nThreadIdentifier = GetCurrentThreadId())
988        {
989                _A(_pAtlModule);
990                _A(VerifyCriticalSectionLocked(_pAtlModule->m_csStaticDataInitAndTypeInfo));
991                POSITION Position;
992                if(!FindHook(Position, nThreadIdentifier))
993                        return FALSE;
994                _A(g_pHookDataList);
995                pHookData = &g_pHookDataList->GetAt(Position);
996                return TRUE;
997        }
998        static BOOL FindHookData(CHookData& HookData, DWORD nThreadIdentifier = GetCurrentThreadId())
999        {
1000                _A(_pAtlModule);
1001                CComCritSecLock<CComCriticalSection> DataLock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
1002                POSITION Position;
1003                if(!FindHook(Position, nThreadIdentifier))
1004                        return FALSE;
1005                _A(g_pHookDataList);
1006                HookData = g_pHookDataList->GetAt(Position);
1007                return TRUE;
1008        }
1009        CHookData* GetHookData() const
1010        {
1011                return m_pHookData;
1012        }
1013        static VOID HandleMessage(WPARAM, typename CTraits::CMessageData&);
1014
1015public:
1016// CThreadMessageHookT
1017        CThreadMessageHookT() :
1018                m_pHookData(NULL)
1019        {
1020        }
1021        ~CThreadMessageHookT()
1022        {
1023                Terminate();
1024        }
1025        VOID Initialize()
1026        {
1027                _A(!m_pHookData);
1028                const HINSTANCE hInstance = NULL; //_AtlBaseModule.GetModuleInstance()
1029                const DWORD nThreadIdentifier = GetCurrentThreadId();
1030                const HHOOK hHook = SetWindowsHookEx(CTraits::GetHookIdentifier(), HookProc, hInstance, nThreadIdentifier);
1031                __E(hHook);
1032                _A(_pAtlModule);
1033                CComCritSecLock<CComCriticalSection> DataLock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
1034                if(!g_pHookDataList)
1035                        g_pHookDataList = new CRoListT<CHookData>;
1036                const POSITION Position = g_pHookDataList->AddTail();
1037                CHookData& HookData = g_pHookDataList->GetAt(Position);
1038                HookData.m_nThreadIdentifier = nThreadIdentifier;
1039                HookData.m_hHook = hHook;
1040                m_pHookData = &HookData;
1041        }
1042        VOID Terminate()
1043        {
1044                if(m_pHookData)
1045                {
1046                        HHOOK hHook = NULL;
1047                        {
1048                                _A(_pAtlModule);
1049                                CComCritSecLock<CComCriticalSection> DataLock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
1050                                POSITION Position = NULL;
1051                                if(FindHook(Position))
1052                                {
1053                                        _A(m_pHookData == &g_pHookDataList->GetAt(Position));
1054                                        hHook = g_pHookDataList->GetAt(Position).m_hHook;
1055                                        g_pHookDataList->RemoveAt(Position);
1056                                        if(g_pHookDataList->IsEmpty())
1057                                        {
1058                                                delete g_pHookDataList;
1059                                                g_pHookDataList = NULL;
1060                                        }
1061                                } else
1062                                        _A(FALSE);
1063                                m_pHookData = NULL;
1064                        }
1065                        if(hHook)
1066                                _W(UnhookWindowsHookEx(hHook));
1067                }
1068        }
1069};
1070
1071template <typename T, typename CTraits, typename CHookData>
1072__declspec(selectany) CRoListT<CHookData>* CThreadMessageHookT<T, CTraits, CHookData>::g_pHookDataList = NULL;
1073
Note: See TracBrowser for help on using the repository browser.