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

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