VirtualBox

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

Last change on this file since 64622 was 63642, checked in by vboxsync, 8 years ago

microatl.h: InternalRelease should check VBOX_STRICT not DEBUG. Use AssertMsg instead of AssertMsgFailed. Text was also ambiguous.

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

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