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

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