VirtualBox

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

Last change on this file since 73097 was 73097, checked in by vboxsync, 6 years ago

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.5 KB
Line 
1/** @file
2 * ATL lookalike, just the tiny subset we actually need.
3 */
4
5/*
6 * Copyright (C) 2016-2017 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_UOFFSETOF(_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 }
697 STDMETHOD_(ULONG, AddRef)() throw()
698 {
699 // If you get errors about undefined InternalAddRef then Base does not
700 // derive from CComObjectRootEx.
701 ULONG l = InternalAddRef();
702 if (l == 2)
703 {
704 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
705 _pAtlModule->Lock();
706 }
707 return l;
708 }
709 STDMETHOD_(ULONG, Release)() throw()
710 {
711 // If you get errors about undefined InternalRelease then Base does not
712 // derive from CComObjectRootEx.
713 ULONG l = InternalRelease();
714 if (l == 0)
715 delete this;
716 else if (l == 1)
717 {
718 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
719 _pAtlModule->Unlock();
720 }
721 return l;
722 }
723 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw()
724 {
725 // If you get errors about undefined _InternalQueryInterface then
726 // double check BEGIN_COM_MAP in the class definition.
727 return _InternalQueryInterface(iid, ppvObj);
728 }
729 static HRESULT WINAPI CreateInstance(CComObjectCached<Base> **pp) throw()
730 {
731 AssertReturn(pp, E_POINTER);
732 *pp = NULL;
733
734 HRESULT hrc = E_OUTOFMEMORY;
735 CComObjectCached<Base> *p = new(std::nothrow) CComObjectCached<Base>();
736 if (p)
737 {
738 p->SetVoid(NULL);
739 p->InternalFinalConstructAddRef();
740 hrc = p->_AtlInitialConstruct();
741 if (SUCCEEDED(hrc))
742 hrc = p->FinalConstruct();
743 p->InternalFinalConstructRelease();
744 if (FAILED(hrc))
745 delete p;
746 else
747 *pp = p;
748 }
749 return hrc;
750 }
751};
752
753template <class Base> class CComObjectNoLock : public Base
754{
755public:
756 CComObjectNoLock(void * = NULL)
757 {
758 }
759 virtual ~CComObjectNoLock()
760 {
761 // Catch refcount screwups by setting refcount to -(LONG_MAX/2).
762 m_iRef = -(LONG_MAX/2);
763 FinalRelease();
764 }
765 STDMETHOD_(ULONG, AddRef)() throw()
766 {
767 // If you get errors about undefined InternalAddRef then Base does not
768 // derive from CComObjectRootEx.
769 return InternalAddRef();
770 }
771 STDMETHOD_(ULONG, Release)() throw()
772 {
773 // If you get errors about undefined InternalRelease then Base does not
774 // derive from CComObjectRootEx.
775 ULONG l = InternalRelease();
776 if (l == 0)
777 delete this;
778 return l;
779 }
780 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw()
781 {
782 // If you get errors about undefined _InternalQueryInterface then
783 // double check BEGIN_COM_MAP in the class definition.
784 return _InternalQueryInterface(iid, ppvObj);
785 }
786};
787
788class CComTypeInfoHolder
789{
790 /** @todo implement type info caching, making stuff more efficient - would we benefit? */
791public:
792 const GUID *m_pGUID;
793 const GUID *m_pLibID;
794 WORD m_iMajor;
795 WORD m_iMinor;
796 ITypeInfo *m_pTInfo;
797
798 HRESULT GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
799 {
800 if (iTInfo != 0)
801 return DISP_E_BADINDEX;
802 return GetTI(lcid, ppTInfo);
803 }
804 HRESULT GetIDsOfNames(REFIID riid, LPOLESTR *pwszNames, UINT cNames, LCID lcid, DISPID *pDispID)
805 {
806 RT_NOREF1(riid); /* should be IID_NULL */
807 HRESULT hrc = FetchTI(lcid);
808 if (m_pTInfo)
809 hrc = m_pTInfo->GetIDsOfNames(pwszNames, cNames, pDispID);
810 return hrc;
811 }
812 HRESULT Invoke(IDispatch *p, DISPID DispID, REFIID riid, LCID lcid, WORD iFlags, DISPPARAMS *pDispParams,
813 VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
814 {
815 RT_NOREF1(riid); /* should be IID_NULL */
816 HRESULT hrc = FetchTI(lcid);
817 if (m_pTInfo)
818 hrc = m_pTInfo->Invoke(p, DispID, iFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
819 return hrc;
820 }
821private:
822 static void __stdcall Cleanup(void *pv)
823 {
824 AssertReturnVoid(pv);
825 CComTypeInfoHolder *p = (CComTypeInfoHolder *)pv;
826 if (p->m_pTInfo != NULL)
827 p->m_pTInfo->Release();
828 p->m_pTInfo = NULL;
829 }
830
831 HRESULT GetTI(LCID lcid)
832 {
833 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
834 Assert(m_pLibID && m_pGUID);
835 if (m_pTInfo)
836 return S_OK;
837 CComCritSectLock<CComCriticalSection> lock(_pAtlModule->m_csStaticDataInitAndTypeInfo, false);
838 HRESULT hrc = lock.Lock();
839 ITypeLib *pTypeLib = NULL;
840 Assert(*m_pLibID != GUID_NULL);
841 hrc = LoadRegTypeLib(*m_pLibID, m_iMajor, m_iMinor, lcid, &pTypeLib);
842 if (SUCCEEDED(hrc))
843 {
844 ITypeInfo *pTypeInfo;
845 hrc = pTypeLib->GetTypeInfoOfGuid(*m_pGUID, &pTypeInfo);
846 if (SUCCEEDED(hrc))
847 {
848 ITypeInfo2 *pTypeInfo2;
849 if (SUCCEEDED(pTypeInfo->QueryInterface(__uuidof(ITypeInfo2), (void **)&pTypeInfo2)))
850 {
851 pTypeInfo->Release();
852 pTypeInfo = pTypeInfo2;
853 }
854 m_pTInfo = pTypeInfo;
855 _pAtlModule->AddTermFunc(Cleanup, (void *)this);
856 }
857 pTypeLib->Release();
858 }
859 return hrc;
860 }
861 HRESULT GetTI(LCID lcid, ITypeInfo **ppTInfo)
862 {
863 AssertReturn(ppTInfo, E_POINTER);
864 HRESULT hrc = S_OK;
865 if (!m_pTInfo)
866 hrc = GetTI(lcid);
867 if (m_pTInfo)
868 {
869 m_pTInfo->AddRef();
870 hrc = S_OK;
871 }
872 *ppTInfo = m_pTInfo;
873 return hrc;
874 }
875 HRESULT FetchTI(LCID lcid)
876 {
877 if (!m_pTInfo)
878 return GetTI(lcid);
879 return S_OK;
880 }
881};
882
883template <class ThreadModel> class CComObjectRootEx
884{
885public:
886 typedef ThreadModel _ThreadModel;
887 CComObjectRootEx()
888 {
889 m_iRef = 0L;
890 }
891 ~CComObjectRootEx()
892 {
893 }
894 ULONG InternalAddRef()
895 {
896 Assert(m_iRef != -1L);
897 return ThreadModel::Increment(&m_iRef);
898 }
899 ULONG InternalRelease()
900 {
901#ifdef VBOX_STRICT
902 LONG c = ThreadModel::Decrement(&m_iRef);
903 AssertMsg(c >= -(LONG_MAX / 2), /* See ~CComObjectNoLock, ~CComObject & ~CComAggObject. */
904 ("Release called on object which has been already destroyed!\n"));
905 return c;
906#else
907 return ThreadModel::Decrement(&m_iRef);
908#endif
909 }
910 ULONG OuterAddRef()
911 {
912 return m_pOuterUnknown->AddRef();
913 }
914 ULONG OuterRelease()
915 {
916 return m_pOuterUnknown->Release();
917 }
918 HRESULT OuterQueryInterface(REFIID iid, void **ppvObject)
919 {
920 return m_pOuterUnknown->QueryInterface(iid, ppvObject);
921 }
922 HRESULT _AtlInitialConstruct()
923 {
924 return m_CritSect.Init();
925 }
926 void Lock()
927 {
928 m_CritSect.Lock();
929 }
930 void Unlock()
931 {
932 m_CritSect.Unlock();
933 }
934 void SetVoid(void *)
935 {
936 }
937 void InternalFinalConstructAddRef()
938 {
939 }
940 void InternalFinalConstructRelease()
941 {
942 Assert(m_iRef == 0);
943 }
944 HRESULT FinalConstruct()
945 {
946 return S_OK;
947 }
948 void FinalRelease()
949 {
950 }
951 static HRESULT WINAPI InternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObj)
952 {
953 AssertReturn(pThis, E_INVALIDARG);
954 AssertReturn(pEntries, E_INVALIDARG);
955 AssertReturn(ppvObj, E_POINTER);
956 *ppvObj = NULL;
957 if (iid == IID_IUnknown)
958 {
959 // For IUnknown use first interface, must be simple map entry.
960 Assert(pEntries->pFunc == COM_SIMPLEMAPENTRY);
961 IUnknown *pObj = (IUnknown *)((INT_PTR)pThis + pEntries->dw);
962 pObj->AddRef();
963 *ppvObj = pObj;
964 return S_OK;
965 }
966 while (pEntries->pFunc)
967 {
968 if (iid == *pEntries->piid)
969 {
970 if (pEntries->pFunc == COM_SIMPLEMAPENTRY)
971 {
972 IUnknown *pObj = (IUnknown *)((INT_PTR)pThis + pEntries->dw);
973 pObj->AddRef();
974 *ppvObj = pObj;
975 return S_OK;
976 }
977 else
978 return pEntries->pFunc(pThis, iid, ppvObj, pEntries->dw);
979 }
980 pEntries++;
981 }
982 return E_NOINTERFACE;
983 }
984 static HRESULT WINAPI _Delegate(void *pThis, REFIID iid, void **ppvObj, DWORD_PTR dw)
985 {
986 AssertPtrReturn(pThis, E_NOINTERFACE);
987 IUnknown *pObj = *(IUnknown **)((DWORD_PTR)pThis + dw);
988 // If this assertion fails then the object has a delegation with a NULL
989 // object pointer, which is highly unusual often means that the pointer
990 // was not set up correctly. Check the COM interface map of the class
991 // for bugs with initializing.
992 AssertPtrReturn(pObj, E_NOINTERFACE);
993 return pObj->QueryInterface(iid, ppvObj);
994 }
995
996 union
997 {
998 LONG m_iRef;
999 IUnknown *m_pOuterUnknown;
1000 };
1001private:
1002 typename ThreadModel::AutoDeleteCriticalSection m_CritSect;
1003};
1004
1005template <class Base> class CComObject : public Base
1006{
1007public:
1008 CComObject(void * = NULL) throw()
1009 {
1010 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
1011 _pAtlModule->Lock();
1012 }
1013 virtual ~CComObject() throw()
1014 {
1015 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
1016 // Catch refcount screwups by setting refcount to -(LONG_MAX/2).
1017 m_iRef = -(LONG_MAX/2);
1018 FinalRelease();
1019 _pAtlModule->Unlock();
1020 }
1021 STDMETHOD_(ULONG, AddRef)()
1022 {
1023 // If you get errors about undefined InternalAddRef then Base does not
1024 // derive from CComObjectRootEx.
1025 return InternalAddRef();
1026 }
1027 STDMETHOD_(ULONG, Release)()
1028 {
1029 // If you get errors about undefined InternalRelease then Base does not
1030 // derive from CComObjectRootEx.
1031 ULONG l = InternalRelease();
1032 if (l == 0)
1033 delete this;
1034 return l;
1035 }
1036 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw()
1037 {
1038 // If you get errors about undefined _InternalQueryInterface then
1039 // double check BEGIN_COM_MAP in the class definition.
1040 return _InternalQueryInterface(iid, ppvObj);
1041 }
1042
1043 static HRESULT WINAPI CreateInstance(CComObject<Base> **pp) throw()
1044 {
1045 AssertReturn(pp, E_POINTER);
1046 *pp = NULL;
1047
1048 HRESULT hrc = E_OUTOFMEMORY;
1049 CComObject<Base> *p = new(std::nothrow) CComObject<Base>();
1050 if (p)
1051 {
1052 p->InternalFinalConstructAddRef();
1053 hrc = p->_AtlInitialConstruct();
1054 if (SUCCEEDED(hrc))
1055 hrc = p->FinalConstruct();
1056 p->InternalFinalConstructRelease();
1057 if (FAILED(hrc))
1058 {
1059 delete p;
1060 p = NULL;
1061 }
1062 }
1063 *pp = p;
1064 return hrc;
1065 }
1066};
1067
1068template <class T, const IID *piid, const GUID *pLibID, WORD iMajor = 1, WORD iMinor = 0> class ATL_NO_VTABLE IDispatchImpl : public T
1069{
1070public:
1071 // IDispatch
1072 STDMETHOD(GetTypeInfoCount)(UINT *pcTInfo)
1073 {
1074 if (!pcTInfo)
1075 return E_POINTER;
1076 *pcTInfo = 1;
1077 return S_OK;
1078 }
1079 STDMETHOD(GetTypeInfo)(UINT cTInfo, LCID lcid, ITypeInfo **ppTInfo)
1080 {
1081 return tih.GetTypeInfo(cTInfo, lcid, ppTInfo);
1082 }
1083 STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR *pwszNames, UINT cNames, LCID lcid, DISPID *pDispID)
1084 {
1085 return tih.GetIDsOfNames(riid, pwszNames, cNames, lcid, pDispID);
1086 }
1087 STDMETHOD(Invoke)(DISPID DispID, REFIID riid, LCID lcid, WORD iFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1088 {
1089 return tih.Invoke((IDispatch *)this, DispID, riid, lcid, iFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1090 }
1091protected:
1092 static CComTypeInfoHolder tih;
1093 static HRESULT GetTI(LCID lcid, ITypeInfo **ppTInfo)
1094 {
1095 return tih.GetTI(lcid, ppTInfo);
1096 }
1097};
1098
1099template <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 };
1100
1101
1102template <class Base> class CComContainedObject : public Base
1103{
1104public:
1105 CComContainedObject(void *pv)
1106 {
1107 m_pOuterUnknown = (IUnknown *)pv;
1108 }
1109
1110 STDMETHOD_(ULONG, AddRef)() throw()
1111 {
1112 return OuterAddRef();
1113 }
1114 STDMETHOD_(ULONG, Release)() throw()
1115 {
1116 return OuterRelease();
1117 }
1118 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw()
1119 {
1120 return OuterQueryInterface(iid, ppvObj);
1121 }
1122};
1123
1124template <class Aggregated> class CComAggObject :
1125 public IUnknown,
1126 public CComObjectRootEx<typename Aggregated::_ThreadModel::ThreadModelNoCS>
1127{
1128public:
1129 CComAggObject(void *pv) :
1130 m_Aggregated(pv)
1131 {
1132 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
1133 _pAtlModule->Lock();
1134 }
1135 virtual ~CComAggObject()
1136 {
1137 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
1138 // Catch refcount screwups by setting refcount to -(LONG_MAX/2).
1139 m_iRef = -(LONG_MAX/2);
1140 FinalRelease();
1141 _pAtlModule->Unlock();
1142 }
1143 HRESULT _AtlInitialConstruct()
1144 {
1145 HRESULT hrc = m_Aggregated._AtlInitialConstruct();
1146 if (SUCCEEDED(hrc))
1147 {
1148 hrc = CComObjectRootEx<typename Aggregated::_ThreadModel::ThreadModelNoCS>::_AtlInitialConstruct();
1149 }
1150 return hrc;
1151 }
1152 HRESULT FinalConstruct()
1153 {
1154 CComObjectRootEx<Aggregated::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
1155 return m_Aggregated.FinalConstruct();
1156 }
1157 void FinalRelease()
1158 {
1159 CComObjectRootEx<Aggregated::_ThreadModel::ThreadModelNoCS>::FinalRelease();
1160 m_Aggregated.FinalRelease();
1161 }
1162
1163 STDMETHOD_(ULONG, AddRef)()
1164 {
1165 return InternalAddRef();
1166 }
1167 STDMETHOD_(ULONG, Release)()
1168 {
1169 ULONG l = InternalRelease();
1170 if (l == 0)
1171 delete this;
1172 return l;
1173 }
1174 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj)
1175 {
1176 AssertReturn(ppvObj, E_POINTER);
1177 *ppvObj = NULL;
1178
1179 HRESULT hrc = S_OK;
1180 if (iid == __uuidof(IUnknown))
1181 {
1182 *ppvObj = (void *)(IUnknown *)this;
1183 AddRef();
1184 }
1185 else
1186 hrc = m_Aggregated._InternalQueryInterface(iid, ppvObj);
1187 return hrc;
1188 }
1189 static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComAggObject<Aggregated> **pp)
1190 {
1191 AssertReturn(pp, E_POINTER);
1192 *pp = NULL;
1193
1194 HRESULT hrc = E_OUTOFMEMORY;
1195 CComAggObject<Aggregated> *p = new(std::nothrow) CComAggObject<Aggregated>(pUnkOuter);
1196 if (p)
1197 {
1198 p->SetVoid(NULL);
1199 p->InternalFinalConstructAddRef();
1200 hrc = p->_AtlInitialConstruct();
1201 if (SUCCEEDED(hrc))
1202 hrc = p->FinalConstruct();
1203 p->InternalFinalConstructRelease();
1204 if (FAILED(hrc))
1205 delete p;
1206 else
1207 *pp = p;
1208 }
1209 return hrc;
1210 }
1211
1212 CComContainedObject<Aggregated> m_Aggregated;
1213};
1214
1215class CComClassFactory:
1216 public IClassFactory,
1217 public CComObjectRootEx<CComMultiThreadModel>
1218{
1219public:
1220 BEGIN_COM_MAP(CComClassFactory)
1221 COM_INTERFACE_ENTRY(IClassFactory)
1222 END_COM_MAP()
1223
1224 virtual ~CComClassFactory()
1225 {
1226 }
1227
1228 // IClassFactory
1229 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj)
1230 {
1231 Assert(m_pfnCreateInstance);
1232 HRESULT hrc = E_POINTER;
1233 if (ppvObj)
1234 {
1235 *ppvObj = NULL;
1236 if (pUnkOuter && riid != __uuidof(IUnknown))
1237 {
1238 AssertMsgFailed(("CComClassFactory: cannot create an aggregated object other than IUnknown\n"));
1239 hrc = CLASS_E_NOAGGREGATION;
1240 }
1241 else
1242 hrc = m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
1243 }
1244 return hrc;
1245 }
1246
1247 STDMETHOD(LockServer)(BOOL fLock)
1248 {
1249 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
1250 if (fLock)
1251 _pAtlModule->Lock();
1252 else
1253 _pAtlModule->Unlock();
1254 return S_OK;
1255 }
1256
1257 // Set creator for use by the factory.
1258 void SetVoid(void *pv)
1259 {
1260 m_pfnCreateInstance = (PFNCREATEINSTANCE)pv;
1261 }
1262
1263 PFNCREATEINSTANCE m_pfnCreateInstance;
1264};
1265
1266template <class T> class CComClassFactorySingleton : public CComClassFactory
1267{
1268public:
1269 CComClassFactorySingleton() :
1270 m_hrc(S_OK),
1271 m_pObj(NULL)
1272 {
1273 }
1274 virtual ~CComClassFactorySingleton()
1275 {
1276 if (m_pObj)
1277 m_pObj->Release();
1278 }
1279 // IClassFactory
1280 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **pvObj)
1281 {
1282 HRESULT hrc = E_POINTER;
1283 if (ppvObj)
1284 {
1285 *ppvObj = NULL;
1286 // Singleton factories do not support aggregation.
1287 AssertReturn(!pUnkOuter, CLASS_E_NOAGGREGATION);
1288
1289 // Test if singleton is already created. Do it outside the lock,
1290 // relying on atomic checks. Remember the inherent race!
1291 if (SUCCEEDED(m_hrc) && !m_pObj)
1292 {
1293 Lock();
1294 // Make sure that the module is in use, otherwise the
1295 // module can terminate while we're creating a new
1296 // instance, which leads to strange errors.
1297 LockServer(true);
1298 __try
1299 {
1300 // Repeat above test to avoid races when multiple threads
1301 // want to create a singleton simultaneously.
1302 if (SUCCEEDED(m_hrc) && !m_pObj)
1303 {
1304 CComObjectCached<T> *p;
1305 m_hrc = CComObjectCached<T>::CreateInstance(&p);
1306 if (SUCCEEDED(m_hrc))
1307 {
1308 m_hrc = p->QueryInterface(IID_IUnknown, (void **)&m_pObj);
1309 if (FAILED(m_hrc))
1310 {
1311 delete p;
1312 }
1313 }
1314 }
1315 }
1316 __finally
1317 {
1318 Unlock();
1319 LockServer(false);
1320 }
1321 }
1322 if (SUCCEEDED(m_hrc))
1323 {
1324 hrc = m_pObj->QueryInterface(riid, ppvObj);
1325 }
1326 else
1327 {
1328 hrc = m_hrc;
1329 }
1330 }
1331 return hrc;
1332 }
1333 HRESULT m_hrc;
1334 IUnknown *m_pObj;
1335};
1336
1337
1338template <class T, const CLSID *pClsID = &CLSID_NULL> class CComCoClass
1339{
1340public:
1341 DECLARE_CLASSFACTORY()
1342 DECLARE_AGGREGATABLE(T)
1343 static const CLSID& WINAPI GetObjectCLSID()
1344 {
1345 return *pClsID;
1346 }
1347 template <class Q>
1348 static HRESULT CreateInstance(Q **pp)
1349 {
1350 return T::_CreatorClass::CreateInstance(NULL, __uuidof(Q), (void **)pp);
1351 }
1352};
1353
1354} /* namespace ATL */
1355
1356#endif /* !___VBox_com_microatl_h */
1357
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