VirtualBox

source: vbox/trunk/include/VBox/com/microatl.h@ 62818

Last change on this file since 62818 was 62697, checked in by vboxsync, 9 years ago

HostDrivers: warnings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.9 KB
Line 
1/** @file
2 * ATL lookalike, just the tiny subset we actually need.
3 */
4
5/*
6 * Copyright (C) 2016 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26#ifndef ___VBox_com_microatl_h
27#define ___VBox_com_microatl_h
28
29#include <iprt/assert.h>
30#include <iprt/critsect.h>
31#include <iprt/err.h>
32
33
34namespace ATL
35{
36
37#define ATL_NO_VTABLE __declspec(novtable)
38
39class CAtlModule;
40__declspec(selectany) CAtlModule *_pAtlModule = NULL;
41
42class CComModule;
43__declspec(selectany) CComModule *_pModule = NULL;
44
45typedef HRESULT (WINAPI FNCREATEINSTANCE)(void *pv, REFIID riid, void **ppv);
46typedef FNCREATEINSTANCE *PFNCREATEINSTANCE;
47typedef HRESULT (WINAPI FNINTERFACEMAPHELPER)(void *pv, REFIID riid, void **ppv, DWORD_PTR dw);
48typedef FNINTERFACEMAPHELPER *PFNINTERFACEMAPHELPER;
49typedef void (__stdcall FNATLTERMFUNC)(void *pv);
50typedef FNATLTERMFUNC *PFNATLTERMFUNC;
51
52struct _ATL_TERMFUNC_ELEM
53{
54 PFNATLTERMFUNC pfn;
55 void *pv;
56 _ATL_TERMFUNC_ELEM *pNext;
57};
58
59struct _ATL_INTMAP_ENTRY
60{
61 const IID *piid; // interface ID
62 DWORD_PTR dw;
63 PFNINTERFACEMAPHELPER pFunc; // NULL: end of array, 1: offset based map entry, other: function pointer
64};
65
66#define COM_SIMPLEMAPENTRY ((ATL::PFNINTERFACEMAPHELPER)1)
67
68#define DECLARE_CLASSFACTORY_EX(c) typedef ATL::CComCreator<ATL::CComObjectNoLock<c> > _ClassFactoryCreatorClass;
69#define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory)
70#define DECLARE_CLASSFACTORY_SINGLETON(o) DECLARE_CLASSFACTORY_EX(ATL::CComClassFactorySingleton<o>)
71#define DECLARE_AGGREGATABLE(c) \
72public: \
73 typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<c> >, ATL::CComCreator<ATL::CComAggObject<c> > > _CreatorClass;
74#define DECLARE_NOT_AGGREGATABLE(c) \
75public: \
76 typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<c> >, ATL::CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass;
77
78#define DECLARE_PROTECT_FINAL_CONSTRUCT() \
79 void InternalFinalConstructAddRef() \
80 { \
81 InternalAddRef(); \
82 } \
83 void InternalFinalConstructRelease() \
84 { \
85 InternalRelease(); \
86 }
87
88#define BEGIN_COM_MAP(c) \
89public: \
90 typedef c _ComClass; \
91 HRESULT _InternalQueryInterface(REFIID iid, void **ppvObj) throw() \
92 { \
93 return InternalQueryInterface(this, _GetEntries(), iid, ppvObj); \
94 } \
95 const static ATL::_ATL_INTMAP_ENTRY *WINAPI _GetEntries() throw() \
96 { \
97 static const ATL::_ATL_INTMAP_ENTRY _aInterfaces[] = \
98 {
99
100#define COM_INTERFACE_ENTRY(c) \
101 { &__uuidof(c), (DWORD_PTR)(static_cast<c *>((_ComClass *)8))-8, COM_SIMPLEMAPENTRY },
102
103#define COM_INTERFACE_ENTRY2(c, c2) \
104 { &__uuidof(c), (DWORD_PTR)(static_cast<c *>(static_cast<c2 *>((_ComClass *)8)))-8, COM_SIMPLEMAPENTRY },
105
106#define COM_INTERFACE_ENTRY_AGGREGATE(iid, pUnk) \
107 { &iid, (DWORD_PTR)RT_OFFSETOF(_ComClass, pUnk), _Delegate},
108
109#define END_COM_MAP() \
110 { NULL, 0, NULL} \
111 }; \
112 return _aInterfaces; \
113 } \
114 virtual ULONG STDMETHODCALLTYPE AddRef(void) throw() = 0; \
115 virtual ULONG STDMETHODCALLTYPE Release(void) throw() = 0; \
116 STDMETHOD(QueryInterface)(REFIID, void **) throw() = 0;
117
118struct _ATL_OBJMAP_ENTRY
119{
120 const CLSID *pclsid;
121 PFNCREATEINSTANCE pfnGetClassObject;
122 PFNCREATEINSTANCE pfnCreateInstance;
123 IUnknown *pCF;
124 DWORD dwRegister;
125};
126
127#define BEGIN_OBJECT_MAP(o) static ATL::_ATL_OBJMAP_ENTRY o[] = {
128#define END_OBJECT_MAP() {NULL, NULL, NULL, NULL, 0}};
129#define OBJECT_ENTRY(clsid, c) {&clsid, c::_ClassFactoryCreatorClass::CreateInstance, c::_CreatorClass::CreateInstance, NULL, 0 },
130
131
132class CComCriticalSection
133{
134public:
135 CComCriticalSection() throw()
136 {
137 memset(&m_CritSect, 0, sizeof(m_CritSect));
138 }
139 ~CComCriticalSection()
140 {
141 }
142 HRESULT Lock() throw()
143 {
144 RTCritSectEnter(&m_CritSect);
145 return S_OK;
146 }
147 HRESULT Unlock() throw()
148 {
149 RTCritSectLeave(&m_CritSect);
150 return S_OK;
151 }
152 HRESULT Init() throw()
153 {
154 HRESULT hrc = S_OK;
155 if (RT_FAILURE(RTCritSectInit(&m_CritSect)))
156 hrc = E_FAIL;
157 return hrc;
158 }
159
160 HRESULT Term() throw()
161 {
162 RTCritSectDelete(&m_CritSect);
163 return S_OK;
164 }
165
166 RTCRITSECT m_CritSect;
167};
168
169template <class TLock> class CComCritSectLock
170{
171public:
172 CComCritSectLock(CComCriticalSection &cs, bool fInitialLock = true) :
173 m_cs(cs),
174 m_fLocked(false)
175 {
176 if (fInitialLock)
177 {
178 HRESULT hrc = Lock();
179 if (FAILED(hrc))
180 throw hrc;
181 }
182 }
183
184 ~CComCritSectLock() throw()
185 {
186 if (m_fLocked)
187 Unlock();
188 }
189
190 HRESULT Lock()
191 {
192 Assert(!m_fLocked);
193 HRESULT hrc = m_cs.Lock();
194 if (FAILED(hrc))
195 return hrc;
196 m_fLocked = true;
197 return S_OK;
198 }
199
200 void Unlock() throw()
201 {
202 Assert(m_fLocked);
203 m_cs.Unlock();
204 m_fLocked = false;
205 }
206
207
208private:
209 TLock &m_cs;
210 bool m_fLocked;
211
212 CComCritSectLock(const CComCritSectLock&) throw(); // Do not call.
213 CComCritSectLock &operator=(const CComCritSectLock &) throw(); // Do not call.
214};
215
216class CComFakeCriticalSection
217{
218public:
219 HRESULT Lock() throw()
220 {
221 return S_OK;
222 }
223 HRESULT Unlock() throw()
224 {
225 return S_OK;
226 }
227 HRESULT Init() throw()
228 {
229 return S_OK;
230 }
231 HRESULT Term() throw()
232 {
233 return S_OK;
234 }
235};
236
237class CComAutoCriticalSection : public CComCriticalSection
238{
239public:
240 CComAutoCriticalSection()
241 {
242 HRESULT hrc = CComCriticalSection::Init();
243 if (FAILED(hrc))
244 throw hrc;
245 }
246 ~CComAutoCriticalSection() throw()
247 {
248 CComCriticalSection::Term();
249 }
250private :
251 HRESULT Init() throw(); // Do not call.
252 HRESULT Term() throw(); // Do not call.
253};
254
255class CComAutoDeleteCriticalSection : public CComCriticalSection
256{
257public:
258 CComAutoDeleteCriticalSection(): m_fInit(false)
259 {
260 }
261
262 ~CComAutoDeleteCriticalSection() throw()
263 {
264 if (!m_fInit)
265 return;
266 m_fInit = false;
267 CComCriticalSection::Term();
268 }
269
270 HRESULT Init() throw()
271 {
272 Assert(!m_fInit);
273 HRESULT hrc = CComCriticalSection::Init();
274 if (SUCCEEDED(hrc))
275 m_fInit = true;
276 return hrc;
277 }
278
279 HRESULT Lock()
280 {
281 Assert(m_fInit);
282 return CComCriticalSection::Lock();
283 }
284
285 HRESULT Unlock()
286 {
287 Assert(m_fInit);
288 return CComCriticalSection::Unlock();
289 }
290
291private:
292 HRESULT Term() throw();
293 bool m_fInit;
294};
295
296
297class CComMultiThreadModelNoCS
298{
299public:
300 static ULONG WINAPI Increment(LONG *pL) throw()
301 {
302 return InterlockedIncrement(pL);
303 }
304 static ULONG WINAPI Decrement(LONG *pL) throw()
305 {
306 return InterlockedDecrement(pL);
307 }
308 typedef CComFakeCriticalSection AutoCriticalSection;
309 typedef CComFakeCriticalSection AutoDeleteCriticalSection;
310 typedef CComMultiThreadModelNoCS ThreadModelNoCS;
311};
312
313class CComMultiThreadModel
314{
315public:
316 static ULONG WINAPI Increment(LONG *pL) throw()
317 {
318 return InterlockedIncrement(pL);
319 }
320 static ULONG WINAPI Decrement(LONG *pL) throw()
321 {
322 return InterlockedDecrement(pL);
323 }
324 typedef CComAutoCriticalSection AutoCriticalSection;
325 typedef CComAutoDeleteCriticalSection AutoDeleteCriticalSection;
326 typedef CComMultiThreadModelNoCS ThreadModelNoCS;
327};
328
329class ATL_NO_VTABLE CAtlModule
330{
331public:
332 static GUID m_LibID;
333 CComCriticalSection m_csStaticDataInitAndTypeInfo;
334
335 CAtlModule() throw()
336 {
337 // One instance only per linking namespace!
338 AssertMsg(!_pAtlModule, ("CAtlModule: trying to create more than one instance per linking namespace\n"));
339
340 fInit = false;
341
342 m_cLock = 0;
343 m_pTermFuncs = NULL;
344 _pAtlModule = this;
345
346 if (FAILED(m_csStaticDataInitAndTypeInfo.Init()))
347 {
348 AssertMsgFailed(("CAtlModule: failed to init critsect\n"));
349 return;
350 }
351 fInit = true;
352 }
353
354 void Term() throw()
355 {
356 if (!fInit)
357 return;
358
359 // Call all term functions.
360 if (m_pTermFuncs)
361 {
362 _ATL_TERMFUNC_ELEM *p = m_pTermFuncs;
363 _ATL_TERMFUNC_ELEM *pNext;
364 while (p)
365 {
366 p->pfn(p->pv);
367 pNext = p->pNext;
368 delete p;
369 p = pNext;
370 }
371 m_pTermFuncs = NULL;
372 }
373 m_csStaticDataInitAndTypeInfo.Term();
374 fInit = false;
375 }
376
377 virtual ~CAtlModule() throw()
378 {
379 Term();
380 }
381
382 virtual LONG Lock() throw()
383 {
384 return CComMultiThreadModel::Increment(&m_cLock);
385 }
386
387 virtual LONG Unlock() throw()
388 {
389 return CComMultiThreadModel::Decrement(&m_cLock);
390 }
391
392 virtual LONG GetLockCount() throw()
393 {
394 return m_cLock;
395 }
396
397 HRESULT AddTermFunc(PFNATLTERMFUNC pfn, void *pv)
398 {
399 HRESULT hrc = S_OK;
400 _ATL_TERMFUNC_ELEM *pNew = NULL;
401 try
402 {
403 pNew = new _ATL_TERMFUNC_ELEM;
404 }
405 catch (...)
406 {
407 }
408 if (!pNew)
409 return E_OUTOFMEMORY;
410 pNew->pfn = pfn;
411 pNew->pv = pv;
412 CComCritSectLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo, false);
413 hrc = lock.Lock();
414 if (SUCCEEDED(hrc))
415 {
416 pNew->pNext = m_pTermFuncs;
417 m_pTermFuncs = pNew;
418 }
419 else
420 {
421 delete pNew;
422 AssertMsgFailed(("CComModule::AddTermFunc: failed to lock critsect\n"));
423 }
424 return hrc;
425 }
426
427protected:
428 bool fInit;
429 LONG m_cLock;
430 _ATL_TERMFUNC_ELEM *m_pTermFuncs;
431};
432
433__declspec(selectany) GUID CAtlModule::m_LibID = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} };
434
435struct _ATL_COM_MODULE
436{
437 HINSTANCE m_hInstTypeLib;
438 CComCriticalSection m_csObjMap;
439};
440
441#ifndef _delayimp_h
442extern "C" IMAGE_DOS_HEADER __ImageBase;
443#endif
444
445class CAtlComModule : public _ATL_COM_MODULE
446{
447public:
448 static bool m_fInitFailed;
449 CAtlComModule() throw()
450 {
451 m_hInstTypeLib = reinterpret_cast<HINSTANCE>(&__ImageBase);
452
453 if (FAILED(m_csObjMap.Init()))
454 {
455 AssertMsgFailed(("CAtlComModule: critsect init failed\n"));
456 m_fInitFailed = true;
457 return;
458 }
459 }
460
461 ~CAtlComModule()
462 {
463 Term();
464 }
465
466 void Term()
467 {
468 m_csObjMap.Term();
469 }
470};
471
472__declspec(selectany) bool CAtlComModule::m_fInitFailed = false;
473__declspec(selectany) CAtlComModule _AtlComModule;
474
475template <class T> class ATL_NO_VTABLE CAtlModuleT : public CAtlModule
476{
477public:
478 CAtlModuleT() throw()
479 {
480 T::InitLibId();
481 }
482
483 static void InitLibId() throw()
484 {
485 }
486};
487
488/**
489 *
490 * This class not _not_ be statically instantiated as a global variable! It may
491 * use VBoxRT before it's initialized otherwise, messing up logging and whatnot.
492 *
493 * When possible create the instance inside the TrustedMain() or main() as a
494 * stack variable. In DLLs use 'new' to instantiate it in the DllMain function.
495 */
496class CComModule : public CAtlModuleT<CComModule>
497{
498public:
499 CComModule()
500 {
501 // One instance only per linking namespace!
502 AssertMsg(!_pModule, ("CComModule: trying to create more than one instance per linking namespace\n"));
503 _pModule = this;
504 m_pObjMap = NULL;
505 }
506
507 ~CComModule()
508 {
509 }
510
511 _ATL_OBJMAP_ENTRY *m_pObjMap;
512 HRESULT Init(_ATL_OBJMAP_ENTRY *p, HINSTANCE h, const GUID *pLibID = NULL) throw()
513 {
514 RT_NOREF1(h);
515
516 if (pLibID)
517 m_LibID = *pLibID;
518
519 // Go over the object map to do some sanity checking, making things
520 // crash early if something is seriously busted.
521 _ATL_OBJMAP_ENTRY *pEntry;
522 if (p != (_ATL_OBJMAP_ENTRY *)-1)
523 {
524 m_pObjMap = p;
525 if (m_pObjMap)
526 {
527 pEntry = m_pObjMap;
528 while (pEntry->pclsid)
529 pEntry++;
530 }
531 }
532 return S_OK;
533 }
534
535 void Term() throw()
536 {
537 _ATL_OBJMAP_ENTRY *pEntry;
538 if (m_pObjMap)
539 {
540 pEntry = m_pObjMap;
541 while (pEntry->pclsid)
542 {
543 if (pEntry->pCF)
544 pEntry->pCF->Release();
545 pEntry->pCF = NULL;
546 pEntry++;
547 }
548 }
549
550 CAtlModuleT<CComModule>::Term();
551 }
552
553 HRESULT GetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) throw()
554 {
555 *ppv = NULL;
556 HRESULT hrc = S_OK;
557
558 if (m_pObjMap)
559 {
560 const _ATL_OBJMAP_ENTRY *pEntry = m_pObjMap;
561
562 while (pEntry->pclsid)
563 {
564 if (pEntry->pfnGetClassObject && rclsid == *pEntry->pclsid)
565 {
566 if (!pEntry->pCF)
567 {
568 CComCritSectLock<CComCriticalSection> lock(_AtlComModule.m_csObjMap, false);
569 hrc = lock.Lock();
570 if (FAILED(hrc))
571 {
572 AssertMsgFailed(("CComModule::GetClassObject: failed to lock critsect\n"));
573 break;
574 }
575
576 if (!pEntry->pCF)
577 {
578 hrc = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (void **)&pEntry->pCF);
579 }
580 }
581
582 if (pEntry->pCF)
583 {
584 hrc = pEntry->pCF->QueryInterface(riid, ppv);
585 }
586 break;
587 }
588 pEntry++;
589 }
590 }
591
592 return hrc;
593 }
594
595 // For EXE only: register all class factories with COM.
596 HRESULT RegisterClassObjects(DWORD dwClsContext, DWORD dwFlags) throw()
597 {
598 HRESULT hrc = S_OK;
599 _ATL_OBJMAP_ENTRY *pEntry;
600 if (m_pObjMap)
601 {
602 pEntry = m_pObjMap;
603 while (pEntry->pclsid && SUCCEEDED(hrc))
604 {
605 if (pEntry->pfnGetClassObject)
606 {
607 IUnknown *p;
608 hrc = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (void **)&p);
609 if (SUCCEEDED(hrc))
610 hrc = CoRegisterClassObject(*(pEntry->pclsid), p, dwClsContext, dwFlags, &pEntry->dwRegister);
611 if (p)
612 p->Release();
613 }
614 pEntry++;
615 }
616 }
617 return hrc;
618 }
619 // For EXE only: revoke all class factories with COM.
620 HRESULT RevokeClassObjects() throw()
621 {
622 HRESULT hrc = S_OK;
623 _ATL_OBJMAP_ENTRY *pEntry;
624 if (m_pObjMap != NULL)
625 {
626 pEntry = m_pObjMap;
627 while (pEntry->pclsid && SUCCEEDED(hrc))
628 {
629 if (pEntry->dwRegister)
630 hrc = CoRevokeClassObject(pEntry->dwRegister);
631 pEntry++;
632 }
633 }
634 return hrc;
635 }
636};
637
638
639template <class T> class CComCreator
640{
641public:
642 static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, void **ppv)
643 {
644 AssertReturn(ppv, E_POINTER);
645 *ppv = NULL;
646 HRESULT hrc = E_OUTOFMEMORY;
647 T *p = NULL;
648 try
649 {
650 p = new T(pv);
651 }
652 catch (...)
653 {
654 }
655 if (p)
656 {
657 p->SetVoid(pv);
658 p->InternalFinalConstructAddRef();
659 hrc = p->_AtlInitialConstruct();
660 if (SUCCEEDED(hrc))
661 hrc = p->FinalConstruct();
662 p->InternalFinalConstructRelease();
663 if (SUCCEEDED(hrc))
664 hrc = p->QueryInterface(riid, ppv);
665 if (FAILED(hrc))
666 delete p;
667 }
668 return hrc;
669 }
670};
671
672template <HRESULT hrc> class CComFailCreator
673{
674public:
675 static HRESULT WINAPI CreateInstance(void *, REFIID, void **ppv)
676 {
677 AssertReturn(ppv, E_POINTER);
678 *ppv = NULL;
679
680 return hrc;
681 }
682};
683
684template <class T1, class T2> class CComCreator2
685{
686public:
687 static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, void **ppv)
688 {
689 AssertReturn(ppv, E_POINTER);
690
691 return !pv ? T1::CreateInstance(NULL, riid, ppv) : T2::CreateInstance(pv, riid, ppv);
692 }
693};
694
695template <class Base> class CComObjectCached : public Base
696{
697public:
698 CComObjectCached(void * = NULL)
699 {
700 }
701 virtual ~CComObjectCached()
702 {
703 // Catch refcount screwups by setting refcount to -(LONG_MAX/2).
704 m_iRef = -(LONG_MAX/2);
705 FinalRelease();
706#ifdef _ATL_DEBUG_INTERFACES
707 _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
708#endif
709 }
710 STDMETHOD_(ULONG, AddRef)() throw()
711 {
712 // If you get errors about undefined InternalAddRef then Base does not
713 // derive from CComObjectRootEx.
714 ULONG l = InternalAddRef();
715 if (l == 2)
716 {
717 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
718 _pAtlModule->Lock();
719 }
720 return l;
721 }
722 STDMETHOD_(ULONG, Release)() throw()
723 {
724 // If you get errors about undefined InternalRelease then Base does not
725 // derive from CComObjectRootEx.
726 ULONG l = InternalRelease();
727 if (l == 0)
728 delete this;
729 else if (l == 1)
730 {
731 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
732 _pAtlModule->Unlock();
733 }
734 return l;
735 }
736 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw()
737 {
738 // If you get errors about undefined _InternalQueryInterface then
739 // double check BEGIN_COM_MAP in the class definition.
740 return _InternalQueryInterface(iid, ppvObj);
741 }
742 static HRESULT WINAPI CreateInstance(CComObjectCached<Base> **pp) throw()
743 {
744 AssertReturn(pp, E_POINTER);
745 *pp = NULL;
746
747 HRESULT hrc = E_OUTOFMEMORY;
748 CComObjectCached<Base> *p = NULL;
749 try
750 {
751 p = new CComObjectCached<Base>();
752 }
753 catch (...)
754 {
755 }
756 if (p)
757 {
758 p->SetVoid(NULL);
759 p->InternalFinalConstructAddRef();
760 hrc = p->_AtlInitialConstruct();
761 if (SUCCEEDED(hrc))
762 hrc = p->FinalConstruct();
763 p->InternalFinalConstructRelease();
764 if (FAILED(hrc))
765 delete p;
766 else
767 *pp = p;
768 }
769 return hrc;
770 }
771};
772
773template <class Base> class CComObjectNoLock : public Base
774{
775public:
776 CComObjectNoLock(void * = NULL)
777 {
778 }
779 virtual ~CComObjectNoLock()
780 {
781 // Catch refcount screwups by setting refcount to -(LONG_MAX/2).
782 m_iRef = -(LONG_MAX/2);
783 FinalRelease();
784 }
785 STDMETHOD_(ULONG, AddRef)() throw()
786 {
787 // If you get errors about undefined InternalAddRef then Base does not
788 // derive from CComObjectRootEx.
789 return InternalAddRef();
790 }
791 STDMETHOD_(ULONG, Release)() throw()
792 {
793 // If you get errors about undefined InternalRelease then Base does not
794 // derive from CComObjectRootEx.
795 ULONG l = InternalRelease();
796 if (l == 0)
797 delete this;
798 return l;
799 }
800 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw()
801 {
802 // If you get errors about undefined _InternalQueryInterface then
803 // double check BEGIN_COM_MAP in the class definition.
804 return _InternalQueryInterface(iid, ppvObj);
805 }
806};
807
808class CComTypeInfoHolder
809{
810 /** @todo implement type info caching, making stuff more efficient - would we benefit? */
811public:
812 const GUID *m_pGUID;
813 const GUID *m_pLibID;
814 WORD m_iMajor;
815 WORD m_iMinor;
816 ITypeInfo *m_pTInfo;
817
818 HRESULT GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
819 {
820 if (iTInfo != 0)
821 return DISP_E_BADINDEX;
822 return GetTI(lcid, ppTInfo);
823 }
824 HRESULT GetIDsOfNames(REFIID riid, LPOLESTR *pwszNames, UINT cNames, LCID lcid, DISPID *pDispID)
825 {
826 RT_NOREF1(riid); /* should be IID_NULL */
827 HRESULT hrc = FetchTI(lcid);
828 if (m_pTInfo)
829 hrc = m_pTInfo->GetIDsOfNames(pwszNames, cNames, pDispID);
830 return hrc;
831 }
832 HRESULT Invoke(IDispatch *p, DISPID DispID, REFIID riid, LCID lcid, WORD iFlags, DISPPARAMS *pDispParams,
833 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
834 {
835 RT_NOREF1(riid); /* should be IID_NULL */
836 HRESULT hrc = FetchTI(lcid);
837 if (m_pTInfo)
838 hrc = m_pTInfo->Invoke(p, DispID, iFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
839 return hrc;
840 }
841private:
842 static void __stdcall Cleanup(void *pv)
843 {
844 AssertReturnVoid(pv);
845 CComTypeInfoHolder *p = (CComTypeInfoHolder *)pv;
846 if (p->m_pTInfo != NULL)
847 p->m_pTInfo->Release();
848 p->m_pTInfo = NULL;
849 }
850
851 HRESULT GetTI(LCID lcid)
852 {
853 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
854 Assert(m_pLibID && m_pGUID);
855 if (m_pTInfo)
856 return S_OK;
857 CComCritSectLock<CComCriticalSection> lock(_pAtlModule->m_csStaticDataInitAndTypeInfo, false);
858 HRESULT hrc = lock.Lock();
859 ITypeLib *pTypeLib = NULL;
860 Assert(*m_pLibID != GUID_NULL);
861 hrc = LoadRegTypeLib(*m_pLibID, m_iMajor, m_iMinor, lcid, &pTypeLib);
862 if (SUCCEEDED(hrc))
863 {
864 ITypeInfo *pTypeInfo;
865 hrc = pTypeLib->GetTypeInfoOfGuid(*m_pGUID, &pTypeInfo);
866 if (SUCCEEDED(hrc))
867 {
868 ITypeInfo2 *pTypeInfo2;
869 if (SUCCEEDED(pTypeInfo->QueryInterface(__uuidof(ITypeInfo2), (void **)&pTypeInfo2)))
870 {
871 pTypeInfo->Release();
872 pTypeInfo = pTypeInfo2;
873 }
874 m_pTInfo = pTypeInfo;
875 _pAtlModule->AddTermFunc(Cleanup, (void *)this);
876 }
877 pTypeLib->Release();
878 }
879 return hrc;
880 }
881 HRESULT GetTI(LCID lcid, ITypeInfo **ppTInfo)
882 {
883 AssertReturn(ppTInfo, E_POINTER);
884 HRESULT hrc = S_OK;
885 if (!m_pTInfo)
886 hrc = GetTI(lcid);
887 if (m_pTInfo)
888 {
889 m_pTInfo->AddRef();
890 hrc = S_OK;
891 }
892 *ppTInfo = m_pTInfo;
893 return hrc;
894 }
895 HRESULT FetchTI(LCID lcid)
896 {
897 if (!m_pTInfo)
898 return GetTI(lcid);
899 return S_OK;
900 }
901};
902
903template <class ThreadModel> class CComObjectRootEx
904{
905public:
906 typedef ThreadModel _ThreadModel;
907 CComObjectRootEx()
908 {
909 m_iRef = 0L;
910 }
911 ~CComObjectRootEx()
912 {
913 }
914 ULONG InternalAddRef()
915 {
916 Assert(m_iRef != -1L);
917 return ThreadModel::Increment(&m_iRef);
918 }
919 ULONG InternalRelease()
920 {
921#ifdef DEBUG
922 LONG c = ThreadModel::Decrement(&m_iRef);
923 if (c < -(LONG_MAX / 2))
924 {
925 AssertMsgFailed(("Release called on object which has been already released\n"));
926 }
927 return c;
928#else
929 return ThreadModel::Decrement(&m_iRef);
930#endif
931 }
932 ULONG OuterAddRef()
933 {
934 return m_pOuterUnknown->AddRef();
935 }
936 ULONG OuterRelease()
937 {
938 return m_pOuterUnknown->Release();
939 }
940 HRESULT OuterQueryInterface(REFIID iid, void **ppvObject)
941 {
942 return m_pOuterUnknown->QueryInterface(iid, ppvObject);
943 }
944 HRESULT _AtlInitialConstruct()
945 {
946 return m_CritSect.Init();
947 }
948 void Lock()
949 {
950 m_CritSect.Lock();
951 }
952 void Unlock()
953 {
954 m_CritSect.Unlock();
955 }
956 void SetVoid(void *)
957 {
958 }
959 void InternalFinalConstructAddRef()
960 {
961 }
962 void InternalFinalConstructRelease()
963 {
964 Assert(m_iRef == 0);
965 }
966 HRESULT FinalConstruct()
967 {
968 return S_OK;
969 }
970 void FinalRelease()
971 {
972 }
973 static HRESULT WINAPI InternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObj)
974 {
975 AssertReturn(pThis, E_INVALIDARG);
976 AssertReturn(pEntries, E_INVALIDARG);
977 AssertReturn(ppvObj, E_POINTER);
978 *ppvObj = NULL;
979 if (iid == IID_IUnknown)
980 {
981 // For IUnknown use first interface, must be simple map entry.
982 Assert(pEntries->pFunc == COM_SIMPLEMAPENTRY);
983 IUnknown *pObj = (IUnknown *)((INT_PTR)pThis + pEntries->dw);
984 pObj->AddRef();
985 *ppvObj = pObj;
986 return S_OK;
987 }
988 while (pEntries->pFunc)
989 {
990 if (iid == *pEntries->piid)
991 {
992 if (pEntries->pFunc == COM_SIMPLEMAPENTRY)
993 {
994 IUnknown *pObj = (IUnknown *)((INT_PTR)pThis + pEntries->dw);
995 pObj->AddRef();
996 *ppvObj = pObj;
997 return S_OK;
998 }
999 else
1000 return pEntries->pFunc(pThis, iid, ppvObj, pEntries->dw);
1001 }
1002 pEntries++;
1003 }
1004 return E_NOINTERFACE;
1005 }
1006 static HRESULT WINAPI _Delegate(void *pThis, REFIID iid, void **ppvObj, DWORD_PTR dw)
1007 {
1008 AssertPtrReturn(pThis, E_NOINTERFACE);
1009 IUnknown *pObj = *(IUnknown **)((DWORD_PTR)pThis + dw);
1010 // If this assertion fails then the object has a delegation with a NULL
1011 // object pointer, which is highly unusual often means that the pointer
1012 // was not set up correctly. Check the COM interface map of the class
1013 // for bugs with initializing.
1014 AssertPtrReturn(pObj, E_NOINTERFACE);
1015 return pObj->QueryInterface(iid, ppvObj);
1016 }
1017
1018 union
1019 {
1020 LONG m_iRef;
1021 IUnknown *m_pOuterUnknown;
1022 };
1023private:
1024 typename ThreadModel::AutoDeleteCriticalSection m_CritSect;
1025};
1026
1027template <class Base> class CComObject : public Base
1028{
1029public:
1030 CComObject(void * = NULL) throw()
1031 {
1032 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
1033 _pAtlModule->Lock();
1034 }
1035 virtual ~CComObject() throw()
1036 {
1037 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
1038 // Catch refcount screwups by setting refcount to -(LONG_MAX/2).
1039 m_iRef = -(LONG_MAX/2);
1040 FinalRelease();
1041 _pAtlModule->Unlock();
1042 }
1043 STDMETHOD_(ULONG, AddRef)()
1044 {
1045 // If you get errors about undefined InternalAddRef then Base does not
1046 // derive from CComObjectRootEx.
1047 return InternalAddRef();
1048 }
1049 STDMETHOD_(ULONG, Release)()
1050 {
1051 // If you get errors about undefined InternalRelease then Base does not
1052 // derive from CComObjectRootEx.
1053 ULONG l = InternalRelease();
1054 if (l == 0)
1055 delete this;
1056 return l;
1057 }
1058 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw()
1059 {
1060 // If you get errors about undefined _InternalQueryInterface then
1061 // double check BEGIN_COM_MAP in the class definition.
1062 return _InternalQueryInterface(iid, ppvObj);
1063 }
1064
1065 static HRESULT WINAPI CreateInstance(CComObject<Base> **pp) throw()
1066 {
1067 AssertReturn(pp, E_POINTER);
1068 *pp = NULL;
1069
1070 HRESULT hrc = E_OUTOFMEMORY;
1071 CComObject<Base> *p = NULL;
1072 try
1073 {
1074 p = new CComObject<Base>();
1075 }
1076 catch (...)
1077 {
1078 }
1079 if (p)
1080 {
1081 p->InternalFinalConstructAddRef();
1082 hrc = p->_AtlInitialConstruct();
1083 if (SUCCEEDED(hrc))
1084 hrc = p->FinalConstruct();
1085 p->InternalFinalConstructRelease();
1086 if (FAILED(hrc))
1087 {
1088 delete p;
1089 p = NULL;
1090 }
1091 }
1092 *pp = p;
1093 return hrc;
1094 }
1095};
1096
1097template <class T, const IID *piid, const GUID *pLibID, WORD iMajor = 1, WORD iMinor = 0> class ATL_NO_VTABLE IDispatchImpl : public T
1098{
1099public:
1100 // IDispatch
1101 STDMETHOD(GetTypeInfoCount)(UINT *pcTInfo)
1102 {
1103 if (!pcTInfo)
1104 return E_POINTER;
1105 *pcTInfo = 1;
1106 return S_OK;
1107 }
1108 STDMETHOD(GetTypeInfo)(UINT cTInfo, LCID lcid, ITypeInfo **ppTInfo)
1109 {
1110 return tih.GetTypeInfo(cTInfo, lcid, ppTInfo);
1111 }
1112 STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR *pwszNames, UINT cNames, LCID lcid, DISPID *pDispID)
1113 {
1114 return tih.GetIDsOfNames(riid, pwszNames, cNames, lcid, pDispID);
1115 }
1116 STDMETHOD(Invoke)(DISPID DispID, REFIID riid, LCID lcid, WORD iFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1117 {
1118 return tih.Invoke((IDispatch *)this, DispID, riid, lcid, iFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1119 }
1120protected:
1121 static CComTypeInfoHolder tih;
1122 static HRESULT GetTI(LCID lcid, ITypeInfo **ppTInfo)
1123 {
1124 return tih.GetTI(lcid, ppTInfo);
1125 }
1126};
1127
1128template <class T, const IID *piid, const GUID *pLibID, WORD iMajor, WORD iMinor> CComTypeInfoHolder IDispatchImpl<T, piid, pLibID, iMajor, iMinor>::tih = { piid, pLibID, iMajor, iMinor, NULL };
1129
1130
1131template <class Base> class CComContainedObject : public Base
1132{
1133public:
1134 CComContainedObject(void *pv)
1135 {
1136 m_pOuterUnknown = (IUnknown *)pv;
1137 }
1138
1139 STDMETHOD_(ULONG, AddRef)() throw()
1140 {
1141 return OuterAddRef();
1142 }
1143 STDMETHOD_(ULONG, Release)() throw()
1144 {
1145 return OuterRelease();
1146 }
1147 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw()
1148 {
1149 return OuterQueryInterface(iid, ppvObj);
1150 }
1151};
1152
1153template <class Aggregated> class CComAggObject :
1154 public IUnknown,
1155 public CComObjectRootEx<typename Aggregated::_ThreadModel::ThreadModelNoCS>
1156{
1157public:
1158 CComAggObject(void *pv) :
1159 m_Aggregated(pv)
1160 {
1161 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
1162 _pAtlModule->Lock();
1163 }
1164 virtual ~CComAggObject()
1165 {
1166 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
1167 // Catch refcount screwups by setting refcount to -(LONG_MAX/2).
1168 m_iRef = -(LONG_MAX/2);
1169 FinalRelease();
1170 _pAtlModule->Unlock();
1171 }
1172 HRESULT _AtlInitialConstruct()
1173 {
1174 HRESULT hrc = m_Aggregated._AtlInitialConstruct();
1175 if (SUCCEEDED(hrc))
1176 {
1177 hrc = CComObjectRootEx<typename Aggregated::_ThreadModel::ThreadModelNoCS>::_AtlInitialConstruct();
1178 }
1179 return hrc;
1180 }
1181 HRESULT FinalConstruct()
1182 {
1183 CComObjectRootEx<Aggregated::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
1184 return m_Aggregated.FinalConstruct();
1185 }
1186 void FinalRelease()
1187 {
1188 CComObjectRootEx<Aggregated::_ThreadModel::ThreadModelNoCS>::FinalRelease();
1189 m_Aggregated.FinalRelease();
1190 }
1191
1192 STDMETHOD_(ULONG, AddRef)()
1193 {
1194 return InternalAddRef();
1195 }
1196 STDMETHOD_(ULONG, Release)()
1197 {
1198 ULONG l = InternalRelease();
1199 if (l == 0)
1200 delete this;
1201 return l;
1202 }
1203 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj)
1204 {
1205 AssertReturn(ppvObj, E_POINTER);
1206 *ppvObj = NULL;
1207
1208 HRESULT hrc = S_OK;
1209 if (iid == __uuidof(IUnknown))
1210 {
1211 *ppvObj = (void *)(IUnknown *)this;
1212 AddRef();
1213 }
1214 else
1215 hrc = m_Aggregated._InternalQueryInterface(iid, ppvObj);
1216 return hrc;
1217 }
1218 static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComAggObject<Aggregated> **pp)
1219 {
1220 AssertReturn(pp, E_POINTER);
1221 *pp = NULL;
1222
1223 HRESULT hrc = E_OUTOFMEMORY;
1224 CComAggObject<Aggregated> *p = NULL;
1225 try
1226 {
1227 p = new CComAggObject<Aggregated>(pUnkOuter);
1228 }
1229 catch (...)
1230 {
1231 }
1232 if (p)
1233 {
1234 p->SetVoid(NULL);
1235 p->InternalFinalConstructAddRef();
1236 hrc = p->_AtlInitialConstruct();
1237 if (SUCCEEDED(hrc))
1238 hrc = p->FinalConstruct();
1239 p->InternalFinalConstructRelease();
1240 if (FAILED(hrc))
1241 delete p;
1242 else
1243 *pp = p;
1244 }
1245 return hrc;
1246 }
1247
1248 CComContainedObject<Aggregated> m_Aggregated;
1249};
1250
1251class CComClassFactory:
1252 public IClassFactory,
1253 public CComObjectRootEx<CComMultiThreadModel>
1254{
1255public:
1256 BEGIN_COM_MAP(CComClassFactory)
1257 COM_INTERFACE_ENTRY(IClassFactory)
1258 END_COM_MAP()
1259
1260 virtual ~CComClassFactory()
1261 {
1262 }
1263
1264 // IClassFactory
1265 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj)
1266 {
1267 Assert(m_pfnCreateInstance);
1268 HRESULT hrc = E_POINTER;
1269 if (ppvObj)
1270 {
1271 *ppvObj = NULL;
1272 if (pUnkOuter && riid != __uuidof(IUnknown))
1273 {
1274 AssertMsgFailed(("CComClassFactory: cannot create an aggregated object other than IUnknown\n"));
1275 hrc = CLASS_E_NOAGGREGATION;
1276 }
1277 else
1278 hrc = m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
1279 }
1280 return hrc;
1281 }
1282
1283 STDMETHOD(LockServer)(BOOL fLock)
1284 {
1285 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
1286 if (fLock)
1287 _pAtlModule->Lock();
1288 else
1289 _pAtlModule->Unlock();
1290 return S_OK;
1291 }
1292
1293 // Set creator for use by the factory.
1294 void SetVoid(void *pv)
1295 {
1296 m_pfnCreateInstance = (PFNCREATEINSTANCE)pv;
1297 }
1298
1299 PFNCREATEINSTANCE m_pfnCreateInstance;
1300};
1301
1302template <class T> class CComClassFactorySingleton : public CComClassFactory
1303{
1304public:
1305 CComClassFactorySingleton() :
1306 m_hrc(S_OK),
1307 m_pObj(NULL)
1308 {
1309 }
1310 virtual ~CComClassFactorySingleton()
1311 {
1312 if (m_pObj)
1313 m_pObj->Release();
1314 }
1315 // IClassFactory
1316 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **pvObj)
1317 {
1318 HRESULT hrc = E_POINTER;
1319 if (ppvObj)
1320 {
1321 *ppvObj = NULL;
1322 // Singleton factories do not support aggregation.
1323 AssertReturn(!pUnkOuter, CLASS_E_NOAGGREGATION);
1324
1325 // Test if singleton is already created. Do it outside the lock,
1326 // relying on atomic checks. Remember the inherent race!
1327 if (SUCCEEDED(m_hrc) && !m_pObj)
1328 {
1329 Lock();
1330 // Make sure that the module is in use, otherwise the
1331 // module can terminate while we're creating a new
1332 // instance, which leads to strange errors.
1333 LockServer(true);
1334 __try
1335 {
1336 // Repeat above test to avoid races when multiple threads
1337 // want to create a singleton simultaneously.
1338 if (SUCCEEDED(m_hrc) && !m_pObj)
1339 {
1340 CComObjectCached<T> *p;
1341 m_hrc = CComObjectCached<T>::CreateInstance(&p);
1342 if (SUCCEEDED(m_hrc))
1343 {
1344 m_hrc = p->QueryInterface(IID_IUnknown, (void **)&m_pObj);
1345 if (FAILED(m_hrc))
1346 {
1347 delete p;
1348 }
1349 }
1350 }
1351 }
1352 __finally
1353 {
1354 Unlock();
1355 LockServer(false);
1356 }
1357 }
1358 if (SUCCEEDED(m_hrc))
1359 {
1360 hrc = m_pObj->QueryInterface(riid, ppvObj);
1361 }
1362 else
1363 {
1364 hrc = m_hrc;
1365 }
1366 }
1367 return hrc;
1368 }
1369 HRESULT m_hrc;
1370 IUnknown *m_pObj;
1371};
1372
1373
1374template <class T, const CLSID *pClsID = &CLSID_NULL> class CComCoClass
1375{
1376public:
1377 DECLARE_CLASSFACTORY()
1378 DECLARE_AGGREGATABLE(T)
1379 static const CLSID& WINAPI GetObjectCLSID()
1380 {
1381 return *pClsID;
1382 }
1383 template <class Q>
1384 static HRESULT CreateInstance(Q **pp)
1385 {
1386 return T::_CreatorClass::CreateInstance(NULL, __uuidof(Q), (void **)pp);
1387 }
1388};
1389
1390} /* namespace ATL */
1391
1392#endif /* !___VBox_com_microatl_h */
1393
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette