source: trunk/Common/alax.info/roatlcom.h @ 482

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

Updated copyright notice

File size: 97.6 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 <windows.h>
13#include <mmsystem.h> // CTimedEvent* is compatible with MMSystem API
14#include <atlsync.h>
15#include <atlcoll.h>
16#include "roatlbase.h"
17#include "roatlcollections.h"
18
19////////////////////////////////////////////////////////////
20// Version
21
22#if !defined(_WIN32_WINNT_WIN7)
23        #define _WIN32_WINNT_WIN7 0x0601
24#endif // !defined(_WIN32_WINNT_WIN7)
25
26#if !defined(_versionhelpers_H_INCLUDED_)
27
28inline bool IsWindowsVistaOrGreater()
29{
30        OSVERSIONINFOEX VersionInformation = { sizeof VersionInformation };
31        GetVersionEx((OSVERSIONINFO*) &VersionInformation);
32        return VersionInformation.dwMajorVersion >= 6; // Windows Vista, Windows Server 2008
33}
34
35#endif // !defined(_versionhelpers_H_INCLUDED_)
36
37////////////////////////////////////////////////////////////
38// _Z
39
40#define _Z2_HRESULT(x)  _Z3(atlTraceGeneral,                 2, _T("%hs 0x%08X %s\n"), #x, x, FAILED(x) ? (LPCTSTR) AtlFormatSystemMessage(x).TrimRight(_T("\t\n\r .")) : _T(""))
41#define _Z3_HRESULT(x)  _Z3(atlTraceGeneral,                 3, _T("%hs 0x%08X %s\n"), #x, x, FAILED(x) ? (LPCTSTR) AtlFormatSystemMessage(x).TrimRight(_T("\t\n\r .")) : _T(""))
42#define _Z4_HRESULT(x)  _Z4(atlTraceGeneral,                 4, _T("%hs 0x%08X %s\n"), #x, x, FAILED(x) ? (LPCTSTR) AtlFormatSystemMessage(x).TrimRight(_T("\t\n\r .")) : _T(""))
43#define _Z45_HRESULT(x) _Z4(atlTraceGeneral, FAILED(x) ? 4 : 5, _T("%hs 0x%08X %s\n"), #x, x, FAILED(x) ? (LPCTSTR) AtlFormatSystemMessage(x).TrimRight(_T("\t\n\r .")) : _T(""))
44#define _Z5_HRESULT(x)  _Z5(atlTraceGeneral,                 5, _T("%hs 0x%08X %s\n"), #x, x, FAILED(x) ? (LPCTSTR) AtlFormatSystemMessage(x).TrimRight(_T("\t\n\r .")) : _T(""))
45#define _Z_HRESULT(x)   _Z4_HRESULT(x)
46
47////////////////////////////////////////////////////////////
48// CSingleThreadedApartment, CMultiThreadedApartment
49
50class CSingleThreadedApartment
51{
52public:
53// CSingleThreadedApartment
54        CSingleThreadedApartment() throw()
55        {
56                _V(CoInitialize(NULL));
57        }
58        ~CSingleThreadedApartment() throw()
59        {
60                CoUninitialize();
61        }
62};
63
64#if (_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)
65
66class CMultiThreadedApartment
67{
68public:
69// CMultiThreadedApartment
70        CMultiThreadedApartment() throw()
71        {
72                _V(CoInitializeEx(NULL, COINIT_MULTITHREADED));
73        }
74        ~CMultiThreadedApartment() throw()
75        {
76                CoUninitialize();
77        }
78};
79inline BOOL IsSingleThreadedApartment() throw()
80{
81        const HRESULT nResult = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
82        _A(nResult != S_OK);
83        if(SUCCEEDED(nResult))
84                CoUninitialize();
85        return SUCCEEDED(nResult);
86}
87inline BOOL IsMultiThreadedApartment() throw()
88{
89        const HRESULT nResult = CoInitializeEx(NULL, COINIT_MULTITHREADED);
90        if(SUCCEEDED(nResult))
91                CoUninitialize();
92        // NOTE: S_OK here means we are on implcit MTA
93        return SUCCEEDED(nResult);
94}
95
96#endif // (_WIN32_WINNT >= 0x0400 ) || defined(_WIN32_DCOM)
97
98////////////////////////////////////////////////////////////
99// DECLARE_QI_TRACE, DECLARE_REFCOUNT_TRACE
100
101#if _TRACE
102
103#define DECLARE_QI_TRACE(_Class) \
104        static HRESULT WINAPI InternalQueryInterface(VOID* pThis, const _ATL_INTMAP_ENTRY* pEntries, REFIID InterfaceIdentifier, void** ppvObject) throw()\
105        {\
106                const HRESULT nResult = CComObjectRootBase::InternalQueryInterface(pThis, pEntries, InterfaceIdentifier, ppvObject); \
107                OLECHAR pszInterfaceIdentifier[64] = { 0 }; \
108                _V(StringFromGUID2(InterfaceIdentifier, pszInterfaceIdentifier, DIM(pszInterfaceIdentifier))); \
109                ::CString sInterfaceName; \
110                if(!_RegKeyHelper::QueryStringValue(HKEY_CLASSES_ROOT, AtlFormatString(_T("Interface\\%ls"), pszInterfaceIdentifier), NULL, sInterfaceName)) \
111                        sInterfaceName = ::CString(pszInterfaceIdentifier); \
112                ATLTRACE(atlTraceQI, SUCCEEDED(nResult) ? 4 : 3, _T("0x%p, Interface %s, Result 0x%08X\n"), pThis, sInterfaceName, nResult); \
113                return nResult;\
114        }
115
116#define DECLARE_REFCOUNT_TRACE(_Class) \
117        ULONG InternalAddRef() throw() \
118        { \
119                ULONG nCount = CComObjectRootEx<_ThreadModel>::InternalAddRef(); \
120                ATLTRACE(atlTraceRefcount, 4, _T("this 0x%p, %d (+1) references\n"), _FILE, _LINE, _FUNCTION, this, nCount); \
121                return nCount; \
122        } \
123        ULONG InternalRelease() throw() \
124        { \
125                ULONG nCount = CComObjectRootEx<_ThreadModel>::InternalRelease(); \
126                ATLTRACE(atlTraceRefcount, 4, _T("this 0x%p, %d (-1) references\n"), _FILE, _LINE, _FUNCTION, this, nCount); \
127                return nCount; \
128        }
129
130#else
131
132#define DECLARE_QI_TRACE(_Class)       
133#define DECLARE_REFCOUNT_TRACE(_Class) 
134
135#endif // _TRACE
136
137////////////////////////////////////////////////////////////
138// CObjectPtrT, CObjectPtr, CWeakObjectPtr
139
140template <typename _Object, BOOL t_bStrong = TRUE, template <typename _Class> class _ComObject = CComObject>
141class CObjectPtrT
142{
143public:
144        _ComObject<_Object>* m_pObject;
145
146        VOID Assign(_Object* pValue) throw()
147        {
148                Attach(pValue);
149                if(t_bStrong)
150                        if(m_pObject)
151                                m_pObject->AddRef();
152        }
153
154public:
155// CObjectPtrT
156        CObjectPtrT() throw() :
157                m_pObject(NULL)
158        {
159        }
160        CObjectPtrT(const CObjectPtrT& pValue) throw() :
161                m_pObject(NULL)
162        {
163                *this = pValue;
164        }
165        template <BOOL t_bValueStrong>
166        CObjectPtrT(const CObjectPtrT<_Object, t_bValueStrong>& pValue) throw() :
167                m_pObject(NULL)
168        {
169                *this = pValue;
170        }
171        CObjectPtrT(_Object* pValue) throw() :
172                m_pObject(NULL)
173        {
174                *this = pValue;
175        }
176        ~CObjectPtrT() throw()
177        {
178                Attach(NULL);
179        }
180        operator _Object* () const throw()
181        {
182                return m_pObject;
183        }
184        CObjectPtrT& operator = (const CObjectPtrT& pValue) throw()
185        {
186                Assign(pValue.m_pObject);
187                return *this;
188        }
189        template <BOOL t_bValueStrong>
190        CObjectPtrT& operator = (const CObjectPtrT<_Object, t_bValueStrong>& pValue) throw()
191        {
192                Assign(pValue.m_pObject);
193                return *this;
194        }
195        CObjectPtrT& operator = (_Object* pValue) throw()
196        {
197                Assign(pValue);
198                return *this;
199        }
200        _Object** operator & () throw()
201        {
202                ATLASSERT(!m_pObject);
203                return (_Object**) &m_pObject;
204        }
205        _Object* operator -> () const throw()
206        {
207                ATLASSERT(m_pObject);
208                return m_pObject;
209        }
210        BOOL operator == (const CObjectPtrT& pValue) const throw()
211        {
212                return m_pObject == pValue.m_pObject;
213        }
214        template <BOOL t_bValueStrong>
215        BOOL operator == (const CObjectPtrT<_Object, t_bValueStrong>& pValue) const throw()
216        {
217                return m_pObject == pValue.m_pObject;
218        }
219        BOOL operator == (_Object* pValue) const throw()
220        {
221                return m_pObject == pValue;
222        }
223        BOOL operator != (const CObjectPtrT& pValue) const throw()
224        {
225                return !(*this == pValue);
226        }
227        template <BOOL t_bValueStrong>
228        BOOL operator != (const CObjectPtrT<_Object, t_bValueStrong>& pValue) const throw()
229        {
230                return !(*this == pValue);
231        }
232        BOOL operator != (_Object* pValue) const throw()
233        {
234                return !(*this == pValue);
235        }
236        _Object* Attach(_Object* pObject) throw()
237        {
238                if(t_bStrong)
239                        if(m_pObject)
240                                m_pObject->Release();
241                m_pObject = static_cast<_ComObject<_Object>*>(pObject);
242                return pObject;
243        }
244        _Object* Detach() throw()
245        {
246                _Object* pObject = m_pObject;
247                m_pObject = NULL;
248                return pObject;
249        }
250        VOID Swap(_Object** ppObject) throw()
251        {
252                ATLASSERT(ppObject);
253                _Object* pObject = m_pObject;
254                m_pObject = static_cast<_ComObject<_Object>*>(*ppObject);
255                *ppObject = pObject;
256        }
257        template <BOOL t_bStrong>
258        VOID Swap(CObjectPtrT<_Object, t_bStrong>& pObject) throw()
259        {
260                Swap((_Object**) &pObject.m_pObject);
261        }
262        CObjectPtrT& Construct()
263        {
264                ATLASSERT(!m_pObject);
265                ATLCHECK(_ComObject<_Object>::CreateInstance(&m_pObject));
266                ATLASSERT(m_pObject);
267                m_pObject->m_dwRef++;
268                return *this;
269        }
270        VOID Release() throw()
271        {
272                Attach(NULL);
273        }
274};
275
276template <typename _Object>
277class CObjectPtr :
278        public CObjectPtrT<_Object, TRUE>
279{
280public:
281// CObjectPtr
282        CObjectPtr() throw()
283        {
284        }
285        CObjectPtr(const CObjectPtr& pValue) throw() :
286                CObjectPtrT<_Object, TRUE>(pValue)
287        {
288        }
289        template <BOOL t_bValueStrong>
290        CObjectPtr(const CObjectPtrT<_Object, t_bValueStrong>& pValue) throw() :
291                CObjectPtrT<_Object, TRUE>(pValue)
292        {
293        }
294        CObjectPtr(_Object* pValue) throw() :
295                CObjectPtrT<_Object, TRUE>(pValue)
296        {
297        }
298        CObjectPtr& operator = (const CObjectPtr& pValue) throw()
299        {
300                __super::operator = (pValue);
301                return *this;
302        }
303        template <BOOL t_bValueStrong>
304        CObjectPtr& operator = (const CObjectPtrT<_Object, t_bValueStrong>& pValue) throw()
305        {
306                __super::operator = (pValue);
307                return *this;
308        }
309        CObjectPtr& operator = (_Object* pValue) throw()
310        {
311                __super::operator = (pValue);
312                return *this;
313        }
314};
315
316template <typename _Object>
317class CWeakObjectPtr :
318        public CObjectPtrT<_Object, FALSE>
319{
320public:
321// CWeakObjectPtr
322        CWeakObjectPtr() throw()
323        {
324        }
325        CWeakObjectPtr(const CWeakObjectPtr& pValue) throw() :
326                CObjectPtrT<_Object, FALSE>(pValue)
327        {
328        }
329        template <BOOL t_bValueStrong>
330        CWeakObjectPtr(const CObjectPtrT<_Object, t_bValueStrong>& pValue) throw() :
331                CObjectPtrT<_Object, FALSE>(pValue)
332        {
333        }
334        CWeakObjectPtr(_Object* pValue) throw() :
335                CObjectPtrT<_Object, FALSE>(pValue)
336        {
337        }
338        CWeakObjectPtr& operator = (const CWeakObjectPtr& pValue) throw()
339        {
340                __super::operator = (pValue);
341                return *this;
342        }
343        template <BOOL t_bValueStrong>
344        CWeakObjectPtr& operator = (const CObjectPtrT<_Object, t_bValueStrong>& pValue) throw()
345        {
346                __super::operator = (pValue);
347                return *this;
348        }
349        CWeakObjectPtr& operator = (_Object* pValue) throw()
350        {
351                __super::operator = (pValue);
352                return *this;
353        }
354};
355
356////////////////////////////////////////////////////////////
357// CCachedObjectPtr
358
359template <typename _Object>
360class CCachedObjectPtr :
361        public CObjectPtrT<_Object, TRUE, CComObjectCached>
362{
363public:
364// CCachedHolder
365        CCachedObjectPtr() throw()
366        {
367        }
368        CCachedObjectPtr(_Object* pObject) throw() :
369                CObjectPtrT<_Object, TRUE, CComObjectCached>(pObject)
370        {
371        }
372};
373
374////////////////////////////////////////////////////////////
375// CLocalObjectPtr
376
377template <typename _Object>
378class CLocalObjectPtr
379{
380public:
381        CComObject<_Object> m_Instance;
382
383public:
384// CObjectPtrT
385        CLocalObjectPtr()
386        {
387                m_Instance.SetVoid(NULL);
388                m_Instance.InternalFinalConstructAddRef();
389                #if _MSC_VER >= 1400
390                        ATLVERIFY(SUCCEEDED(m_Instance._AtlInitialConstruct()));
391                #endif // _MSC_VER >= 1400
392                ATLVERIFY(SUCCEEDED(m_Instance.FinalConstruct()));
393                ATLVERIFY(SUCCEEDED(m_Instance._AtlFinalConstruct()));
394                m_Instance.InternalFinalConstructRelease();
395                m_Instance.InternalAddRef();
396        }
397        ~CLocalObjectPtr()
398        {
399        }
400        operator const _Object* () const
401        {
402                return &m_Instance;
403        }
404        operator _Object* ()
405        {
406                return &m_Instance;
407        }
408        _Object* operator -> ()
409        {
410                return &m_Instance;
411        }
412};
413
414////////////////////////////////////////////////////////////
415// CCrossThreadPtr
416
417template <typename _Interface, const IID* t_pInterfaceIdentifier = &__uuidof(_Interface)>
418class CCrossThreadPtr
419{
420public:
421        mutable CComAutoCriticalSection m_DataCriticalSection;
422        IStream* m_pStream;
423
424public:
425        CCrossThreadPtr() throw() :
426                m_pStream(NULL)
427        {
428        }
429        ~CCrossThreadPtr() throw()
430        {
431                _ATLTRY
432                {
433                        Detach();
434                }
435                _ATLCATCHALL()
436                {
437                        _Z_EXCEPTION();
438                }
439        }
440        VOID Attach(_Interface* pObject)
441        {
442                CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
443                Detach();
444                if(pObject)
445                        __C(CoMarshalInterThreadInterfaceInStream(*t_pInterfaceIdentifier, pObject, &m_pStream));
446        }
447        CComPtr<_Interface> Detach()
448        {
449                CComPtr<_Interface> pObject;
450                CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
451                if(m_pStream)
452                {
453                        __C(CoGetInterfaceAndReleaseStream(m_pStream, *t_pInterfaceIdentifier, (VOID**) &pObject));
454                        m_pStream = NULL;
455                }
456                return pObject;
457        }
458        operator BOOL () const throw()
459        {
460                CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
461                return (m_pStream != NULL);
462        }
463        VOID operator = (_Interface* pObject)
464        {
465                Attach(pObject);
466        }
467};
468
469////////////////////////////////////////////////////////////
470// CConnectionPointConnectionT, CConnectionPointConnection
471
472template <const IID* t_pInterfaceIdentifier>
473class CConnectionPointConnectionT
474{
475private:
476        BOOL m_bAdvised;
477        CComPtr<IConnectionPointContainer> m_pConnectionPointContainer;
478        DWORD m_nCookie;
479
480public:
481// CConnectionPointConnectionT
482        CConnectionPointConnectionT() throw() :
483                m_bAdvised(FALSE)
484        {
485        }
486        ~CConnectionPointConnectionT() throw()
487        {
488                if(m_bAdvised)
489                        Unadvise();
490        }
491        BOOL IsAdvised() const throw()
492        {
493                return m_bAdvised;
494        }
495        const CComPtr<IConnectionPointContainer>& GetConnectionPointContainer() const throw()
496        {
497                return m_pConnectionPointContainer;
498        }
499        VOID Advise(IConnectionPointContainer* pConnectionPointContainer, IUnknown* pSink)
500        {
501                _A(!m_bAdvised);
502                __D(pConnectionPointContainer, E_NOINTERFACE);
503                __C(AtlAdvise(pConnectionPointContainer, pSink, *t_pInterfaceIdentifier, &m_nCookie));
504                m_bAdvised = TRUE;
505                m_pConnectionPointContainer = pConnectionPointContainer;
506        }
507        VOID Advise(IUnknown* pConnectionPointContainerUnknown, IUnknown* pSink)
508        {
509                Advise(CComQIPtr<IConnectionPointContainer>(pConnectionPointContainerUnknown), pSink);
510        }
511        BOOL Unadvise() throw()
512        {
513                if(!m_bAdvised)
514                        return FALSE;
515                HRESULT nResult = AtlUnadvise(m_pConnectionPointContainer, *t_pInterfaceIdentifier, m_nCookie);
516                if(FAILED(nResult))
517                        ATLTRACE(atlTraceCOM, 2, _T("Failed to unadvise connection point, nResult 0x%08X\n"), nResult);
518                m_bAdvised = FALSE;
519                m_pConnectionPointContainer = NULL;
520                return TRUE;
521        }
522        CConnectionPointConnectionT& operator = (CConnectionPointConnectionT& ConnectionPointConnection) throw()
523        {
524                // NOTE: Transfer connection
525                Unadvise();
526                m_bAdvised = ConnectionPointConnection.m_bAdvised;
527                m_pConnectionPointContainer = ConnectionPointConnection.m_pConnectionPointContainer;
528                m_nCookie = ConnectionPointConnection.m_nCookie;
529                ConnectionPointConnection.m_bAdvised = FALSE;
530                ConnectionPointConnection.m_pConnectionPointContainer = NULL;
531                return *this;
532        }
533};
534
535////////////////////////////////////////////////////////////
536// _ComDynamicUnkArrayHelper
537
538class _ComDynamicUnkArrayHelper
539{
540public:
541        template <typename _IConnectionPointImpl>
542        static VOID Fix(_IConnectionPointImpl* pInstance, UINT nSize = _DEFAULT_VECTORLENGTH)
543        {
544                _A(pInstance->m_vec.GetSize() == 0);
545                DWORD nCookie1 = pInstance->m_vec.Add((IUnknown*) 1);
546                DWORD nCookie2 = pInstance->m_vec.Add((IUnknown*) 2);
547                _A(nCookie1 && nCookie2);
548                _W(pInstance->m_vec.Remove(nCookie2));
549                _W(pInstance->m_vec.Remove(nCookie1));
550                _A(pInstance->m_vec.GetSize() == _DEFAULT_VECTORLENGTH);
551        }
552};
553
554#define FIX_CONNECTIONPOINT(Class, Interface)   _ComDynamicUnkArrayHelper::Fix((IConnectionPointImpl<Class, &Interface>*) this)
555
556////////////////////////////////////////////////////////////
557// CActiveObjectT, CFakeActiveObjectHandler, CDefaultActiveObjectHandler, CRunningObjectActiveObjectHandler
558
559class CFakeActiveObjectHandler
560{
561public:
562// CFakeActiveObjectHandler
563        static DWORD RegisterActiveObject(IUnknown* pUnknown, REFCLSID ClassIdentifier, DWORD nFlags) throw()
564        {
565                pUnknown;
566                ClassIdentifier;
567                nFlags;
568                return 1;
569        }
570        static VOID RevokeActiveObject(DWORD nCookie) throw()
571        {
572                ATLASSERT(nCookie == 1);
573        }
574};
575
576class CDefaultActiveObjectHandler
577{
578public:
579// CDefaultActiveObjectHandler
580        static DWORD RegisterActiveObject(IUnknown* pUnknown, REFCLSID ClassIdentifier, DWORD nFlags)
581        {
582                DWORD nCookie;
583                ATLCHECK(::RegisterActiveObject(pUnknown, ClassIdentifier, nFlags, &nCookie));
584                return nCookie;
585        }
586        static VOID RevokeActiveObject(DWORD nCookie)
587        {
588                ATLCHECK(::RevokeActiveObject(nCookie, NULL));
589        }
590};
591
592class CRunningObjectActiveObjectHandler
593{
594public:
595// CRunningObjectActiveObjectHandler
596        static CStringW StringFromIdentifier(const GUID& Identifier)
597        {
598                WCHAR pszIdentifierString[64] = { 0 };
599                ATLVERIFY(StringFromGUID2(Identifier, pszIdentifierString, _countof(pszIdentifierString)));
600                return pszIdentifierString;
601        }
602        static DWORD RegisterActiveObject(IUnknown* pUnknown, REFCLSID ClassIdentifier, DWORD nFlags)
603        {
604                // NOTE: Direct registration into ROT allows us to specify ROTFLAGS_ALLOWANYCLIENT flag and
605                //       allow interaction between server *service* and client application
606                ATLASSERT(nFlags == ACTIVEOBJECT_STRONG);
607                CComPtr<IRunningObjectTable> pRunningObjectTable;
608                ATLCHECK(GetRunningObjectTable(0, &pRunningObjectTable));
609                CComPtr<IMoniker> pMoniker;
610                ATLCHECK(CreateItemMoniker(OLESTR("!"), StringFromIdentifier(ClassIdentifier), &pMoniker));
611                DWORD nCookie;
612                ATLCHECK(pRunningObjectTable->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE | ROTFLAGS_ALLOWANYCLIENT, pUnknown, pMoniker, &nCookie));
613                return nCookie;
614        }
615        static VOID RevokeActiveObject(DWORD nCookie)
616        {
617                CComPtr<IRunningObjectTable> pRunningObjectTable;
618                ATLCHECK(GetRunningObjectTable(0, &pRunningObjectTable));
619                ATLCHECK(pRunningObjectTable->Revoke(nCookie));
620        }
621};
622
623template <typename _Handler = CRunningObjectActiveObjectHandler>
624class CActiveObjectT :
625        protected _Handler
626{
627private:
628        DWORD m_nCookie;                // Active object identifier
629
630public:
631// CActiveObjectT
632        CActiveObjectT() throw() :
633                m_nCookie(0)
634        {
635        }
636        ~CActiveObjectT() throw()
637        {
638                _ATLTRY
639                {
640                        Unregister();
641                }
642                _ATLCATCHALL()
643                {
644                        _Z_EXCEPTION();
645                }
646        }
647        DWORD GetCookie() const throw()
648        {
649                return m_nCookie;
650        }
651        VOID Register(IUnknown* pUnknown, const CLSID& ClassIdentifier, DWORD nFlags = ACTIVEOBJECT_STRONG)
652        {
653                ATLASSERT(m_nCookie == 0);
654                m_nCookie = RegisterActiveObject(pUnknown, ClassIdentifier, nFlags);
655                ATLASSERT(m_nCookie);
656        }
657        VOID Unregister()
658        {
659                if(m_nCookie)
660                {
661                        RevokeActiveObject(m_nCookie);
662                        m_nCookie = 0;
663                }
664        }
665};
666
667typedef CActiveObjectT<> CActiveObject;
668
669////////////////////////////////////////////////////////////
670// CThreadT
671
672template <typename COwner>
673class ATL_NO_VTABLE CThreadT :
674        public CComObjectRootEx<CComMultiThreadModelNoCS>,
675        public IUnknown
676{
677protected:
678        typedef CThreadT<COwner> CThread;
679
680public:
681
682BEGIN_COM_MAP(CThreadT)
683END_COM_MAP()
684
685public:
686        typedef DWORD (COwner::*OWNERTHREADPROC)(CThread* pThread, CEvent& InitializationEvent, CEvent& TerminationEvent);
687
688        ////////////////////////////////////////////////////////
689        // CMessageQueue
690
691        class CMessageQueue
692        {
693        public:
694        // CMessageQueue
695                CMessageQueue()
696                {
697                        MSG Message;
698                        PeekMessage(&Message, NULL, WM_USER, WM_USER, PM_NOREMOVE);
699                }
700                BOOL Wait(DWORD nTimeoutTime = INFINITE)
701                {
702                        const DWORD nWaitResult = MsgWaitForMultipleObjects(0, NULL, FALSE, nTimeoutTime, QS_POSTMESSAGE);
703                        _Z5_WAITRESULT(nWaitResult);
704                        _A(nWaitResult == WAIT_OBJECT_0 || nWaitResult == WAIT_TIMEOUT && nTimeoutTime != INFINITE);
705                        return nWaitResult == WAIT_OBJECT_0;
706                }
707                BOOL Peek(UINT& nMessage)
708                {
709                        MSG Message;
710                        if(!PeekMessage(&Message, NULL, 0, 0, PM_REMOVE))
711                                return FALSE;
712                        nMessage = Message.message;
713                        return TRUE;
714                }
715                static VOID Post(DWORD nIdentifier, UINT nMessage, WPARAM wParam = 0, LPARAM lParam = 0)
716                {
717                        _A(nIdentifier);
718                        _W(PostThreadMessage(nIdentifier, nMessage, wParam, lParam));
719                }
720        };
721
722private:
723        COwner* m_pOwner;
724        OWNERTHREADPROC m_pOwnerThreadProc;
725        CEvent m_InitializationEvent;
726        CEvent m_TerminationEvent;
727        CHandle m_Handle;
728        DWORD m_nIdentifier;
729
730        DWORD ThreadProc()
731        {
732                DWORD nResult;
733                _ATLTRY
734                {
735                        ATLTRACE(atlTraceGeneral, 3, _T("Starting thread %d (0x%X)\n"), GetCurrentThreadId(), GetCurrentThreadId());
736                        ATLASSERT(m_pOwner && m_pOwnerThreadProc);
737                        nResult = (m_pOwner->*m_pOwnerThreadProc)(this, m_InitializationEvent, m_TerminationEvent);
738                        ATLTRACE(atlTraceGeneral, 3, _T("Stopping thread %d (0x%X), result %d (0x%X)\n"), GetCurrentThreadId(), GetCurrentThreadId(), nResult, nResult);
739                }
740                _ATLCATCH(Exception)
741                {
742                        //_Z_EXCEPTION();
743                        ATLTRACE(atlTraceException, 1, _T("An exception 0x%08X has been caught in thread %d (0x%X)\n"), (HRESULT) Exception, GetCurrentThreadId(), GetCurrentThreadId());
744                        nResult = (HRESULT) Exception;
745                }
746                _ATLCATCHALL()
747                {
748                        //_Z_EXCEPTION();
749                        ATLTRACE(atlTraceException, 1, _T("An exception has been caught in thread %d (0x%X)\n"), GetCurrentThreadId(), GetCurrentThreadId());
750                        nResult = E_FAIL;
751                }
752                return nResult;
753        }
754        static DWORD WINAPI ThreadProc(CThreadT* pThread)
755        {
756                return pThread->ThreadProc();
757        }
758
759public:
760// CThreadT
761        CThreadT() :
762                m_pOwner(NULL),
763                m_pOwnerThreadProc(NULL),
764                m_InitializationEvent(NULL, TRUE, FALSE, NULL),
765                m_TerminationEvent(NULL, TRUE, FALSE, NULL),
766                m_nIdentifier(0)
767        {
768                ATLTRACE(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
769        }
770        ~CThreadT()
771        {
772                ATLTRACE(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
773                Terminate();
774        }
775        const CHandle& GetHandle() const
776        {
777                return m_Handle;
778        }
779        DWORD GetIdentifier() const
780        {
781                return m_nIdentifier;
782        }
783        BOOL GetExitCode(DWORD& nExitCode) const
784        {
785                return GetExitCodeThread(m_Handle, &nExitCode);
786        }
787        BOOL IsStillActive() const
788        {
789                if(!m_Handle)
790                        return FALSE;
791                DWORD nExitCode;
792                __E(GetExitCode(nExitCode));
793                return nExitCode == STILL_ACTIVE;
794        }
795        VOID Initialize(COwner* pOwner, OWNERTHREADPROC pOwnerThreadProc, CEvent** ppInitializationEvent)
796        {
797                ATLASSERT(!m_pOwner && pOwner);
798                ATLASSERT(ppInitializationEvent);
799                m_pOwner = pOwner;
800                m_pOwnerThreadProc = pOwnerThreadProc;
801                ATLASSERT(WaitForSingleObject(m_TerminationEvent, 0) == WAIT_TIMEOUT);
802                static const DWORD g_nFlags = 0; //CREATE_SUSPENDED;
803                m_Handle.Attach(CreateThreadT<CThreadT>(NULL, 0, ThreadProc, this, g_nFlags, &m_nIdentifier));
804                ATLWINCHECK(m_Handle);
805                ATLASSERT(m_nIdentifier);
806                ATLTRACE(atlTraceGeneral, 3, _T("Thread %d (0x%X) started from thread %d (0x%X)\n"), m_nIdentifier, m_nIdentifier, GetCurrentThreadId(), GetCurrentThreadId());
807                //ResumeThread(m_Handle);
808                *ppInitializationEvent = &m_InitializationEvent;
809        }
810        BOOL Initialize(COwner* pOwner, OWNERTHREADPROC pOwnerThreadProc)
811        {
812                CEvent* pInitializationEvent;
813                Initialize(pOwner, pOwnerThreadProc, &pInitializationEvent);
814                ATLASSERT(pInitializationEvent == &m_InitializationEvent);
815                const HANDLE phObjects[] = { m_Handle, m_InitializationEvent };
816                const DWORD nWaitResult = WaitForMultipleObjects(_countof(phObjects), phObjects, FALSE, INFINITE);
817                ATLASSERT((nWaitResult - WAIT_OBJECT_0) < _countof(phObjects));
818                if(nWaitResult == WAIT_OBJECT_0 + 0)
819                {
820                        DWORD nExitCode;
821                        ATLVERIFY(GetExitCodeThread(m_Handle, &nExitCode));
822                        m_Handle.Close();
823                        SetLastError(nExitCode);
824                        return FALSE;
825                }
826                return TRUE;
827        }
828        BOOL Terminate(ULONG nTimeout = INFINITE, BOOL bForce = TRUE)
829        {
830                if(!m_Handle)
831                        return FALSE;
832                ATLTRACE(atlTraceGeneral, 3, _T("Thread %d (0x%X) is being terminated from thread %d (0x%X), nTimeout %d, bForce %d\n"), m_nIdentifier, m_nIdentifier, GetCurrentThreadId(), GetCurrentThreadId(), nTimeout, bForce);
833                ATLVERIFY(m_TerminationEvent.Set());
834                if(GetCurrentThreadId() != m_nIdentifier)
835                {
836                        const DWORD nWaitResult = WaitForSingleObject(m_Handle, nTimeout);
837                        ATLTRACE(atlTraceGeneral, 4, _T("m_nIdentifier %d (0x%X), nWaitResult 0x%X\n"), m_nIdentifier, m_nIdentifier, nWaitResult);
838                        ATLASSERT(nWaitResult == WAIT_OBJECT_0 || nWaitResult == WAIT_TIMEOUT && nTimeout != INFINITE);
839                        if(nWaitResult != WAIT_OBJECT_0)
840                        {
841                                if(!bForce)
842                                        return FALSE;
843                                ATLTRACE(atlTraceGeneral, 2, _T("Thread %d (0x%X) is being forcefully terminated from thread %d (0x%X)\n"), m_nIdentifier, m_nIdentifier, GetCurrentThreadId(), GetCurrentThreadId());
844                                ATLVERIFY(TerminateThread(m_Handle, (DWORD) HRESULT_FROM_WIN32(ERROR_TIMEOUT)));
845                        }
846                        ATLTRACE(atlTraceGeneral, 3, _T("Thread %d (0x%x) has been terminated from thread %d\n"), m_nIdentifier, m_nIdentifier, GetCurrentThreadId());
847                } else
848                        ATLTRACE(atlTraceGeneral, 3, _T("Thread %d (0x%X) is self-terminated\n"), m_nIdentifier, m_nIdentifier);
849                m_Handle.Close();
850                return TRUE;
851        }
852        VOID AsynchronousTerminate()
853        {
854                ATLVERIFY(m_TerminationEvent.Set());
855        }
856        VOID PostMessage(UINT nMessage, WPARAM wParam = 0, LPARAM lParam = 0)
857        {
858                _A(m_Handle);
859                _W(PostThreadMessage(m_nIdentifier, nMessage, wParam, lParam));
860        }
861};
862
863////////////////////////////////////////////////////////
864// CTimedEventDaemon
865
866// TODO: Clean up tracing
867#if _MSC_VER >= 1800 // Visual Studio 2013
868        #if defined(_DEBUG)
869                #define atlTraceTimedEvent 0 // Disabled for stock ATLTRACE
870        #else
871                #define atlTraceTimedEvent ((INT) -1) // Disabled for my ATLTRACE
872        #endif
873#else
874        #define atlTraceTimedEvent atlTraceCore
875#endif
876
877class ATL_NO_VTABLE CTimedEventDaemon :
878        public CComObjectRootEx<CComMultiThreadModelNoCS>,
879        public IUnknown
880{
881        typedef CThreadT<CTimedEventDaemon> CThread;
882        typedef VOID (CALLBACK TIMECALLBACK)(UINT_PTR, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR);
883
884public:
885
886BEGIN_COM_MAP(CTimedEventDaemon)
887END_COM_MAP()
888
889public:
890
891        ////////////////////////////////////////////////////////
892        // CTimedEvent
893
894        class CTimedEvent
895        {
896        public:
897                ULONG m_nDelay;
898                ULONG m_nResolution;
899                TIMECALLBACK* m_pTimeProc;
900                DWORD_PTR m_nUser;
901                UINT m_nFlags;
902                ULONG m_nTime;
903                BOOL m_bShot;
904                BOOL m_bActive;
905
906        public:
907        // CTimedEvent
908                CTimedEvent()
909                {
910                }
911                CTimedEvent(ULONG nDelay, ULONG nResolution, TIMECALLBACK* pTimeProc, DWORD_PTR nUser, UINT nFlags) :
912                        m_nDelay(nDelay),
913                        m_nResolution(nResolution), 
914                        m_pTimeProc(pTimeProc), 
915                        m_nUser(nUser), 
916                        m_nFlags(nFlags),
917                        m_nTime(GetTickCount()),
918                        m_bShot(FALSE),
919                        m_bActive(FALSE)
920                {
921                }
922        };
923
924        ////////////////////////////////////////////////////////
925        // CTimedEventList
926
927        class CTimedEventList :
928                public CAtlList<CTimedEvent>
929        {
930        public:
931        // CTimedEventList
932                BOOL IsValidPosition(POSITION Position) const
933                {
934                        for(POSITION CurrentPosition = GetHeadPosition(); CurrentPosition; GetNext(CurrentPosition))
935                                if(CurrentPosition == Position)
936                                        return TRUE;
937                        return FALSE;
938                }
939                POSITION GetEarliestActivePosition() const
940                {
941                        POSITION BestPosition = NULL;
942                        for(POSITION Position = GetHeadPosition(); Position; GetNext(Position))
943                        {
944                                const CTimedEvent& Event = GetAt(Position);
945                                if(!(Event.m_nFlags & TIME_PERIODIC) && Event.m_bShot)
946                                        continue; // Inactive
947                                if(BestPosition)
948                                {
949                                        const CTimedEvent& BestEvent = GetAt(BestPosition);
950                                        if((LONG) ((Event.m_nTime + Event.m_nDelay) - (BestEvent.m_nTime + BestEvent.m_nDelay)) >= 0)
951                                                continue; // Later
952                                }
953                                BestPosition = Position;
954                        }
955                        return BestPosition;
956                }
957        };
958
959private:
960        static BOOL g_bDefaultTimedEventDaemonTerminated;
961        static CTimedEventDaemon* g_pDefaultTimedEventDaemon;
962        #if _DEVELOPMENT
963                DWORD m_nSignature;
964        #endif // _DEVELOPMENT
965        mutable CComAutoCriticalSection m_DataCriticalSection;
966        CTimedEventList m_TimedEventList;
967        CEvent m_ListChangeEvent;
968        #if defined(_WINDLL)
969                CEvent m_ThreadPreTerminationEvent;
970        #endif // defined(_WINDLL)
971        CObjectPtr<CThread> m_pThread;
972        CEvent m_IdlenessEvent;
973
974        static VOID STDMETHODCALLTYPE DestroyDefaultTimedEventDaemon(DWORD_PTR nParameter)
975        {
976                _ATLTRY
977                {
978                        CObjectPtr<CTimedEventDaemon> pTimedEventDaemon;
979                        {
980                                _A(_pAtlModule);
981                                CComCritSecLock<CComCriticalSection> Lock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
982                                g_bDefaultTimedEventDaemonTerminated = TRUE;
983                                if(g_pDefaultTimedEventDaemon)
984                                {
985                                        #if defined(_DEBUG) || _TRACE
986                                                // NOTE: Add a lock removed by timeSetEvent
987                                                _pAtlModule->Lock();
988                                        #endif // defined(_DEBUG) || _TRACE
989                                        pTimedEventDaemon.Swap(&g_pDefaultTimedEventDaemon);
990                                }
991                        }
992                        if(pTimedEventDaemon)
993                        {
994                                _A(pTimedEventDaemon == (CTimedEventDaemon*) nParameter);
995                                pTimedEventDaemon->Terminate();
996                        }
997                }
998                _ATLCATCHALL()
999                {
1000                        _Z_EXCEPTION();
1001                }
1002        }
1003        DWORD ThreadProc(CThread* pThread, CEvent& InitializationEvent, CEvent& TerminationEvent)
1004        {
1005                CMultiThreadedApartment Apartment;
1006                CObjectPtr<CTimedEventDaemon> pThisReference = this;
1007                #if defined(_WINDLL)
1008                        CObjectPtr<CThread> pThreadReference = pThread;
1009                #endif // defined(_WINDLL)
1010                _W(InitializationEvent.Set());
1011                const HANDLE phObjects[] = { TerminationEvent, m_ListChangeEvent };
1012                for(; ; )
1013                {
1014                        const DWORD nWaitResult = WaitForMultipleObjects(DIM(phObjects), phObjects, FALSE, INFINITE);
1015                        _Z5_WAITRESULT(nWaitResult);
1016                        _A((nWaitResult - WAIT_OBJECT_0) < DIM(phObjects));
1017                        if(nWaitResult != WAIT_OBJECT_0 + 1) // m_ListChangeEvent
1018                                break;
1019                        for(; ; )
1020                        {
1021                                POSITION CurrentPosition = NULL;
1022                                LONG nDelay = INFINITE;
1023                                {
1024                                        CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
1025                                        CurrentPosition = m_TimedEventList.GetEarliestActivePosition();
1026                                        _W(m_ListChangeEvent.Reset());
1027                                        _Z4(atlTraceTimedEvent, 4, _T("%d timed events on the list\n"), m_TimedEventList.GetCount());
1028                                        if(!CurrentPosition)
1029                                        {
1030                                                _Z4(atlTraceTimedEvent, 4, _T("No more active timed events found\n"));
1031                                                break;
1032                                        }
1033                                        const CTimedEvent& CurrentTimedEvent = m_TimedEventList.GetAt(CurrentPosition);
1034                                        nDelay = (LONG) (CurrentTimedEvent.m_nTime + CurrentTimedEvent.m_nDelay) - GetTickCount();
1035                                }
1036                                const DWORD nWaitResult = (nDelay > 0) ? WaitForMultipleObjects(DIM(phObjects), phObjects, FALSE, nDelay) : WAIT_TIMEOUT;
1037                                _Z5_WAITRESULT(nWaitResult);
1038                                _A((nWaitResult - WAIT_OBJECT_0) < DIM(phObjects) || nWaitResult == WAIT_TIMEOUT);
1039                                if(nWaitResult == WAIT_OBJECT_0 + 0) // Termination
1040                                        break;
1041                                if(nWaitResult == WAIT_OBJECT_0 + 1) // m_ListChangeEvent
1042                                {
1043                                        _Z4(atlTraceTimedEvent, 4, _T("Timed event list changed\n"));
1044                                        continue;
1045                                }
1046                                TIMECALLBACK* pTimeProc = NULL;
1047                                DWORD_PTR nUser = 0;
1048                                {
1049                                        CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
1050                                        if(!m_TimedEventList.IsValidPosition(CurrentPosition))
1051                                                continue;
1052                                        _Z4(atlTraceTimedEvent, 4, _T("Firing an event, CurrentPosition 0x%p\n"), CurrentPosition);
1053                                        CTimedEvent& CurrentTimedEvent = m_TimedEventList.GetAt(CurrentPosition);
1054                                        CurrentTimedEvent.m_nTime = GetTickCount();
1055                                        CurrentTimedEvent.m_bShot = TRUE;
1056                                        CurrentTimedEvent.m_bActive = TRUE;
1057                                        pTimeProc = CurrentTimedEvent.m_pTimeProc;
1058                                        nUser = CurrentTimedEvent.m_nUser;
1059                                        _W(m_IdlenessEvent.Reset());
1060                                }
1061                                if(pTimeProc)
1062                                        _ATLTRY
1063                                        {
1064                                                (*pTimeProc)((UINT) (UINT_PTR) CurrentPosition, 0, nUser, 0, 0);
1065                                        }
1066                                        _ATLCATCHALL()
1067                                        {
1068                                                _Z_EXCEPTION();
1069                                        }
1070                                _W(m_IdlenessEvent.Set());
1071                                {
1072                                        CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
1073                                        if(m_TimedEventList.IsValidPosition(CurrentPosition))
1074                                                m_TimedEventList.GetAt(CurrentPosition).m_bActive = FALSE;
1075                                }
1076                        }
1077                }
1078                #if defined(_WINDLL)
1079                        _W(m_ThreadPreTerminationEvent.Set());
1080                        pThreadReference.Release();
1081                #endif // defined(_WINDLL)
1082                pThisReference.Release();
1083                return 0;
1084        }
1085
1086public:
1087// CTimedEventDaemon
1088        static CObjectPtr<CTimedEventDaemon> GetDefaultTimedEventDaemon()
1089        {
1090                CObjectPtr<CTimedEventDaemon> pTimedEventDaemon;
1091                CComCritSecLock<CComCriticalSection> Lock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
1092                if(!g_bDefaultTimedEventDaemonTerminated)
1093                {
1094                        if(!g_pDefaultTimedEventDaemon)
1095                        {
1096                                CObjectPtr<CTimedEventDaemon> pTimedEventDaemon;
1097                                _ATLTRY
1098                                {
1099                                        pTimedEventDaemon.Construct()->Initialize();
1100                                        _pAtlModule->AddTermFunc(DestroyDefaultTimedEventDaemon, (DWORD_PTR) (CTimedEventDaemon*) pTimedEventDaemon);
1101                                        g_pDefaultTimedEventDaemon = pTimedEventDaemon.Detach();
1102                                        #if defined(_DEBUG) || _TRACE
1103                                                // NOTE: Exclude object's module lock so that it does not affect termination lock count report
1104                                                _pAtlModule->Unlock();
1105                                        #endif // defined(_DEBUG) || _TRACE
1106                                }
1107                                _ATLCATCHALL()
1108                                {
1109                                        _Z_EXCEPTION();
1110                                }
1111                        }
1112                        pTimedEventDaemon = g_pDefaultTimedEventDaemon;
1113                }
1114                return pTimedEventDaemon;
1115        }
1116        CTimedEventDaemon() :
1117                m_ListChangeEvent(TRUE, FALSE),
1118                m_IdlenessEvent(TRUE, TRUE)
1119        {
1120                _Z4_THIS();
1121                #if _DEVELOPMENT
1122                        // WARN: CTimedEventDaemon has unresolved problems with late termination, so
1123                        //       we mark used memory block to distinguish in head trace
1124                        m_nSignature = 0x89674523;
1125                #endif // _DEVELOPMENT
1126        }
1127        ~CTimedEventDaemon()
1128        {
1129                _Z4_THIS();
1130                _A(!m_pThread);
1131        }
1132        VOID Initialize()
1133        {
1134                #if defined(_WINDLL)
1135                        _A(!m_ThreadPreTerminationEvent);
1136                        __E(m_ThreadPreTerminationEvent.Create(NULL, TRUE, FALSE, NULL));
1137                #endif // defined(_WINDLL)
1138                _A(!m_pThread);
1139                __E(m_pThread.Construct()->Initialize(this, &CTimedEventDaemon::ThreadProc));
1140        }
1141        VOID Terminate()
1142        {
1143                CObjectPtr<CThread> pThread;
1144                {
1145                        CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
1146                        m_pThread.Swap(pThread);
1147                }
1148                if(pThread)
1149                {
1150                        #if defined(_WINDLL)
1151                                _A(m_ThreadPreTerminationEvent);
1152                                CEvent ThreadPreTerminationEvent;
1153                                if(DuplicateHandle(GetCurrentProcess(), m_ThreadPreTerminationEvent, GetCurrentProcess(), &ThreadPreTerminationEvent.m_h, 0, FALSE, DUPLICATE_SAME_ACCESS))
1154                                {
1155                                        CEvent Thread;
1156                                        _W(DuplicateHandle(GetCurrentProcess(), pThread->GetHandle(), GetCurrentProcess(), &Thread.m_h, 0, FALSE, DUPLICATE_SAME_ACCESS));
1157                                        pThread->AsynchronousTerminate();
1158                                        pThread.Release();
1159                                        const HANDLE phObjects[] = { ThreadPreTerminationEvent, Thread };
1160                                        const DWORD nWaitResult = WaitForMultipleObjects(DIM(phObjects), phObjects, FALSE, INFINITE);
1161                                        _Z5_WAITRESULT(nWaitResult);
1162                                        _A(nWaitResult - WAIT_OBJECT_0 < DIM(phObjects));
1163                                        return;
1164                                }
1165                        #endif // !defined(_WINDLL)
1166                        pThread->Terminate();
1167                }
1168        }
1169        HRESULT SetEvent(ULONG nDelay, ULONG nResolution, TIMECALLBACK* pTimeProc, DWORD_PTR nUser, UINT nFlags, UINT_PTR* pnEvent)
1170        {
1171                _ATLTRY
1172                {
1173                        CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
1174                        const POSITION Position = m_TimedEventList.AddTail(CTimedEvent(nDelay, nResolution, pTimeProc, nUser, nFlags));
1175                        _A(Position);
1176                        _W(m_ListChangeEvent.Set());
1177                        _A(pnEvent);
1178                        *pnEvent = (UINT_PTR) Position;
1179                        _Z4(atlTraceTimedEvent, 4, _T("An event has been set, Position 0x%p, nDelay %d, nFlags 0x%X, %d events on the list\n"), Position, nDelay, nFlags, m_TimedEventList.GetCount());
1180                }
1181                _ATLCATCH(Exception)
1182                {
1183                        _C(Exception.m_hr);
1184                }
1185                return S_OK;
1186        }
1187        HRESULT KillEvent(UINT_PTR nEvent)
1188        {
1189                BOOL bConcurrentlyActive = FALSE;
1190                {
1191                        CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
1192                        const POSITION Position = (POSITION) nEvent;
1193                        _Z4(atlTraceTimedEvent, 4, _T("An event is being killed, Position 0x%p\n"), Position);
1194                        _D(m_TimedEventList.IsValidPosition(Position), E_INVALIDARG);
1195                        if(m_TimedEventList.GetAt(Position).m_bActive)
1196                                if(m_pThread && m_pThread->GetIdentifier() != GetCurrentThreadId())
1197                                        bConcurrentlyActive = TRUE;
1198                        m_TimedEventList.RemoveAt(Position);
1199                        _W(m_ListChangeEvent.Set());
1200                        _Z4(atlTraceTimedEvent, 4, _T("An event has been killed, Position 0x%p, %d more events on the list\n"), Position, m_TimedEventList.GetCount());
1201                }
1202                if(bConcurrentlyActive)
1203                {
1204                        static const DWORD g_nTimeout = 5 * 1000; // 5 seconds
1205                        const DWORD nWaitResult = WaitForSingleObject(m_IdlenessEvent, g_nTimeout);
1206                        //_Z5_WAITRESULT(nWaitResult);
1207                        _A(nWaitResult == WAIT_OBJECT_0 || nWaitResult == WAIT_TIMEOUT);
1208                        if(nWaitResult != WAIT_OBJECT_0)
1209                                _Z2(atlTraceTimedEvent, 2, _T("Worker thread failed to get idle within reasonable time, nWaitResult 0x%X\n"), nWaitResult);
1210                }
1211                return S_OK;
1212        }
1213
1214// Standard API substitution
1215        static MMRESULT timeSetEvent(UINT nDelay, UINT nResolution, TIMECALLBACK* pTimeProc, DWORD_PTR nUser, UINT nFlags)
1216        {
1217                _A(nFlags == (TIME_CALLBACK_FUNCTION | TIME_PERIODIC) || nFlags == (TIME_CALLBACK_FUNCTION | TIME_ONESHOT));
1218                UINT_PTR nEvent = 0;
1219                if(_pAtlModule && _pAtlModule->cbSize)
1220                {
1221                        CObjectPtr<CTimedEventDaemon> pTimedEventDaemon = GetDefaultTimedEventDaemon();
1222                        if(pTimedEventDaemon)
1223                                _V(pTimedEventDaemon->SetEvent(nDelay, nResolution, pTimeProc, nUser, nFlags, &nEvent));
1224                }
1225                return (MMRESULT) nEvent;
1226        }
1227        static MMRESULT timeKillEvent(UINT uEvent)
1228        {
1229                MMRESULT nResult = MMSYSERR_INVALPARAM;
1230                if(_pAtlModule && _pAtlModule->cbSize)
1231                {
1232                        CObjectPtr<CTimedEventDaemon> pTimedEventDaemon;
1233                        {
1234                                CComCritSecLock<CComCriticalSection> Lock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
1235                                pTimedEventDaemon = g_pDefaultTimedEventDaemon;
1236                        }
1237                        if(pTimedEventDaemon)
1238                                if(SUCCEEDED(pTimedEventDaemon->KillEvent((UINT_PTR) uEvent)))
1239                                        nResult = MMSYSERR_NOERROR;
1240                }
1241                return nResult;
1242        }
1243};
1244
1245__declspec(selectany) BOOL CTimedEventDaemon::g_bDefaultTimedEventDaemonTerminated = FALSE;
1246__declspec(selectany) CTimedEventDaemon* CTimedEventDaemon::g_pDefaultTimedEventDaemon = NULL;
1247
1248////////////////////////////////////////////////////////////
1249// CTimedEventT, CSimpleTimedEventT
1250
1251template <typename T, typename _Owner, typename _OwnerPtr = _Owner*, typename _Parameter = INT_PTR>
1252class CTimedEventT
1253{
1254protected:
1255        typedef CTimedEventT<T, _Owner, _OwnerPtr, _Parameter> CTimedEvent;
1256        typedef VOID (_Owner::*HANDLER)(T*);
1257
1258public:
1259        mutable CComAutoCriticalSection m_DataCriticalSection;
1260        CObjectPtr<CTimedEventDaemon> m_pTimedEventDaemon;
1261        UINT_PTR m_nEvent;
1262        _OwnerPtr m_pOwner;
1263        _Parameter m_Parameter;
1264        HANDLER m_pHandler;
1265        CEvent m_IdlenessEvent;
1266
1267        VOID TimedEventProc(UINT_PTR nEvent)
1268        {
1269                _OwnerPtr pOwner = NULL;
1270                _Parameter Parameter;
1271                HANDLER pHandler;
1272                {
1273                        CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
1274                        if(m_nEvent == nEvent)
1275                        {
1276                                pOwner = m_pOwner;
1277                                Parameter = m_Parameter;
1278                                pHandler = m_pHandler;
1279                                _A(pOwner && pHandler);
1280                        }
1281                }
1282                if(pOwner)
1283                {
1284                        // NOTE: Since the object may get destroyed insde callback, we duplicate handle required to be set
1285                        CEvent IdlenessEvent;
1286                        _W(DuplicateHandle(GetCurrentProcess(), m_IdlenessEvent, GetCurrentProcess(), &IdlenessEvent.m_h, 0, FALSE, DUPLICATE_SAME_ACCESS));
1287                        _W(IdlenessEvent.Reset());
1288                        (pOwner->*pHandler)(static_cast<T*>(this));
1289                        _W(IdlenessEvent.Set());
1290                }
1291        }
1292        static VOID CALLBACK TimedEventProc(UINT_PTR nEvent, UINT, DWORD_PTR nUser, DWORD_PTR, DWORD_PTR)
1293        {
1294                _ATLTRY
1295                {
1296                        ((CTimedEventT*) nUser)->TimedEventProc((UINT_PTR) nEvent);
1297                }
1298                _ATLCATCHALL()
1299                {
1300                        _Z_EXCEPTION();
1301                }
1302        }
1303
1304public:
1305// CTimedEventT
1306        CTimedEventT() :
1307                m_nEvent(0),
1308                m_IdlenessEvent(TRUE, TRUE)
1309        {
1310#if defined(_DEBUG)
1311                m_pOwner = NULL;
1312                m_pHandler = NULL;
1313#endif // defined(_DEBUG)
1314        }
1315        ~CTimedEventT()
1316        {
1317                Destroy();
1318                static const DWORD g_nTimeout = 5 * 1000;
1319                const DWORD nWaitResult = WaitForSingleObject(m_IdlenessEvent, g_nTimeout);
1320                _Z5_WAITRESULT(nWaitResult);
1321                _A(nWaitResult == WAIT_OBJECT_0 || nWaitResult == WAIT_TIMEOUT);
1322                if(nWaitResult != WAIT_OBJECT_0)
1323                        ATLTRACE(atlTraceGeneral, 2, _T("Worker thread failed to get idle within reasonable time, nWaitResult %d\n"), nWaitResult);
1324        }
1325        VOID Initialize(CTimedEventDaemon* pTimedEventDaemon)
1326        {
1327                _A(pTimedEventDaemon);
1328                CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
1329                _A(!m_pTimedEventDaemon || m_pTimedEventDaemon == pTimedEventDaemon);
1330                m_pTimedEventDaemon = pTimedEventDaemon;
1331        }
1332        const _Parameter& GetParameter() const
1333        {
1334                return m_Parameter;
1335        }
1336        VOID SetParameter(_Parameter Parameter)
1337        {
1338                m_Parameter = Parameter;
1339        }
1340        UINT_PTR GetEvent() const
1341        {
1342                CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
1343                return m_nEvent;
1344        }
1345        BOOL IsActive() const
1346        {
1347                CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
1348                return m_nEvent != 0;
1349        }
1350        VOID Create(_Owner* pOwner, HANDLER pHandler, ULONG nDelay, ULONG nResolution, BOOL bPeriodic)
1351        {
1352                _A(pOwner && pHandler);
1353                CObjectPtr<CTimedEventDaemon> pTimedEventDaemon;
1354                UINT_PTR nPreviousEvent;
1355                {
1356                        CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
1357                        if(m_pTimedEventDaemon)
1358                        {
1359                                pTimedEventDaemon = m_pTimedEventDaemon;
1360                                nPreviousEvent = m_nEvent;
1361                                UINT_PTR nEvent;
1362                                __C(m_pTimedEventDaemon->SetEvent(nDelay, nResolution, TimedEventProc, (DWORD_PTR) this, (bPeriodic ? TIME_PERIODIC : TIME_ONESHOT), &nEvent));
1363                                m_nEvent = nEvent;
1364                                m_pOwner = pOwner;
1365                                m_pHandler = pHandler;
1366                        }
1367                }
1368                if(pTimedEventDaemon && nPreviousEvent)
1369                        _V(pTimedEventDaemon->KillEvent(nPreviousEvent));
1370        }
1371        VOID CreateOneshot(_Owner* pOwner, HANDLER pHandler, ULONG nDelay, ULONG nResolution = 0)
1372        {
1373                return Create(pOwner, pHandler, nDelay, nResolution, FALSE);
1374        }
1375        VOID CreatePeriodic(_Owner* pOwner, HANDLER pHandler, ULONG nDelay, ULONG nResolution = 0)
1376        {
1377                return Create(pOwner, pHandler, nDelay, nResolution, TRUE);
1378        }
1379        VOID Destroy()
1380        {
1381                CObjectPtr<CTimedEventDaemon> pTimedEventDaemon;
1382                UINT_PTR nEvent;
1383                {
1384                        CComCritSecLock<CComAutoCriticalSection> DataLock(m_DataCriticalSection);
1385                        _A(m_pTimedEventDaemon);
1386                        pTimedEventDaemon = m_pTimedEventDaemon;
1387                        nEvent = m_nEvent;
1388                        m_nEvent = 0;
1389                        m_pOwner = NULL;
1390                        m_pHandler = NULL;
1391                }
1392                if(pTimedEventDaemon && nEvent)
1393                        _V(pTimedEventDaemon->KillEvent(nEvent));
1394        }
1395};
1396
1397template <typename _Owner, typename _OwnerPtr = _Owner*, typename _Parameter = INT_PTR>
1398class CSimpleTimedEventT :
1399        public CTimedEventT<CSimpleTimedEventT<_Owner, _OwnerPtr, _Parameter>, _Owner, _OwnerPtr, _Parameter>
1400{
1401protected:
1402        typedef CSimpleTimedEventT<_Owner, _OwnerPtr, _Parameter> CSimpleTimedEvent;
1403
1404public:
1405// CSimpleTimedEventT
1406        CSimpleTimedEventT()
1407        {
1408                __super::Initialize(CTimedEventDaemon::GetDefaultTimedEventDaemon());
1409        }
1410};
1411
1412////////////////////////////////////////////////////////////
1413// CDebugTimeCheck, CDebugTimeCheck
1414
1415#if defined(_M_IX86) && (defined(_DEBUG) || _TRACE)
1416
1417class CDebugTimeCheck
1418{
1419public:
1420
1421        ////////////////////////////////////////////////////////
1422        // CCheck
1423
1424        class ATL_NO_VTABLE CCheck :
1425                public CComObjectRootEx<CComMultiThreadModelNoCS>,
1426                public IUnknown
1427        {
1428                typedef CSimpleTimedEventT<CCheck, CObjectPtr<CCheck> > CTimedEvent;
1429
1430        public:
1431
1432        BEGIN_COM_MAP(CCheck)
1433        END_COM_MAP()
1434
1435        private:
1436                DWORD m_nThreadIdentifier;
1437                CString m_sDescription;
1438                CInterlockedT<BOOL> m_bTerminated;
1439                CTimedEvent m_TimeoutEvent;
1440                ULONG m_nEventTimeout;
1441                ULONG m_nCheckTimeout;
1442
1443                VOID TraceTimeout(CTimedEvent*)
1444                {
1445                        _A(_pAtlModule);
1446                        CComCritSecLock<CComCriticalSection> Lock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
1447                        if(m_bTerminated)
1448                                return;
1449                        m_nCheckTimeout += m_nEventTimeout;
1450                        ATLTRACE(atlTraceGeneral, 2, _T("Timeout %d ms in thread %d, m_sDescription \"%s\"\n"), m_nCheckTimeout, m_nThreadIdentifier, m_sDescription);
1451                        if(m_nCheckTimeout == 3 * m_nEventTimeout)
1452                                _ATLTRY
1453                                {
1454                                        CDebugTraceCallStack::TraceCallStack(m_nThreadIdentifier);
1455                                        // NOTE: An exception would possibly trigger an external debugger event
1456                                        AtlThrow(HRESULT_FROM_WIN32(ERROR_TIMEOUT));
1457                                }
1458                                _ATLCATCHALL()
1459                                {
1460                                        _Z_EXCEPTION();
1461                                }
1462                }
1463
1464        public:
1465        // CCheck
1466                CCheck() :
1467                        m_nThreadIdentifier(0)
1468                {
1469                        _Z5_THIS();
1470                }
1471                ~CCheck()
1472                {
1473                        _Z5_THIS();
1474                        _A(!m_TimeoutEvent.IsActive());
1475                }
1476                VOID Initialize(const CString& sDescription, ULONG nTimeout)
1477                {
1478                        _A(!m_TimeoutEvent.IsActive());
1479                        m_nThreadIdentifier = GetCurrentThreadId();
1480                        m_sDescription = sDescription;
1481                        m_bTerminated = FALSE;
1482                        m_nEventTimeout = nTimeout;
1483                        m_nCheckTimeout = 0;
1484                        m_TimeoutEvent.CreatePeriodic(this, &CDebugTimeCheck::CCheck::TraceTimeout, nTimeout);
1485                }
1486                VOID Terminate()
1487                {
1488                        m_bTerminated = TRUE;
1489                        _A(_pAtlModule);
1490                        CComCritSecLock<CComCriticalSection> Lock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
1491                        m_TimeoutEvent.Destroy();
1492                }
1493        };
1494
1495private:
1496        CObjectPtr<CCheck> m_pCheck;
1497
1498public:
1499// CDebugTimeCheck
1500        static ULONG GetDefaultTimeout()
1501        {
1502                static const ULONG g_nTimeout = 5000;
1503                return g_nTimeout;
1504        }
1505        CDebugTimeCheck(const CString& sDescription, ULONG nTimeout = GetDefaultTimeout())
1506        {
1507                m_pCheck.Construct()->Initialize(sDescription, nTimeout);
1508        }
1509        CDebugTimeCheck(LPCTSTR pszDescription = NULL, ULONG nTimeout = GetDefaultTimeout())
1510        {
1511                m_pCheck.Construct()->Initialize(CString(pszDescription), nTimeout);
1512        }
1513        ~CDebugTimeCheck()
1514        {
1515                if(m_pCheck)
1516                        m_pCheck->Terminate();
1517        }
1518};
1519
1520#else
1521
1522class CDebugTimeCheck
1523{
1524public:
1525// CDebugTimeCheck
1526        CDebugTimeCheck(LPCTSTR = NULL, ULONG = 0) throw()
1527        {
1528        }
1529};
1530
1531#endif // defined(_M_IX86) && (defined(_DEBUG) || _TRACE)
1532
1533////////////////////////////////////////////////////////////
1534// CRoCriticalSections
1535
1536#if defined(_DEBUG) || _TRACE
1537
1538class CRoCriticalSections
1539{
1540private:
1541        static CTimedEventDaemon* g_pTimedEventDaemon;
1542
1543        static VOID STDMETHODCALLTYPE DestroyTimedEventDaemon(DWORD_PTR nParameter) throw()
1544        {
1545                _ATLTRY
1546                {
1547                        _A(_pAtlModule);
1548                        CObjectPtr<CTimedEventDaemon> pTimedEventDaemon = g_pTimedEventDaemon;
1549                        g_pTimedEventDaemon = NULL;
1550                        _A(pTimedEventDaemon == (CTimedEventDaemon*) nParameter);
1551                        if(pTimedEventDaemon)
1552                        {
1553                                _pAtlModule->Lock();
1554                                pTimedEventDaemon->Terminate();
1555                        }
1556                }
1557                _ATLCATCHALL()
1558                {
1559                        _Z_EXCEPTION();
1560                }
1561        }
1562
1563public:
1564// CRoCriticalSections
1565        static CObjectPtr<CTimedEventDaemon> GetTimedEventDaemon()
1566        {
1567                _A(_pAtlModule);
1568                _A(_pAtlModule->cbSize);
1569                CComCritSecLock<CComCriticalSection> Lock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
1570                if(!g_pTimedEventDaemon)
1571                {
1572                        CObjectPtr<CTimedEventDaemon> pTimedEventDaemon;
1573                        pTimedEventDaemon.Construct()->Initialize();
1574                        _pAtlModule->Unlock();
1575                        _pAtlModule->AddTermFunc(DestroyTimedEventDaemon, (DWORD_PTR) (CTimedEventDaemon*) pTimedEventDaemon);
1576                        g_pTimedEventDaemon = pTimedEventDaemon.Detach();
1577                }
1578                return g_pTimedEventDaemon;
1579        }
1580        static CObjectPtr<CTimedEventDaemon> GetCurrentTimedEventDaemon() throw()
1581        {
1582                _A(_pAtlModule);
1583                _A(_pAtlModule->cbSize);
1584                CComCritSecLock<CComCriticalSection> Lock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
1585                return g_pTimedEventDaemon;
1586        }
1587        static UINT_PTR SetEvent(UINT nDelay, UINT nResolution, VOID (CALLBACK *pTimeProc)(UINT_PTR, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR), DWORD_PTR nUser, UINT nFlags) throw()
1588        {
1589                UINT_PTR nEvent = 0;
1590                CObjectPtr<CTimedEventDaemon> pTimedEventDaemon = g_pTimedEventDaemon;
1591                if(pTimedEventDaemon)
1592                        _V(pTimedEventDaemon->SetEvent(nDelay, nResolution, pTimeProc, nUser, nFlags, &nEvent));
1593                return nEvent;
1594        }
1595        static VOID KillEvent(UINT_PTR nEvent) throw()
1596        {
1597                CObjectPtr<CTimedEventDaemon> pTimedEventDaemon = g_pTimedEventDaemon;
1598                if(pTimedEventDaemon)
1599                        _V(pTimedEventDaemon->KillEvent(nEvent));
1600        }
1601};
1602
1603__declspec(selectany) CTimedEventDaemon* CRoCriticalSections::g_pTimedEventDaemon = NULL;
1604
1605#endif // defined(_DEBUG) || _TRACE
1606
1607////////////////////////////////////////////////////////////
1608// CRoCriticalSection, CRoCriticalSectionLock
1609
1610#if defined(_DEBUG) || _TRACE
1611
1612#pragma warning(disable: 4748) // warning C4748: /GS can not protect parameters and local variables from local buffer overrun because optimizations are disabled in function
1613#pragma optimize("", off)
1614
1615class CRoCriticalSection :
1616        public CComAutoCriticalSection
1617{
1618public:
1619
1620        ////////////////////////////////////////////////////////
1621        // CLockContext
1622
1623        class CLockContext
1624        {
1625        public:
1626                CRoCriticalSection& m_CriticalSection;
1627                DWORD m_nThreadIdentifier;
1628                CONTEXT& m_ThreadContext;
1629                ULONG m_nTimeout;
1630                ULONG m_nTimeoutTime;
1631
1632        public:
1633        // CLockContext
1634                CLockContext(CRoCriticalSection* pCriticalSection, CONTEXT& ThreadContext, ULONG nTimeout) :
1635                        m_CriticalSection(*pCriticalSection),
1636                        m_nThreadIdentifier(GetCurrentThreadId()),
1637                        m_ThreadContext(ThreadContext),
1638                        m_nTimeout(nTimeout),
1639                        m_nTimeoutTime(0)
1640                {
1641                }
1642        };
1643
1644private:
1645        static CTlsIndex g_nContextTlsIndex;
1646        static CComAutoCriticalSection g_CriticalSection;
1647        DWORD m_nLockThreadIdentifier;
1648        CONTEXT m_LockThreadContext;
1649
1650        VOID LockTimeout(CLockContext& LockContext)
1651        {
1652                LockContext.m_nTimeoutTime += LockContext.m_nTimeout;
1653                CComCritSecLock<CComAutoCriticalSection> GlobalLock(g_CriticalSection);
1654                ATLCORETRACE1(atlTraceGeneral, 1, _T("Critical section 0x%08X deadlock suspicion: locked in thread %d, trying to lock in thread %d, timeout %d ms\n"), this, m_nLockThreadIdentifier, LockContext.m_nThreadIdentifier, LockContext.m_nTimeoutTime);
1655                const UINT nTimeoutCount = LockContext.m_nTimeoutTime / LockContext.m_nTimeout;
1656                if(nTimeoutCount % 64 == 3)
1657                {
1658                        DWORD nLockThreadIdentifier = m_nLockThreadIdentifier;
1659                        CONTEXT LockedThreadContext = m_LockThreadContext;
1660                        CONTEXT LockingThreadContext = LockContext.m_ThreadContext;
1661                        CComCritSecLock<CComAutoCriticalSection> Lock(CDebugSymbols::GetGlobalCriticalSection());
1662                        #if defined(_DEBUG)
1663                                // NOTE: Debug builds don't have functions inlined so lock time stack is likely to be damaged anyway, let us just skip it
1664                                LockedThreadContext.ContextFlags = 0;
1665                        #endif // defined(_DEBUG)
1666                        if(LockedThreadContext.ContextFlags)
1667                        {
1668                                ATLCORETRACE3(LockedThreadContext)(atlTraceGeneral, 2, _T("Thread %d locked the critical section 0x%p, lock time call stack follows:\n"), nLockThreadIdentifier, this);
1669                                CDebugTraceCallStack::TraceCallStack(nLockThreadIdentifier, LockedThreadContext);
1670                        } else
1671                                ATLCORETRACE3(LockedThreadContext)(atlTraceGeneral, 2, _T("Thread %d locked the critical section 0x%p\n"), nLockThreadIdentifier, this);
1672                        ATLCORETRACE1(atlTraceGeneral, 2, _T("Thread %d current stack follows:\n"), nLockThreadIdentifier, this);
1673                        CDebugTraceCallStack::TraceCallStack(nLockThreadIdentifier);
1674                        ATLCORETRACE3(LockingThreadContext)(atlTraceGeneral, 2, _T("Thread %d is trying to lock the critical section 0x%p, call stack follows:\n"), LockContext.m_nThreadIdentifier, this);
1675                        CDebugTraceCallStack::TraceCallStack(LockContext.m_nThreadIdentifier, LockingThreadContext);
1676                        #pragma region MiniDump
1677                        #if defined(_WINDLL) && !defined(_WIN64)
1678                                #if !defined(_DEBUG) && _TRACE
1679                                        if(nTimeoutCount == 3)
1680                                        {
1681                                                typedef HRESULT (STDAPICALLTYPE *WRITEMINIDUMP)();
1682                                                WRITEMINIDUMP pWriteMiniDump = (WRITEMINIDUMP) GetProcAddress(_AtlBaseModule.GetModuleInstance(), "WriteMiniDump");
1683                                                if(pWriteMiniDump)
1684                                                {
1685                                                        TCHAR pszRunDllPath[MAX_PATH] = { 0 };
1686                                                        ATLVERIFY(GetSystemDirectory(pszRunDllPath, DIM(pszRunDllPath)));
1687                                                        Combine(pszRunDllPath, pszRunDllPath, _T("rundll32.exe"));
1688                                                        TCHAR pszModuleName[MAX_PATH] = { 0 };
1689                                                        ATLVERIFY(GetModuleFileName(_AtlBaseModule.GetModuleInstance(), pszModuleName, DIM(pszModuleName)));
1690                                                        CRoArrayT<CString> Array;
1691                                                        _W(Array.Add(AtlFormatString(_T("%d"), GetCurrentProcessId())) >= 0);
1692                                                        TCHAR pszProcessModulePath[MAX_PATH] = { 0 }, pszModulePath[MAX_PATH] = { 0 };
1693                                                        _W(GetModuleFileName(NULL, pszProcessModulePath, DIM(pszProcessModulePath)));
1694                                                        _W(GetModuleFileName(_AtlBaseModule.GetModuleInstance(), pszModulePath, DIM(pszModulePath)));
1695                                                        _W(Array.Add(pszProcessModulePath) >= 0);
1696                                                        _W(Array.Add(pszModulePath) >= 0);
1697                                                        _W(Array.Add(_T("Deadlock")) >= 0);
1698                                                        STARTUPINFO StartupInformation;
1699                                                        ZeroMemory(&StartupInformation, sizeof StartupInformation);
1700                                                        StartupInformation.cb = sizeof StartupInformation;
1701                                                        PROCESS_INFORMATION ProcessInformation;
1702                                                        if(CreateProcess(NULL, const_cast<LPTSTR>((LPCTSTR) AtlFormatString(_T("\"%s\" \"%s\",WriteMiniDump %s"), pszRunDllPath, pszModuleName, _StringHelper::GetCommaSeparatedValue(Array))), NULL, NULL, FALSE, 0, NULL, NULL, &StartupInformation, &ProcessInformation))
1703                                                        {
1704                                                                reinterpret_cast<CHandle&>(ProcessInformation.hProcess).Close();
1705                                                                reinterpret_cast<CHandle&>(ProcessInformation.hThread).Close();
1706                                                        } else
1707                                                                ATLCORETRACE3(LockedThreadContext)(atlTraceGeneral, 2, _T("Failed to CreateProcess: 0x%08X\n"), nLockThreadIdentifier, AtlHresultFromLastError());
1708                                                }
1709                                        }
1710                                #endif // !defined(_DEBUG) && _TRACE
1711                        #endif // defined(_WINDLL) && !defined(_WIN64)
1712                        #pragma endregion
1713                        #if defined(_DEBUG)
1714                                _CrtDbgBreak(); // Break into debugger to investigate the issue
1715                        #endif // defined(_DEBUG)
1716                }
1717        }
1718        static VOID CALLBACK LockTimeout(UINT_PTR nEvent, UINT, DWORD_PTR nParameter, DWORD_PTR, DWORD_PTR)
1719        {
1720                CLockContext* pLockContext = (CLockContext*) nParameter;
1721                _A(pLockContext);
1722                _ATLTRY
1723                {
1724                        pLockContext->m_CriticalSection.LockTimeout(*pLockContext);
1725                }
1726                _ATLCATCHALL()
1727                {
1728                        _Z_EXCEPTION();
1729                }
1730        }
1731        CRoCriticalSection(const CRoCriticalSection&);
1732        CRoCriticalSection& operator = (const CRoCriticalSection&);
1733
1734public:
1735// CRoCriticalSection
1736        CRoCriticalSection()
1737        {
1738                m_nLockThreadIdentifier = 0;
1739                ZeroMemory(&m_LockThreadContext, sizeof m_LockThreadContext);
1740        }
1741        ~CRoCriticalSection()
1742        {
1743                _A(m_sec.LockCount < 0);
1744        }
1745        HRESULT Lock()
1746        {
1747                _ATLTRY
1748                {
1749                        CONTEXT ThreadContext;
1750                        if(!GetCurrentThreadContext(&ThreadContext))
1751                                ThreadContext.ContextFlags = 0;
1752                        CObjectPtr<CTimedEventDaemon> pTimedEventDaemon = CRoCriticalSections::GetTimedEventDaemon();
1753                        static const ULONG g_nTimeout = 5 * 1000; // 5 seconds
1754                        CLockContext LockContext(this, ThreadContext, g_nTimeout);
1755                        UINT_PTR nEvent;
1756                        __C(pTimedEventDaemon->SetEvent(g_nTimeout, 0, LockTimeout, (DWORD_PTR) &LockContext, TIME_PERIODIC, &nEvent));
1757                        if(!VerifyCriticalSectionLocked(*this))
1758                        {
1759//                              for(SIZE_T nInnerIndex = 0; nInnerIndex < m_Section.m_InnerCriticalSectionArray.GetCount(); nInnerIndex++)
1760//                                      __A(m_Section.m_InnerCriticalSectionArray[nInnerIndex]->VerifyNotLocked());
1761                        }
1762                        __C(__super::Lock());
1763                        __C(pTimedEventDaemon->KillEvent(nEvent));
1764                        const CInterlockedT<LONG>& nRecursionCount = reinterpret_cast<CInterlockedT<LONG>&>(m_sec.RecursionCount);
1765                        if(nRecursionCount == (LONG) 1) // First lock
1766                        {
1767                                CComCritSecLock<CComAutoCriticalSection> GlobalLock(g_CriticalSection);
1768                                m_nLockThreadIdentifier = GetCurrentThreadId();
1769                                m_LockThreadContext = ThreadContext;
1770                        }
1771                        if(LockContext.m_nTimeoutTime)
1772                                ATLCORETRACE1(atlTraceGeneral, 2, _T("Critical section 0x%08X deadlock suspicion: entered in thread %d after timeout %d ms\n"), this, GetCurrentThreadId(), LockContext.m_nTimeoutTime);
1773                }
1774                _ATLCATCH(Exception)
1775                {
1776                        _Z_ATLEXCEPTION(Exception);
1777                        return Exception;
1778                }
1779                return S_OK;
1780        }
1781        HRESULT Unlock()
1782        {
1783                {
1784                        CComCritSecLock<CComAutoCriticalSection> GlobalLock(g_CriticalSection);
1785                        _A(VerifyCriticalSectionLocked(*this));
1786                        const CInterlockedT<LONG>& nRecursionCount = reinterpret_cast<CInterlockedT<LONG>&>(m_sec.RecursionCount);
1787                        if(nRecursionCount == (LONG) 1) // Last lock
1788                        {
1789                                m_nLockThreadIdentifier = 0;
1790                                m_LockThreadContext.ContextFlags = 0; //ZeroMemory(&m_LockThreadContext, sizeof m_LockThreadContext);
1791                        }
1792                }
1793                return __super::Unlock();
1794        }
1795        VOID AddInnerCriticalSection(CRoCriticalSection& Section)
1796        {
1797                // TODO: CRoCriticalSection::AddInnerCriticalSection
1798        }
1799};
1800
1801__declspec(selectany) CComAutoCriticalSection CRoCriticalSection::g_CriticalSection;
1802
1803#if !defined(_WIN64) && defined(_WINDLL)
1804        #if !defined(_DEBUG) && _TRACE
1805
1806                #define AVAILABILITY_INTERNALWRITEMINIDUMP
1807
1808                //#pragma comment(linker, "/EXPORT:WriteMiniDump=_WriteMiniDump@16,PRIVATE")
1809
1810                //extern "C" // __declspec(dllexport)
1811                ATLINLINE HRESULT STDMETHODCALLTYPE InternalWriteMiniDump(HWND hParentWindow, HINSTANCE hInstance, LPSTR pszCommandLine, INT nShowCommand)
1812                {
1813                        _ATLTRY
1814                        {
1815                                hParentWindow; hInstance; nShowCommand;
1816                                //MessageBox(GetActiveWindow(), AtlFormatString(_T("pszCommandLine \"%hs\""), pszCommandLine), _T("Debug"), MB_ICONWARNING | MB_OK);
1817                                CRoArrayT<CString> Array;
1818                                _StringHelper::GetCommaSeparatedItems(CA2CT(pszCommandLine), Array);
1819                                __D(Array.GetCount() >= 4, E_UNNAMED);
1820                                INT nProcessIdentifier;
1821                                __D(StrToIntEx(Array[0], STIF_SUPPORT_HEX, &nProcessIdentifier), E_UNNAMED);
1822                                CHandle Process;
1823                                Process.Attach(OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, nProcessIdentifier));
1824                                __E(Process);
1825                                TCHAR pszDirectory[MAX_PATH] = { 0 };
1826                                if(IsWindowsVistaOrGreater())
1827                                {
1828                                        _W(SHGetSpecialFolderPath(NULL, pszDirectory, CSIDL_COMMON_APPDATA, TRUE));
1829                                } else
1830                                {
1831                                        _W(GetWindowsDirectory(pszDirectory, _countof(pszDirectory)));
1832                                        _W(PathStripToRoot(pszDirectory));
1833                                }
1834                                CPath sPath;
1835                                sPath.Combine(pszDirectory, AtlFormatString(_T("%s-%d-%s-%s-%d.dmp"), 
1836                                        FindFileName(Array[1]), // Process Host Module Path
1837                                        nProcessIdentifier, 
1838                                        FindFileName(Array[2]), // Module Path
1839                                        FindFileName(Array[3]), // Comment
1840                                        GetCurrentProcessId(), 
1841                                        0));
1842                                CAtlFile File;
1843                                __C(File.Create(sPath, GENERIC_WRITE, FILE_SHARE_READ, CREATE_ALWAYS));
1844                                MINIDUMP_TYPE Type = MiniDumpNormal;
1845                                #if defined(REGISTRY_ROOT)
1846                                        DWORD nType = (DWORD) Type;
1847                                        if(_RegKeyHelper::QueryIntegerValueEx(HKEY_CURRENT_USER, REGISTRY_ROOT _T("\\Debug"), _T("MiniDump Type"), nType) || 
1848                                                _RegKeyHelper::QueryIntegerValueEx(HKEY_LOCAL_MACHINE, REGISTRY_ROOT _T("\\Debug"), _T("MiniDump Type"), nType))
1849                                                Type = (MINIDUMP_TYPE) nType;
1850                                #endif // defined(REGISTRY_ROOT)
1851                                __E(MiniDumpWriteDump(Process, nProcessIdentifier, File, Type, NULL, NULL, NULL));
1852                        }
1853                        _ATLCATCH(Exception)
1854                        {
1855                                _C(Exception);
1856                        }
1857                        return S_OK;
1858                }
1859
1860        #endif // !defined(_DEBUG) && _TRACE
1861#endif // !defined(_WIN64) && defined(_WINDLL)
1862
1863#pragma optimize("", on)
1864#pragma warning(default: 4748)
1865
1866#else
1867
1868typedef CComAutoCriticalSection CRoCriticalSection;
1869
1870#endif // defined(_DEBUG) || _TRACE
1871
1872typedef CComAutoCriticalSection CRoLightCriticalSection;
1873
1874#if TRUE
1875
1876template <typename CCriticalSection>
1877inline BOOL TryLock(CCriticalSection& CriticalSection);
1878
1879#if _WIN32_WINNT >= 0x0400
1880        template <>
1881        inline BOOL TryLock<CComCriticalSection>(CComCriticalSection& CriticalSection)
1882        {
1883                return TryEnterCriticalSection(&CriticalSection.m_sec);
1884        }
1885        template <>
1886        inline BOOL TryLock<CRoCriticalSection>(CRoCriticalSection& CriticalSection)
1887        {
1888                return TryEnterCriticalSection(&CriticalSection.m_sec);
1889        }
1890#endif // _WIN32_WINNT >= 0x0400
1891
1892template <typename CCriticalSection>
1893class CRoCriticalSectionLockT
1894{
1895private:
1896        CCriticalSection& m_CriticalSection;
1897        BOOL m_bLocked;
1898
1899        CRoCriticalSectionLockT(const CRoCriticalSectionLockT&);
1900        CRoCriticalSectionLockT& operator = (const CRoCriticalSectionLockT&);
1901
1902public:
1903// CRoCriticalSectionLockT
1904        CRoCriticalSectionLockT(CCriticalSection& CriticalSection, BOOL bInitialLock = TRUE) :
1905                m_CriticalSection(CriticalSection),
1906                m_bLocked(FALSE)
1907        {
1908                if(bInitialLock)
1909                        Lock();
1910        }
1911        ~CRoCriticalSectionLockT()
1912        {
1913                if(m_bLocked)
1914                        Unlock();
1915        }
1916        VOID Lock()
1917        {
1918                _A(!m_bLocked);
1919                _V(m_CriticalSection.Lock());
1920                m_bLocked = TRUE;
1921        }
1922        BOOL TryLock()
1923        {
1924                _A(!m_bLocked);
1925                if(!::TryLock(m_CriticalSection))
1926                        return FALSE;
1927                m_bLocked = TRUE;
1928                return TRUE;
1929        }
1930        VOID Unlock()
1931        {
1932                ATLASSUME(m_bLocked);
1933                m_CriticalSection.Unlock();
1934                m_bLocked = FALSE;
1935        }
1936        BOOL IsLocked() const
1937        {
1938                return m_bLocked;
1939        }
1940};
1941
1942typedef CRoCriticalSectionLockT<CRoCriticalSection> CRoCriticalSectionLock;
1943
1944#else
1945
1946typedef CComCritSecLock<CRoCriticalSection> CRoCriticalSectionLock;
1947
1948#endif
1949
1950typedef CComCritSecLock<CRoLightCriticalSection> CRoLightCriticalSectionLock;
1951
1952/////////////////////////////////////////////////////////////////////////////
1953// DeadlockCriticalSectionT
1954
1955template <typename _CriticalSection>
1956inline DWORD WINAPI DeadlockCriticalSectionThreadProcT(_CriticalSection* pCriticalSection)
1957{
1958        CComCritSecLock<_CriticalSection> Lock(*pCriticalSection);
1959        _A(FALSE);
1960        return 0;
1961}
1962
1963template <typename _CriticalSection>
1964inline VOID DeadlockCriticalSectionT(_CriticalSection& CriticalSection)
1965{
1966        CComCritSecLock<_CriticalSection> Lock(CriticalSection);
1967        // WARN: GetThreadId is WinVista+, so we have to use CreateThreadT instead of AtlCreateThread
1968        DWORD nThreadIdentifier;
1969        CHandle ThreadHandle;
1970        ThreadHandle.Attach(CreateThreadT<_CriticalSection>(NULL, 0, DeadlockCriticalSectionThreadProcT<_CriticalSection>, &CriticalSection, 0, &nThreadIdentifier));
1971        ATLTRACE(atlTraceGeneral, 1, _T("Deadlocked in threads %d and %d (spawned)\n"), GetCurrentThreadId(), nThreadIdentifier);
1972        WaitForSingleObject(ThreadHandle, INFINITE);
1973        _A(FALSE);
1974}
1975
1976/////////////////////////////////////////////////////////////////////////////
1977// CComCritSecUnlock
1978
1979template <typename CCriticalSection>
1980class CComCritSecUnlock
1981{
1982private:
1983        CCriticalSection& m_CriticalSection;
1984        BOOL m_bUnlocked;
1985
1986        CComCritSecUnlock(const CComCritSecUnlock&);
1987        CComCritSecUnlock& operator = (const CComCritSecUnlock&);
1988
1989public:
1990// CComCritSecUnlock
1991        CComCritSecUnlock(CCriticalSection& CriticalSection, BOOL bInitialUnlock = TRUE) :
1992                m_CriticalSection(CriticalSection),
1993                m_bUnlocked(FALSE)
1994        {
1995                if(bInitialUnlock)
1996                        Unlock();
1997        }
1998        ~CComCritSecUnlock()
1999        {
2000                if(m_bUnlocked)
2001                        Lock();
2002        }
2003        VOID Unlock()
2004        {
2005                _A(!m_bUnlocked);
2006                _V(m_CriticalSection.Unlock());
2007                m_bUnlocked = TRUE;
2008        }
2009        VOID Lock()
2010        {
2011                _A(m_bUnlocked);
2012                m_CriticalSection.Lock();
2013                m_bUnlocked = FALSE;
2014        }
2015        BOOL TryLock()
2016        {
2017                _A(m_bUnlocked);
2018                if(!::TryLock(m_CriticalSection))
2019                        return FALSE;
2020                m_bUnlocked = FALSE;
2021                return TRUE;
2022        }
2023        BOOL IsLocked() const
2024        {
2025                return m_bLocked;
2026        }
2027};
2028
2029typedef CComCritSecUnlock<CRoCriticalSection> CRoCriticalSectionUnlock;
2030
2031// TODO: Condition Variables and One-Time Initialization
2032
2033////////////////////////////////////////////////////////////
2034// CApiComReleaseReaderWriterLock
2035//
2036// NOTE: Requires Windows Vista or Windows Server 2008
2037
2038#if _WIN32_WINNT >= 0x0600
2039
2040class CApiComReleaseReaderWriterLock
2041{
2042protected:
2043        SRWLOCK m_Lock;
2044
2045public:
2046// CApiComReleaseReaderWriterLock
2047        CApiComReleaseReaderWriterLock()
2048        {
2049                memset(&m_Lock, 0, sizeof m_Lock);
2050        }
2051        ~CApiComReleaseReaderWriterLock()
2052        {
2053        }
2054        VOID Initialize()
2055        {
2056                InitializeSRWLock(&m_Lock);
2057        }
2058        VOID Terminate()
2059        {
2060        }
2061        BOOL VerifyAcquiredExclusive() const
2062        {
2063                return TRUE; // No way to verify
2064        }
2065        VOID AcquireExclusive()
2066        {
2067                AcquireSRWLockExclusive(&m_Lock);
2068        }
2069        #if _WIN32_WINNT >= _WIN32_WINNT_WIN7
2070                BOOLEAN TryAcquireExclusive()
2071        {
2072                return TryAcquireSRWLockExclusive(&m_Lock);
2073        }
2074        #endif // _WIN32_WINNT >= _WIN32_WINNT_WIN7
2075        VOID ReleaseExclusive()
2076        {
2077                ReleaseSRWLockExclusive(&m_Lock);
2078        }
2079        BOOL VerifyAcquiredShared() const
2080        {
2081                return TRUE; // No way to verify
2082        }
2083        VOID AcquireShared()
2084        {
2085                AcquireSRWLockShared(&m_Lock);
2086        }
2087        #if _WIN32_WINNT >= _WIN32_WINNT_WIN7
2088                BOOLEAN TryAcquireShared()
2089        {
2090                return TryAcquireSRWLockShared(&m_Lock);
2091        }
2092        #endif // _WIN32_WINNT >= _WIN32_WINNT_WIN7
2093        VOID ReleaseShared()
2094        {
2095                ReleaseSRWLockShared(&m_Lock);
2096        }
2097};
2098
2099#endif // _WIN32_WINNT >= 0x0600
2100
2101////////////////////////////////////////////////////////////
2102// CNativeComReleaseReaderWriterLock
2103
2104template <UINT t_nDefaultSpinCount = 1>
2105class CNativeComReleaseReaderWriterLockT
2106{
2107protected:
2108        CInterlockedLong m_nLock;
2109
2110public:
2111// CNativeComReleaseReaderWriterLockT
2112        CNativeComReleaseReaderWriterLockT() :
2113                m_nLock(0)
2114        {
2115        }
2116        ~CNativeComReleaseReaderWriterLockT()
2117        {
2118        }
2119        VOID Initialize()
2120        {
2121                m_nLock = 0;
2122        }
2123        VOID Terminate()
2124        {
2125        }
2126        BOOL VerifyAcquiredExclusive() const
2127        {
2128                return TRUE; // No way to reliably verify
2129        }
2130        VOID AcquireExclusiveNoSpin()
2131        {
2132                for(; ; )
2133                {
2134                        if(m_nLock.ExchangeAdd(-0x10000) == 0)
2135                                break;
2136                        m_nLock.ExchangeAdd(+0x10000);
2137                        SwitchToThread();
2138                }
2139        }
2140        VOID AcquireExclusiveSpin(UINT nSpinCount)
2141        {
2142                for(UINT nSpinIndex = 0; ; nSpinIndex++)
2143                {
2144                        if(m_nLock.ExchangeAdd(-0x10000) == 0)
2145                                break;
2146                        m_nLock.ExchangeAdd(+0x10000);
2147                        if(nSpinIndex < nSpinCount)
2148                                continue;
2149                        SwitchToThread();
2150                        nSpinIndex = 0;
2151                }
2152        }
2153        VOID AcquireExclusive()
2154        {
2155                (t_nDefaultSpinCount > 0) ? AcquireExclusiveSpin(t_nDefaultSpinCount) : AcquireExclusiveNoSpin();
2156        }
2157        BOOLEAN TryAcquireExclusive()
2158        {
2159                if(m_nLock.ExchangeAdd(-0x10000) == 0)
2160                        return TRUE;
2161                m_nLock.ExchangeAdd(+0x10000);
2162                return FALSE;
2163        }
2164        VOID ReleaseExclusive()
2165        {
2166                _A(m_nLock < -0x10000 / 2);
2167                m_nLock.ExchangeAdd(+0x10000);
2168        }
2169        BOOL VerifyAcquiredShared() const
2170        {
2171                return TRUE; // No way to reliably verify
2172        }
2173        VOID AcquireSharedNoSpin()
2174        {
2175                for(; ; )
2176                {
2177                        if(m_nLock.Increment() > 0)
2178                                break;
2179                        m_nLock.Decrement();
2180                        SwitchToThread();
2181                }
2182        }
2183        VOID AcquireSharedSpin(UINT nSpinCount)
2184        {
2185                for(UINT nSpinIndex = 0; ; nSpinIndex++)
2186                {
2187                        if(m_nLock.Increment() > 0)
2188                                break;
2189                        m_nLock.Decrement();
2190                        if(nSpinIndex < nSpinCount)
2191                                continue;
2192                        SwitchToThread();
2193                        nSpinIndex = 0;
2194                }
2195        }
2196        VOID AcquireShared()
2197        {
2198                (t_nDefaultSpinCount > 0) ? AcquireSharedSpin(t_nDefaultSpinCount) : AcquireSharedNoSpin();
2199        }
2200        BOOLEAN TryAcquireShared()
2201        {
2202                if(m_nLock.Increment() > 0)
2203                        return TRUE;
2204                m_nLock.Decrement();
2205                return FALSE;
2206        }
2207        VOID ReleaseShared()
2208        {
2209                m_nLock.Decrement();
2210        }
2211};
2212
2213typedef CNativeComReleaseReaderWriterLockT<> CNativeComReleaseReaderWriterLock;
2214
2215////////////////////////////////////////////////////////////
2216// CComReleaseReaderWriterLock, CComDebugReaderWriterLock, CRoReaderWriterLock
2217
2218//typedef CApiComReleaseReaderWriterLock CComReleaseReaderWriterLock;
2219typedef CNativeComReleaseReaderWriterLock CComReleaseReaderWriterLock;
2220
2221#if defined(_DEBUG)
2222
2223class CComDebugReaderWriterLock :
2224        private CComReleaseReaderWriterLock
2225{
2226private:
2227
2228        ////////////////////////////////////////////////////////
2229        // CAcquirement
2230
2231        class CAcquirement
2232        {
2233        public:
2234                DWORD m_nThreadIdentifier;
2235                BOOL m_bExclusive;
2236
2237        public:
2238        // CAcquirement
2239                static BOOL IsEqualThreadIdentifier(const CAcquirement& Acquirement, DWORD nThreadIdentifier)
2240                {
2241                        return Acquirement.m_nThreadIdentifier == nThreadIdentifier;
2242                }
2243                CAcquirement()
2244                {
2245                }
2246                CAcquirement(DWORD nThreadIdentifier, BOOL bExclusive) :
2247                        m_nThreadIdentifier(nThreadIdentifier),
2248                        m_bExclusive(bExclusive)
2249                {
2250                }
2251        };
2252
2253        ////////////////////////////////////////////////////////
2254        // CAcquirementList
2255
2256        class CAcquirementList :
2257                private CRoListT<CAcquirement>
2258        {
2259        private:
2260                mutable CComReleaseReaderWriterLock m_DataReaderWriterLock;
2261
2262        public:
2263        // CAcquirementList
2264                BOOL IsEmpty() const
2265                {
2266                        m_DataReaderWriterLock.AcquireShared();
2267                        const BOOL bResult = __super::IsEmpty();
2268                        m_DataReaderWriterLock.ReleaseShared();
2269                        return bResult;
2270                }
2271                BOOL Find(DWORD nThreadIdentifier = GetCurrentThreadId()) const
2272                {
2273                        POSITION Position = NULL;
2274                        m_DataReaderWriterLock.AcquireShared();
2275                        __super::FindFirstThatT(&CAcquirement::IsEqualThreadIdentifier, nThreadIdentifier, &Position);
2276                        m_DataReaderWriterLock.ReleaseShared();
2277                        return Position != NULL;
2278                }
2279                BOOL Find(BOOL& bExclusive, DWORD nThreadIdentifier = GetCurrentThreadId()) const
2280                {
2281                        POSITION Position = NULL;
2282                        m_DataReaderWriterLock.AcquireShared();
2283                        __super::FindFirstThatT(&CAcquirement::IsEqualThreadIdentifier, nThreadIdentifier, &Position);
2284                        if(Position)
2285                                bExclusive = GetAt(Position).m_bExclusive;
2286                        m_DataReaderWriterLock.ReleaseShared();
2287                        return Position != NULL;
2288                }
2289                VOID Add(BOOL bExclusive, DWORD nThreadIdentifier = GetCurrentThreadId())
2290                {
2291                        m_DataReaderWriterLock.AcquireExclusive();
2292                        __super::AddTail(CAcquirement(nThreadIdentifier, bExclusive));
2293                        m_DataReaderWriterLock.ReleaseExclusive();
2294                }
2295                BOOL RemoveLast(DWORD nThreadIdentifier = GetCurrentThreadId())
2296                {
2297                        POSITION Position;
2298                        m_DataReaderWriterLock.AcquireExclusive();
2299                        if(__super::FindLastThatT(&CAcquirement::IsEqualThreadIdentifier, nThreadIdentifier, &Position))
2300                                __super::RemoveAt(Position);
2301                        m_DataReaderWriterLock.ReleaseExclusive();
2302                        return Position != NULL;
2303                }
2304        };
2305
2306protected:
2307        CAcquirementList m_AcquirementList;
2308
2309public:
2310// CComDebugReaderWriterLock
2311        CComDebugReaderWriterLock()
2312        {
2313        }
2314        ~CComDebugReaderWriterLock()
2315        {
2316        }
2317        VOID Initialize()
2318        {
2319                __super::Initialize();
2320                _A(m_AcquirementList.IsEmpty());
2321        }
2322        VOID Terminate()
2323        {
2324                _A(m_AcquirementList.IsEmpty());
2325        }
2326        BOOL VerifyAcquiredExclusive() const
2327        {
2328                BOOL bExclusive;
2329                if(!m_AcquirementList.Find(bExclusive))
2330                        return FALSE;
2331                return bExclusive;
2332        }
2333        VOID AcquireExclusive()
2334        {
2335                _A(!m_AcquirementList.Find());
2336                __super::AcquireExclusive();
2337                m_AcquirementList.Add(TRUE);
2338        }
2339        BOOLEAN TryAcquireExclusive()
2340        {
2341                _A(!m_AcquirementList.Find());
2342                if(!__super::TryAcquireExclusive())
2343                        return FALSE;
2344                m_AcquirementList.Add(TRUE);
2345                return TRUE;
2346        }
2347        VOID ReleaseExclusive()
2348        {
2349                _W(m_AcquirementList.RemoveLast());
2350                __super::ReleaseExclusive();
2351                _A(!m_AcquirementList.Find());
2352        }
2353        BOOL VerifyAcquiredShared() const
2354        {
2355                BOOL bExclusive;
2356                if(!m_AcquirementList.Find(bExclusive))
2357                        return FALSE;
2358                return !bExclusive;
2359        }
2360        VOID AcquireShared()
2361        {
2362                _A(!m_AcquirementList.Find());
2363                __super::AcquireShared();
2364                m_AcquirementList.Add(FALSE);
2365        }
2366        BOOLEAN TryAcquireShared()
2367        {
2368                _A(!m_AcquirementList.Find());
2369                if(!__super::TryAcquireShared())
2370                        return FALSE;
2371                m_AcquirementList.Add(FALSE);
2372                return TRUE;
2373        }
2374        VOID ReleaseShared()
2375        {
2376                _W(m_AcquirementList.RemoveLast());
2377                __super::ReleaseShared();
2378                _A(!m_AcquirementList.Find());
2379        }
2380};
2381
2382#endif // defined(_DEBUG)
2383
2384#if defined(_DEBUG)
2385typedef CComDebugReaderWriterLock CComReaderWriterLock;
2386#else
2387typedef CComReleaseReaderWriterLock CComReaderWriterLock;
2388#endif // defined(_DEBUG)
2389
2390class CComAutoReaderWriterLock : 
2391        public CComReaderWriterLock
2392{
2393private:
2394        VOID Initialize();
2395        VOID Terminate();
2396
2397public:
2398// CComAutoReaderWriterLock
2399        CComAutoReaderWriterLock()
2400        {
2401                __super::Initialize();
2402        }
2403        ~CComAutoReaderWriterLock()
2404        {
2405                __super::Terminate();
2406        }
2407};
2408
2409// SUGG: Merge classes to have shared lock/unlock classes with traits/bases to lock shared/exclusive
2410
2411template <typename _ReaderWriterLock>
2412class CComReaderWriterLockExclusiveLockT
2413{
2414private:
2415        _ReaderWriterLock& m_Lock;
2416        BOOL m_bLocked;
2417
2418        CComReaderWriterLockExclusiveLockT(const CComReaderWriterLockExclusiveLockT&);
2419        CComReaderWriterLockExclusiveLockT& operator = (const CComReaderWriterLockExclusiveLockT&);
2420
2421public:
2422// CComReaderWriterLockExclusiveLockT
2423        CComReaderWriterLockExclusiveLockT(_ReaderWriterLock& ReaderWriterLock, BOOL bInitialLock = TRUE) :
2424                m_Lock(ReaderWriterLock),
2425                m_bLocked(FALSE)
2426        {
2427                if(bInitialLock)
2428                        Lock();
2429        }
2430        ~CComReaderWriterLockExclusiveLockT()
2431        {
2432                if(m_bLocked)
2433                        Unlock();
2434        }
2435        VOID Lock()
2436        {
2437                _A(!m_bLocked);
2438                m_Lock.AcquireExclusive();
2439                m_bLocked = TRUE;
2440        }
2441//#if _WIN32_WINNT >= _WIN32_WINNT_WIN7
2442        BOOL TryLock()
2443        {
2444                _A(!m_bLocked);
2445                if(!m_Lock.TryAcquireExclusive())
2446                        return FALSE;
2447                m_bLocked = TRUE;
2448                return TRUE;
2449        }
2450//#endif // _WIN32_WINNT >= _WIN32_WINNT_WIN7
2451        VOID Unlock()
2452        {
2453                ATLASSUME(m_bLocked);
2454                m_Lock.ReleaseExclusive();
2455                m_bLocked = FALSE;
2456        }
2457};
2458
2459template <typename _ReaderWriterLock>
2460class CComReaderWriterLockExclusiveUnlockT
2461{
2462private:
2463        _ReaderWriterLock& m_Lock;
2464        BOOL m_bUnlocked;
2465
2466        CComReaderWriterLockExclusiveUnlockT(const CComReaderWriterLockExclusiveUnlockT&);
2467        CComReaderWriterLockExclusiveUnlockT& operator = (const CComReaderWriterLockExclusiveUnlockT&);
2468
2469public:
2470// CComReaderWriterLockExclusiveUnlockT
2471        CComReaderWriterLockExclusiveUnlockT(_ReaderWriterLock& ReaderWriterLock, BOOL bInitialUnlock = TRUE) :
2472                m_Lock(ReaderWriterLock),
2473                m_bUnlocked(FALSE)
2474        {
2475                if(bInitialUnlock)
2476                        Unlock();
2477        }
2478        ~CComReaderWriterLockExclusiveUnlockT()
2479        {
2480                if(m_bUnlocked)
2481                        Lock();
2482        }
2483        VOID Unlock()
2484        {
2485                _A(!m_bUnlocked);
2486                m_Lock.ReleaseExclusive();
2487                m_bUnlocked = TRUE;
2488        }
2489        VOID Lock()
2490        {
2491                ATLASSUME(m_bUnlocked);
2492                m_Lock.AcquireExclusive();
2493                m_bUnlocked = FALSE;
2494        }
2495//#if _WIN32_WINNT >= _WIN32_WINNT_WIN7
2496        BOOL TryLock()
2497        {
2498                _A(!m_bLocked);
2499                if(!m_Lock.TryAcquireExclusive())
2500                        return FALSE;
2501                m_bLocked = TRUE;
2502                return TRUE;
2503        }
2504//#endif // _WIN32_WINNT >= _WIN32_WINNT_WIN7
2505};
2506
2507template <typename _ReaderWriterLock>
2508class CComReaderWriterLockSharedLockT
2509{
2510private:
2511        _ReaderWriterLock& m_Lock;
2512        BOOL m_bLocked;
2513
2514        CComReaderWriterLockSharedLockT(const CComReaderWriterLockSharedLockT&);
2515        CComReaderWriterLockSharedLockT& operator = (const CComReaderWriterLockSharedLockT&);
2516
2517public:
2518// CComReaderWriterLockSharedLockT
2519        CComReaderWriterLockSharedLockT(_ReaderWriterLock& ReaderWriterLock, BOOL bInitialLock = TRUE) :
2520                m_Lock(ReaderWriterLock),
2521                m_bLocked(FALSE)
2522        {
2523                if(bInitialLock)
2524                        Lock();
2525        }
2526        ~CComReaderWriterLockSharedLockT()
2527        {
2528                if(m_bLocked)
2529                        Unlock();
2530        }
2531        VOID Lock()
2532        {
2533                _A(!m_bLocked);
2534                m_Lock.AcquireShared();
2535                m_bLocked = TRUE;
2536        }
2537//#if _WIN32_WINNT >= _WIN32_WINNT_WIN7
2538        BOOL TryLock()
2539        {
2540                _A(!m_bLocked);
2541                if(!m_Lock.TryAcquireShared())
2542                        return FALSE;
2543                m_bLocked = TRUE;
2544                return TRUE;
2545        }
2546//#endif // _WIN32_WINNT >= _WIN32_WINNT_WIN7
2547        VOID Unlock()
2548        {
2549                ATLASSUME(m_bLocked);
2550                m_Lock.ReleaseShared();
2551                m_bLocked = FALSE;
2552        }
2553};
2554
2555template <typename _ReaderWriterLock>
2556class CComReaderWriterLockSharedUnlockT
2557{
2558private:
2559        _ReaderWriterLock& m_Lock;
2560        BOOL m_bUnlocked;
2561
2562        CComReaderWriterLockSharedUnlockT(const CComReaderWriterLockSharedUnlockT&);
2563        CComReaderWriterLockSharedUnlockT& operator = (const CComReaderWriterLockSharedUnlockT&);
2564
2565public:
2566// CComReaderWriterLockSharedUnlockT
2567        CComReaderWriterLockSharedUnlockT(_ReaderWriterLock& ReaderWriterLock, BOOL bInitialUnlock = TRUE) :
2568                m_Lock(ReaderWriterLock),
2569                m_bUnlocked(FALSE)
2570        {
2571                if(bInitialUnlock)
2572                        Unlock();
2573        }
2574        ~CComReaderWriterLockSharedUnlockT()
2575        {
2576                if(m_bUnlocked)
2577                        Lock();
2578        }
2579        VOID Unlock()
2580        {
2581                _A(!m_bUnlocked);
2582                m_Lock.ReleaseShared();
2583                m_bUnlocked = TRUE;
2584        }
2585        VOID Lock()
2586        {
2587                ATLASSUME(m_bUnlocked);
2588                m_Lock.AcquireShared();
2589                m_bUnlocked = FALSE;
2590        }
2591//#if _WIN32_WINNT >= _WIN32_WINNT_WIN7
2592        BOOL TryLock()
2593        {
2594                _A(!m_bLocked);
2595                if(!m_Lock.TryAcquireShared())
2596                        return FALSE;
2597                m_bLocked = TRUE;
2598                return TRUE;
2599        }
2600//#endif // _WIN32_WINNT >= _WIN32_WINNT_WIN7
2601};
2602
2603// TODO: Deadlock-aware Debug/Trace versions
2604
2605//#if !defined(SRWLOCK_THROUGH_CRITICALSECTION)
2606//#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600
2607//#define SRWLOCK_THROUGH_CRITICALSECTION
2608//#endif
2609//#endif
2610
2611#if defined(SRWLOCK_THROUGH_CRITICALSECTION)
2612typedef CRoCriticalSection CRoReaderWriterLock;
2613typedef CRoCriticalSectionLock CRoReaderWriterLockExclusiveLock;
2614typedef CRoCriticalSectionUnlock CRoReaderWriterLockExclusiveUnlock;
2615typedef CRoCriticalSectionLock CRoReaderWriterLockSharedLock;
2616typedef CRoCriticalSectionUnlock CRoReaderWriterLockSharedUnlock;
2617#else
2618typedef CComAutoReaderWriterLock CRoReaderWriterLock;
2619typedef CComReaderWriterLockExclusiveLockT<CRoReaderWriterLock> CRoReaderWriterLockExclusiveLock;
2620typedef CComReaderWriterLockExclusiveUnlockT<CRoReaderWriterLock> CRoReaderWriterLockExclusiveUnlock;
2621typedef CComReaderWriterLockSharedLockT<CRoReaderWriterLock> CRoReaderWriterLockSharedLock;
2622typedef CComReaderWriterLockSharedUnlockT<CRoReaderWriterLock> CRoReaderWriterLockSharedUnlock;
2623#endif
2624
2625////////////////////////////////////////////////////////////
2626// CLocalObjectMap
2627
2628class CLocalObjectMap
2629{
2630private:
2631        _ATL_OBJMAP_ENTRY* m_pObjectMap;
2632        BOOL m_bRegistered;
2633
2634public:
2635// CLocalObjectMap
2636        CLocalObjectMap(_ATL_OBJMAP_ENTRY* pObjectMap) throw() :
2637                m_pObjectMap(pObjectMap),
2638                m_bRegistered(FALSE)
2639        {
2640                _A(m_pObjectMap);
2641        }
2642        CLocalObjectMap(_ATL_OBJMAP_ENTRY* pObjectMap, BOOL bRegister) :
2643                m_pObjectMap(pObjectMap),
2644                m_bRegistered(FALSE)
2645        {
2646                if(bRegister)
2647                        Register();
2648                _A(m_bRegistered == bRegister);
2649        }
2650        ~CLocalObjectMap() throw()
2651        {
2652                if(m_bRegistered)
2653                        _ATLTRY
2654                        {
2655                                Revoke();
2656                        }
2657                        _ATLCATCHALL()
2658                        {
2659                                _Z_EXCEPTION();
2660                        }
2661        }
2662        VOID Register()
2663        {
2664                _A(!m_bRegistered);
2665                SIZE_T nIndex = 0;
2666                _ATLTRY
2667                {
2668                        for(; m_pObjectMap[nIndex].pclsid; nIndex++)
2669                                __C(m_pObjectMap[nIndex].RegisterClassObject(CLSCTX_INPROC_SERVER, REGCLS_MULTIPLEUSE));
2670                }
2671                _ATLCATCHALL()
2672                {
2673                        for(nIndex--; nIndex + 1 > 0; nIndex--)
2674                                _V(m_pObjectMap[nIndex].RevokeClassObject());
2675                        _ATLRETHROW;
2676                }
2677                m_bRegistered = TRUE;
2678        }
2679        VOID Revoke()
2680        {
2681                _A(m_bRegistered);
2682                for(SIZE_T nIndex = 0; m_pObjectMap[nIndex].pclsid; nIndex++)
2683                        __C(m_pObjectMap[nIndex].RevokeClassObject());
2684                m_bRegistered = FALSE;
2685        }
2686};
2687
2688////////////////////////////////////////////////////////////
2689// CInProcessServerLibrary
2690
2691class CInProcessServerLibrary
2692{
2693private:
2694        HMODULE m_hModule;
2695
2696public:
2697// CInProcessServerLibrary
2698        CInProcessServerLibrary() throw() :
2699                m_hModule(NULL)
2700        {
2701        }
2702        CInProcessServerLibrary(HMODULE hModule) throw() :
2703                m_hModule(NULL)
2704        {
2705                Initialize(hModule);
2706        }
2707        CInProcessServerLibrary(LPCTSTR pszPath) :
2708                m_hModule(NULL)
2709        {
2710                Initialize(pszPath);
2711        }
2712        ~CInProcessServerLibrary() throw()
2713        {
2714                Terminate();
2715        }
2716        VOID Initialize(HMODULE hModule) throw()
2717        {
2718                Terminate();
2719                m_hModule = hModule;
2720        }
2721        static CPath PathFromModuleDirectoryAndName(LPCTSTR pszName, HMODULE hModule = _AtlBaseModule.GetModuleInstance())
2722        {
2723                TCHAR pszDirectory[MAX_PATH] = { 0 };
2724                _W(GetModuleFileName(hModule, pszDirectory, DIM(pszDirectory)));
2725                _W(ATLPath::RemoveFileSpec(pszDirectory));
2726                CPath sPath;
2727                sPath.Combine(pszDirectory, pszName);
2728                return sPath;
2729        }
2730        VOID Initialize(LPCTSTR pszPath)
2731        {
2732                Terminate();
2733                m_hModule = LoadLibrary(pszPath);
2734                __E(m_hModule);
2735        }
2736        BOOL TryInitialize(LPCTSTR pszPath) throw()
2737        {
2738                const HMODULE hModule = LoadLibrary(pszPath);
2739                if(!hModule)
2740                        return FALSE;
2741                Terminate();
2742                m_hModule = hModule;
2743                return TRUE;
2744        }
2745        VOID Terminate()
2746        {
2747                if(m_hModule)
2748                {
2749                        FreeLibrary(m_hModule);
2750                        m_hModule = NULL;
2751                }
2752        }
2753        HMODULE GetModule() const throw()
2754        {
2755                return m_hModule;
2756        }
2757        operator HMODULE () const throw()
2758        {
2759                return GetModule();
2760        }
2761        template <typename IObject>
2762        HRESULT CreateInstance(CComPtr<IObject>& pObject, const CLSID& ClassIdentifier, IUnknown* pOuterUnknown = NULL)
2763        {
2764                if(!m_hModule)
2765                        return HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
2766                typedef HRESULT (STDMETHODCALLTYPE *DLLGETCLASSOBJECT)(__in REFCLSID ClassIdentifier, __in REFIID InterfaceIdentifier, __out VOID** ppvObject);
2767                const DLLGETCLASSOBJECT pDllGetClassObject = (DLLGETCLASSOBJECT) GetProcAddress(m_hModule, "DllGetClassObject");
2768                if(!pDllGetClassObject)
2769                        return AtlHresultFromLastError();
2770                CComPtr<IClassFactory> pClassFactory;
2771                _C((pDllGetClassObject)(ClassIdentifier, __uuidof(IClassFactory), (VOID**) &pClassFactory));
2772                _A(pClassFactory);
2773                _C(pClassFactory->CreateInstance(pOuterUnknown, __uuidof(IObject), (VOID**) &pObject));
2774                return S_OK;
2775        }
2776};
2777
2778////////////////////////////////////////////////////////////
2779// CPrivateDispatchTypeInfoT
2780
2781template <typename T, typename IObject>
2782class ATL_NO_VTABLE CPrivateDispatchTypeInfoT
2783{
2784protected:
2785        typedef CPrivateDispatchTypeInfoT<T, IObject> CPrivateDispatchTypeInfo;
2786
2787public:
2788
2789        ////////////////////////////////////////////////////////
2790        // CObjectDispatch
2791
2792        class ATL_NO_VTABLE CObjectDispatch :
2793                public IDispatchImpl<IObject>
2794        {
2795        public:
2796        // CObjectDispatch
2797                typename IDispatchImpl<IObject>::_tihclass& GetTypeInfoHolder() throw()
2798                {
2799                        return _tih;
2800                }
2801        };
2802
2803protected:
2804        mutable CRoCriticalSection m_TypeCriticalSection;
2805        CComPtr<ITypeLib> m_pTypeLib;
2806
2807public:
2808// CPrivateDispatchTypeInfoT
2809        VOID LoadTypeInfo(INT nResourceIdentifier = 0)
2810        {
2811                TCHAR pszPath[MAX_PATH] = { 0 };
2812                _W(GetModuleFileName(_AtlBaseModule.GetModuleInstance(), pszPath, DIM(pszPath)));
2813                if(nResourceIdentifier)
2814                {
2815                        const SIZE_T nPathLength = _tcslen(pszPath);
2816                        _stprintf_s(pszPath + nPathLength, DIM(pszPath) - nPathLength, _T("\\%d"), nResourceIdentifier);
2817                }
2818                // SUGG: Put type library pointer on global collection for reuse
2819                CRoCriticalSectionLock TypeLock(m_TypeCriticalSection);
2820                CComPtr<ITypeLib> pTypeLib;
2821                if(!m_pTypeLib)
2822                {
2823                        __C(LoadTypeLib(CT2OLE(pszPath), &pTypeLib));
2824                        m_pTypeLib = pTypeLib;
2825                } else
2826                        pTypeLib = m_pTypeLib;
2827                CComPtr<ITypeInfo> pTypeInfo;
2828                __C(pTypeLib->GetTypeInfoOfGuid(__uuidof(IObject), &pTypeInfo));
2829                _A(pTypeInfo);
2830                IDispatchImpl<IObject>* pDispath = static_cast<IDispatchImpl<IObject>*>(static_cast<T*>(this));
2831                CComTypeInfoHolder& TypeInfoHolder = static_cast<CObjectDispatch*>(pDispath)->GetTypeInfoHolder();
2832                TypeInfoHolder.m_pInfo = pTypeInfo;
2833                TypeInfoHolder.LoadNameCache(pTypeInfo);
2834        }
2835};
2836
2837////////////////////////////////////////////////////////////
2838// CSupportErrorInfoBase
2839
2840INT_PTR AtlMessageBoxEx(HWND hParentWindow, ATL::_U_STRINGorID Text, ATL::_U_STRINGorID Caption, UINT nType) throw();
2841
2842class CSupportErrorInfoBase
2843{
2844public:
2845
2846        ////////////////////////////////////////////////////////
2847        // CErrorContext
2848
2849        class CErrorContext
2850        {
2851        public:
2852                CErrorContext* m_pPrevious;
2853
2854        public:
2855        // CErrorContext
2856                CErrorContext() :
2857                        m_pPrevious(NULL)
2858                {
2859                }
2860                virtual CString GetText() = 0;
2861        };
2862
2863        ////////////////////////////////////////////////////////
2864        // CLocalErrorInfo
2865        //
2866        // NOTE: Local COM method context to hold pending error information
2867
2868        class CLocalErrorInfo
2869        {
2870        private:
2871                static CRoListT<CLocalErrorInfo*>* g_pList;
2872                DWORD m_nThreadIdentifier;
2873                HRESULT m_nResult;
2874                CErrorContext* m_pContext;
2875                CComPtr<IErrorInfo> m_pErrorInfo;
2876
2877        public:
2878        // CLocalErrorInfo
2879                static CLocalErrorInfo* GetCurrent()
2880                {
2881                        const DWORD nThreadIdentifier = GetCurrentThreadId();
2882                        _A(_pAtlModule);
2883                        CComCritSecLock<CComCriticalSection> Lock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
2884                        if(g_pList)
2885                        {
2886                                for(POSITION Position = g_pList->GetTailPosition(); Position; g_pList->GetPrev(Position))
2887                                {
2888                                        CLocalErrorInfo* pLocalErrorInfo = g_pList->GetAt(Position);
2889                                        _A(pLocalErrorInfo);
2890                                        if(pLocalErrorInfo->m_nThreadIdentifier == nThreadIdentifier)
2891                                                return pLocalErrorInfo;
2892                                }
2893                        }
2894                        return NULL;
2895                }
2896                static CString GetCurrentDescription()
2897                {
2898                        CString sDescription;
2899                        CLocalErrorInfo* pLocalErrorInfo = GetCurrent();
2900                        if(pLocalErrorInfo)
2901                                GetErrorDescription(pLocalErrorInfo->m_pErrorInfo, sDescription);
2902                        return sDescription;
2903                }
2904                CLocalErrorInfo() :
2905                        m_nThreadIdentifier(GetCurrentThreadId()),
2906                        m_nResult(S_OK),
2907                        m_pContext(NULL)
2908                {
2909                        _ATLTRY
2910                        {
2911                                CComCritSecLock<CComCriticalSection> Lock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
2912                                if(!g_pList)
2913                                        g_pList = new CRoListT<CLocalErrorInfo*>();
2914                                _W(g_pList->AddTail(this));
2915                        }
2916                        _ATLCATCHALL()
2917                        {
2918                                _Z_EXCEPTION();
2919                        }
2920                        _V(SetErrorInfo(0, NULL));
2921                }
2922                ~CLocalErrorInfo()
2923                {
2924                        CComCritSecLock<CComCriticalSection> Lock(_pAtlModule->m_csStaticDataInitAndTypeInfo);
2925                        if(g_pList)
2926                        {
2927                                const POSITION Position = g_pList->Find(this);
2928                                if(Position)
2929                                        g_pList->RemoveAt(Position);
2930                                if(g_pList->IsEmpty())
2931                                {
2932                                        delete g_pList;
2933                                        g_pList = NULL;
2934                                }
2935                        }
2936                }
2937                VOID Initialize(HRESULT nResult)
2938                {
2939                        m_nResult = nResult;
2940                        m_pErrorInfo.Release();
2941                        _V(GetErrorInfo(0, &m_pErrorInfo));
2942                }
2943                HRESULT GetResult() const
2944                {
2945                        return m_nResult;
2946                }
2947                CErrorContext* GetContext()
2948                {
2949                        return m_pContext;
2950                }
2951                VOID AddContext(CErrorContext* pContext)
2952                {
2953                        _A(pContext);
2954                        _A(!pContext->m_pPrevious);
2955                        pContext->m_pPrevious = m_pContext;
2956                        m_pContext = pContext;
2957                }
2958                VOID RemoveContext(CErrorContext* pContext)
2959                {
2960                        _A(pContext);
2961                        _A(m_pContext == pContext);
2962                        m_pContext = pContext->m_pPrevious;
2963                }
2964                BOOL UpdateErrorInfo()
2965                {
2966                        if(m_pErrorInfo)
2967                        {
2968                                _V(SetErrorInfo(0, m_pErrorInfo));
2969                                return TRUE;
2970                        }
2971                        return FALSE;
2972                }
2973                BOOL UpdateErrorInfo(HRESULT nResult)
2974                {
2975                        if(nResult == m_nResult && m_pErrorInfo)
2976                        {
2977                                _V(SetErrorInfo(0, m_pErrorInfo));
2978                                return TRUE;
2979                        }
2980                        return FALSE;
2981                }
2982        };
2983
2984        ////////////////////////////////////////////////////////
2985        // CTextErrorContext
2986
2987        class CTextErrorContext :
2988                public CErrorContext
2989        {
2990        private:
2991                CLocalErrorInfo* m_pLocalErrorInfo;
2992                CString m_sText;
2993                #if _TRACE
2994                        BOOL m_bDestructorTrace;
2995                #endif // _TRACE
2996
2997                VOID SetLocalErrorInfo()
2998                {
2999                        m_pLocalErrorInfo = CLocalErrorInfo::GetCurrent();
3000                        if(m_pLocalErrorInfo)
3001                                m_pLocalErrorInfo->AddContext(this);
3002                }
3003
3004        public:
3005        // CTextErrorContext
3006                CTextErrorContext(BOOL bDestructorTrace = FALSE)
3007                {
3008                        bDestructorTrace;
3009                        #if _TRACE
3010                                m_bDestructorTrace = bDestructorTrace;
3011                        #endif // _TRACE
3012                        SetLocalErrorInfo();
3013                }
3014                CTextErrorContext(const CString& sText, BOOL bDestructorTrace = FALSE)
3015                {
3016                        bDestructorTrace;
3017                        m_sText = sText;
3018                        #if _TRACE
3019                                m_bDestructorTrace = bDestructorTrace;
3020                        #endif // _TRACE
3021                        SetLocalErrorInfo();
3022                }
3023                CTextErrorContext(const CString& sText, BOOL bDestructorTrace, LPCTSTR pszConstructorTraceText)
3024                {
3025                        bDestructorTrace; pszConstructorTraceText;
3026                        m_sText = sText;
3027                        #if _TRACE
3028                                m_bDestructorTrace = bDestructorTrace;
3029                                const BOOL bConstructorTrace = pszConstructorTraceText != NULL;
3030                                if(bConstructorTrace)
3031                                        _Z3(atlTraceException, 3, _T("Entering Context, %s, %s, 0x%p\n"), m_sText, CString(pszConstructorTraceText), this);
3032                        #endif // _TRACE
3033                        SetLocalErrorInfo();
3034                }
3035                ~CTextErrorContext()
3036                {
3037                        #if _TRACE
3038                                if(m_bDestructorTrace && !m_sText.IsEmpty())
3039                                        _Z2(atlTraceException, 2, _T("Leaving Context, %s, 0x%p\n"), m_sText, this);
3040                        #endif // _TRACE
3041                        Terminate();
3042                }
3043                VOID Terminate()
3044                {
3045                        if(m_pLocalErrorInfo)
3046                        {
3047                                m_pLocalErrorInfo->RemoveContext(this);
3048                                m_pLocalErrorInfo = NULL;
3049                        }
3050                }
3051                VOID SetText(const CString& sText)
3052                {
3053                        m_sText = sText;
3054                }
3055                VOID SetDestructorTrace(BOOL bDestructorTrace)
3056                {
3057                        #if _TRACE
3058                                m_bDestructorTrace = bDestructorTrace;
3059                        #endif // _TRACE
3060                }
3061
3062        // CErrorContext
3063                CString GetText()
3064                {
3065                        return m_sText;
3066                }
3067        };
3068
3069        ////////////////////////////////////////////////////////
3070        // CErrorT, CReportErrorTraits, CError
3071        //
3072        // NOTE: Custom HRESULT producing class to additionally to communicate to current CLocalErrorInfo instance, if available
3073
3074        template <typename T, typename CReportErrorTraits>
3075        class CErrorT
3076        {
3077        private:
3078                CLocalErrorInfo* m_pLocalErrorInfo;
3079                HRESULT m_nResult;
3080                CString m_sMessage;
3081
3082                VOID AppendContextText(CString& sText) const
3083                {
3084                        if(!m_pLocalErrorInfo)
3085                                return;
3086                        CErrorContext* pContext = m_pLocalErrorInfo->GetContext();
3087                        if(!pContext)
3088                                return;
3089                        CRoArrayT<CString> Array;
3090                        for(; pContext; pContext = pContext->m_pPrevious)
3091                        {
3092                                const CString sText = pContext->GetText();
3093                                if(!sText.IsEmpty())
3094                                        Array.InsertAt(0, sText);
3095                        }
3096                        if(Array.IsEmpty())
3097                                return;
3098                        const CString sContextText = _StringHelper::Join(Array, _T("; "));
3099                        if(!sText.IsEmpty())
3100                                sText += AtlFormatString(_T(" [%s]"), sContextText);
3101                        else
3102                                sText = sContextText;
3103                }
3104
3105        public:
3106        // CErrorT
3107                static LPCTSTR GetGenericFormat()
3108                {
3109                        return _T("Error 0x%08X");
3110                }
3111                static CString FormatResult(HRESULT nResult, LPCTSTR pszGenericFormat = NULL)
3112                {
3113                        CString sMessage = AtlFormatSystemMessage(nResult);
3114                        sMessage.TrimRight(_T("\t\n\r ."));
3115                        if(sMessage.IsEmpty() && pszGenericFormat)
3116                                sMessage = AtlFormatString(pszGenericFormat, nResult);
3117                        return sMessage;
3118                }
3119                static HRESULT SetErrorMessage(HRESULT nResult, LPCTSTR pszMessage)
3120                {
3121                        CString sMessage;
3122                        if(!pszMessage || !_tcslen(pszMessage))
3123                        {
3124                                sMessage = T::FormatResult(nResult, GetGenericFormat());
3125                                pszMessage = sMessage;
3126                        }
3127                        return CReportErrorTraits::ReportError(nResult, pszMessage);
3128                }
3129                static inline VOID Throw(HRESULT nResult, LPCTSTR pszMessage = NULL, INT nLine = 0)
3130                {
3131                        CString sText;
3132                        if(pszMessage)
3133                                sText = pszMessage;
3134                        CString sResultMessage = T::FormatResult(nResult, T::GetGenericFormat());
3135                        if(!sResultMessage.IsEmpty() && !sText.IsEmpty())
3136                                sText += _T(": ");
3137                        sText += sResultMessage;
3138                        if(nLine)
3139                                sText += AtlFormatString(_T(" #%d"), nLine);
3140                        AtlThrow(T(nResult, sText));
3141                }
3142                static inline VOID ThrowFailed(HRESULT nResult, LPCTSTR pszMessage = NULL, INT nLine = 0)
3143                {
3144                        if(SUCCEEDED(nResult))
3145                                return;
3146                        CString sMessage;
3147                        if(!pszMessage && GetErrorDescription(sMessage))
3148                                AtlThrow(T(nResult, sMessage));
3149                        Throw(nResult, pszMessage, nLine);
3150                }
3151                static inline VOID ThrowFalse(BOOL bValue, LPCTSTR pszMessage = NULL, HRESULT nResult = E_UNNAMED, INT nLine = 0)
3152                {
3153                        if(bValue)
3154                                return;
3155                        CString sMessage;
3156                        if(!pszMessage && GetErrorDescription(sMessage))
3157                                AtlThrow(T(nResult, sMessage));
3158                        Throw(nResult, pszMessage, nLine);
3159                }
3160                static inline VOID ThrowFalse(const VOID* pvValue, LPCTSTR pszMessage = NULL, HRESULT nResult = E_UNNAMED, INT nLine = 0)
3161                {
3162                        if(pvValue)
3163                                return;
3164                        CString sMessage;
3165                        if(!pszMessage && GetErrorDescription(sMessage))
3166                                AtlThrow(T(nResult, sMessage));
3167                        Throw(nResult, pszMessage, nLine);
3168                }
3169                CErrorT(HRESULT nResult, LPCTSTR pszMessage = NULL) :
3170                        m_pLocalErrorInfo(CLocalErrorInfo::GetCurrent()),
3171                        m_nResult(nResult),
3172                        m_sMessage(pszMessage)
3173                {
3174                }
3175                CErrorT(CLocalErrorInfo& LocalErrorInfo, HRESULT nResult, LPCTSTR pszMessage = NULL) :
3176                        m_pLocalErrorInfo(&LocalErrorInfo),
3177                        m_nResult(nResult),
3178                        m_sMessage(pszMessage)
3179                {
3180                }
3181                HRESULT GetResult() const
3182                {
3183                        return m_nResult;
3184                }
3185                operator HRESULT () const
3186                {
3187                        const T* pT = static_cast<const T*>(this);
3188                        HRESULT nResult;
3189                        if(m_pLocalErrorInfo)
3190                        {
3191                                CString sMessage = m_sMessage;
3192                                AppendContextText(sMessage);
3193                                nResult = pT->SetErrorMessage(m_nResult, sMessage);
3194                                m_pLocalErrorInfo->Initialize(nResult);
3195                        } else
3196                                nResult = pT->SetErrorMessage(m_nResult, m_sMessage);
3197                        return nResult;
3198                }
3199                static CString Concatenate(SIZE_T nCount, LPCTSTR pszSeparator, LPCTSTR pszFirstMessage, ...)
3200                {
3201                        _A(nCount > 0 && pszSeparator);
3202                        CString sMessage = pszFirstMessage;
3203                        va_list Arguments;
3204                        va_start(Arguments, pszFirstMessage);
3205                        for(SIZE_T nIndex = 1; nIndex < nCount; nIndex++)
3206                        {
3207                                LPCTSTR pszNextMessage = va_arg(Arguments, LPCTSTR);
3208                                if(!pszNextMessage || !*pszNextMessage)
3209                                        continue;
3210                                if(!sMessage.IsEmpty())
3211                                        sMessage.Append(pszSeparator);
3212                                sMessage.Append(pszNextMessage);
3213                        }
3214                        va_end(Arguments);
3215                        return sMessage;
3216                }
3217                static INT_PTR MessageBox(HWND hParentWindow, const CLocalErrorInfo& ErrorInfo, _U_STRINGorID Caption, UINT nType = MB_ICONERROR | MB_OK)
3218                {
3219                        CString sMessage;
3220                        const CString sGenericMessage = AtlFormatString(T::GetGenericFormat(), ErrorInfo.GetResult());
3221                        CString sDescription = ErrorInfo.GetCurrentDescription();
3222                        BOOL bAppendResult = TRUE;
3223                        if(sDescription.IsEmpty())
3224                        {
3225                                sMessage = T::FormatResult(ErrorInfo.GetResult());
3226                                if(sMessage.IsEmpty())
3227                                {
3228                                        sMessage = sGenericMessage;
3229                                        bAppendResult = FALSE;
3230                                }
3231                        } else
3232                        {
3233                                sMessage = sDescription;
3234                                if(sMessage.Compare(sGenericMessage) == 0)
3235                                        bAppendResult = FALSE;
3236                        }
3237                        if(bAppendResult)
3238                                sMessage.AppendFormat(_T(" (0x%08X)"), ErrorInfo.GetResult());
3239                        return AtlMessageBoxEx(hParentWindow, (LPCTSTR) sMessage, Caption, nType);
3240                }
3241        };
3242
3243        class CReportErrorTraits
3244        {
3245        public:
3246        // CReportErrorTraits
3247                static HRESULT ReportError(HRESULT nResult, LPCTSTR pszMessage)
3248                {
3249                        _A(pszMessage);
3250                        return AtlReportError(CLSID_NULL, pszMessage, 0, NULL, IID_NULL, nResult);
3251                }
3252        };
3253
3254        class CError :
3255                public CErrorT<CError, CReportErrorTraits>
3256        {
3257        public:
3258        // CError
3259                CError(HRESULT nResult, LPCTSTR pszMessage = NULL) :
3260                        CErrorT<CError, CReportErrorTraits>(nResult, pszMessage)
3261                {
3262                }
3263        };
3264
3265        ////////////////////////////////////////////////////////
3266        // CExceptionErrorInfo
3267        //
3268        // NOTE: Converts exception into HRESULT existing from COM method, updating error information
3269
3270        class CExceptionErrorInfo
3271        {
3272        protected:
3273                HRESULT m_nResult;
3274
3275        public:
3276        // CExceptionErrorInfo
3277                CExceptionErrorInfo()
3278                {
3279                }
3280                CExceptionErrorInfo(HRESULT nResult, CLocalErrorInfo& LocalErrorInfo)
3281                {
3282                        Initialize(nResult, LocalErrorInfo);
3283                }
3284                VOID Initialize(HRESULT nResult, CLocalErrorInfo& LocalErrorInfo)
3285                {
3286                        LocalErrorInfo.UpdateErrorInfo(nResult);
3287                        m_nResult = nResult;
3288                }
3289                operator HRESULT () const
3290                {
3291                        return m_nResult;
3292                }
3293        };
3294
3295public:
3296// CSupportErrorInfoBase
3297        static BOOL GetErrorInformation(CComPtr<IErrorInfo>& pErrorInfo)
3298        {
3299                _A(!pErrorInfo);
3300                GetErrorInfo(0, &pErrorInfo);
3301                return pErrorInfo != NULL;
3302        }
3303        static BOOL GetErrorDescription(IErrorInfo* pErrorInfo, CString& sDescription)
3304        {
3305                if(!pErrorInfo)
3306                        return FALSE;
3307                CComBSTR sDescriptionW;
3308                pErrorInfo->GetDescription(&sDescriptionW);
3309                sDescription = CString(sDescriptionW);
3310                return !sDescription.IsEmpty();
3311        }
3312        static BOOL GetErrorDescription(CString& sMessage)
3313        {
3314                CComPtr<IErrorInfo> pErrorInfo;
3315                if(!GetErrorInformation(pErrorInfo))
3316                        return FALSE;
3317                return GetErrorDescription(pErrorInfo, sMessage);
3318        }
3319};
3320
3321////////////////////////////////////////////////////////////
3322// CSimpleSupportErrorInfoT
3323
3324template <typename T, typename _Interface>
3325class ATL_NO_VTABLE CSimpleSupportErrorInfoT :
3326        public ISupportErrorInfoImpl<&__uuidof(_Interface)>,
3327        public CSupportErrorInfoBase
3328{
3329protected:
3330        typedef CSimpleSupportErrorInfoT<T, _Interface> CSimpleSupportErrorInfo;
3331
3332public:
3333
3334        ////////////////////////////////////////////////////////
3335        // CSupportErrorInfoReportErrorTraits, CErrorT, CError
3336
3337        class CSupportErrorInfoReportErrorTraits
3338        {
3339        public:
3340        // CSupportErrorInfoReportErrorTraits
3341                static HRESULT ReportError(HRESULT nResult, LPCTSTR pszMessage)
3342                {
3343                        _A(pszMessage);
3344                        return AtlReportError(T::GetObjectCLSID(), pszMessage, 0, NULL, __uuidof(_Interface), nResult);
3345                }
3346        };
3347
3348        template <typename T>
3349        class CErrorT :
3350                public CSupportErrorInfoBase::CErrorT<T, CSupportErrorInfoReportErrorTraits>
3351        {
3352        public:
3353        // CErrorT
3354                CErrorT(HRESULT nResult, LPCTSTR pszMessage = NULL) :
3355                        CSupportErrorInfoBase::CErrorT<T, CSupportErrorInfoReportErrorTraits>(nResult, pszMessage)
3356                {
3357                }
3358                CErrorT(CLocalErrorInfo& LocalErrorInfo, HRESULT nResult, LPCTSTR pszMessage = NULL) :
3359                        CSupportErrorInfoBase::CErrorT<T, CSupportErrorInfoReportErrorTraits>(LocalErrorInfo, nResult, pszMessage)
3360                {
3361                }
3362        };
3363
3364        class CError :
3365                public CErrorT<CError>
3366        {
3367        public:
3368        // CError
3369                CError(HRESULT nResult, LPCTSTR pszMessage = NULL) :
3370                        CErrorT<CError>(nResult, pszMessage)
3371                {
3372                }
3373        };
3374
3375public:
3376// CSimpleSupportErrorInfoT
3377        //static HRESULT SetErrorInfo(HRESULT nResult, LPCTSTR pszMessage)
3378        //{
3379        //      return CSupportErrorInfoReportErrorTraits::ReportError(nResult, pszMessage);
3380        //}
3381};
3382
3383__declspec(selectany) CRoListT<CSupportErrorInfoBase::CLocalErrorInfo*>* CSupportErrorInfoBase::CLocalErrorInfo::g_pList = NULL;
3384
3385//template <typename T, typename _Interface>
3386//__declspec(selectany) CRoListT<typename CSimpleSupportErrorInfoT<T, _Interface>::CLocalErrorInfo*>* CSimpleSupportErrorInfoT<T, _Interface>::CLocalErrorInfo::g_pList = NULL;
3387
3388////////////////////////////////////////////////////////////
3389// CMsAccurateFileTime
3390
3391class CMsAccurateFileTime
3392{
3393private:
3394
3395public:
3396// CMsAccurateFileTime
3397        static ULONGLONG IntegerFromFileTime(const FILETIME& FileTime) throw()
3398        {
3399                return ((ULONGLONG) FileTime.dwHighDateTime << 32) + FileTime.dwLowDateTime;
3400        }
3401        static ULONGLONG GetTime() throw()
3402        {
3403                FILETIME AnchorFileTime;
3404                GetSystemTimeAsFileTime(&AnchorFileTime);
3405                return IntegerFromFileTime(AnchorFileTime);
3406        }
3407};
3408
3409////////////////////////////////////////////////////////////
3410// CUsAccurateFileTime
3411
3412class CUsAccurateFileTime
3413{
3414private:
3415        static const ULONGLONG g_nFileTimeFrequency = 1000 * 10000; // 100 ns units
3416        static CUsAccurateFileTime g_Instance;
3417        mutable CRoReaderWriterLock m_DataReaderWriterLock;
3418        ULONGLONG m_nCurrentFrequency;
3419        ULONGLONG m_nAnchorCounter;
3420        ULONGLONG m_nAnchorFileTime;
3421
3422        static ULONGLONG IntegerFromFileTime(const FILETIME& FileTime) throw()
3423        {
3424                return CMsAccurateFileTime::IntegerFromFileTime(FileTime);
3425        }
3426        ULONGLONG InternalGetTime() throw()
3427        {
3428                static const ULONGLONG g_nSynchronizationInterval = 20 * 60; // 20 minutes
3429                const ULONGLONG nCounter = GetBaseCounter();
3430                ULONGLONG nRelativeCounter;
3431                ULONGLONG nUnsynchronizedFileTime;
3432                {
3433                        CRoReaderWriterLockSharedLock DataLock(m_DataReaderWriterLock);
3434                        nRelativeCounter = nCounter - m_nAnchorCounter;
3435                        nUnsynchronizedFileTime = m_nAnchorFileTime + (nRelativeCounter * g_nFileTimeFrequency) / m_nCurrentFrequency;
3436                        if(nRelativeCounter < g_nSynchronizationInterval * m_nFrequency)
3437                                return nUnsynchronizedFileTime;
3438                }
3439                FILETIME FileTime;
3440                GetSystemTimeAsFileTime(&FileTime);
3441                const ULONGLONG nFileTime = IntegerFromFileTime(FileTime);
3442                CRoReaderWriterLockExclusiveLock DataLock(m_DataReaderWriterLock);
3443                ULONGLONG nFrequency = (g_nFileTimeFrequency * nRelativeCounter) / (nFileTime - m_nAnchorFileTime);
3444                #pragma region Warn if currency frequency goes into unexpected range
3445                const UINT nRelativeFrequency = (UINT) ((nFrequency * 128) / m_nFrequency);
3446        if(nRelativeFrequency < (128 - 12) || nRelativeFrequency > (128 + 12))
3447        {
3448                        _Z2(atlTraceGeneral, 2, _T("Current frequency is out of reasonable range, m_nFrequency %I64d, m_nCurrentFrequency %I64d, nFrequency %I64d, nRelativeFrequency %d\n"), m_nFrequency, m_nCurrentFrequency, nFrequency, nRelativeFrequency);
3449            if(nFrequency < (128 - 16) * m_nFrequency / 128)
3450                nFrequency = (128 - 16) * m_nFrequency / 128;
3451            else if(nFrequency > (128 + 16) * m_nFrequency / 128)
3452                nFrequency = (128 + 16) * m_nFrequency / 128;
3453        }
3454                #pragma endregion
3455                m_nAnchorCounter = nCounter;
3456                m_nAnchorFileTime = nUnsynchronizedFileTime;
3457                m_nCurrentFrequency = nFrequency;
3458                return nUnsynchronizedFileTime;
3459        }
3460
3461public:
3462        const ULONGLONG m_nFrequency;
3463
3464public:
3465// CUsAccurateFileTime
3466        static ULONGLONG GetBaseFrequency() throw()
3467        {
3468                LARGE_INTEGER Frequency;
3469                _W(QueryPerformanceFrequency(&Frequency));
3470                return (ULONGLONG) Frequency.QuadPart;
3471        }
3472        static ULONGLONG GetBaseCounter() throw()
3473        {
3474                LARGE_INTEGER Counter;
3475                _W(QueryPerformanceCounter(&Counter));
3476                return (ULONGLONG) Counter.QuadPart;
3477        }
3478        static ULONGLONG GetTime() throw()
3479        {
3480                return g_Instance.InternalGetTime();
3481        }
3482        CUsAccurateFileTime() throw() :
3483                m_nFrequency(GetBaseFrequency())
3484        {
3485                _A(m_nFrequency > 0);
3486                m_nCurrentFrequency = m_nFrequency;
3487                m_nAnchorCounter = GetBaseCounter();
3488                FILETIME AnchorFileTime;
3489                GetSystemTimeAsFileTime(&AnchorFileTime);
3490                m_nAnchorFileTime = IntegerFromFileTime(AnchorFileTime);
3491        }
3492};
3493
3494__declspec(selectany) CUsAccurateFileTime CUsAccurateFileTime::g_Instance;
3495
Note: See TracBrowser for help on using the repository browser.