VirtualBox

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

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

VBox/com/ptr.h,VBox/com/microatl.h: Catch all bad_alloc exceptions in createObject and CreateInstance and turn them into E_OUTOFMEMORY return codes. This greatly simplifies exception analysis in code using these two methods.

  • 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-2019 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_INCLUDED_com_microatl_h
27#define VBOX_INCLUDED_com_microatl_h
28#ifndef RT_WITHOUT_PRAGMA_ONCE
29# pragma once
30#endif
31
32#include <VBox/cdefs.h> /* VBOX_STRICT */
33#include <iprt/assert.h>
34#include <iprt/critsect.h>
35#include <iprt/errcore.h> /* RT_FAILURE() */
36
37#include <iprt/win/windows.h>
38
39#include <new>
40
41
42namespace ATL
43{
44
45#define ATL_NO_VTABLE __declspec(novtable)
46
47class CAtlModule;
48__declspec(selectany) CAtlModule *_pAtlModule = NULL;
49
50class CComModule;
51__declspec(selectany) CComModule *_pModule = NULL;
52
53typedef HRESULT (WINAPI FNCREATEINSTANCE)(void *pv, REFIID riid, void **ppv);
54typedef FNCREATEINSTANCE *PFNCREATEINSTANCE;
55typedef HRESULT (WINAPI FNINTERFACEMAPHELPER)(void *pv, REFIID riid, void **ppv, DWORD_PTR dw);
56typedef FNINTERFACEMAPHELPER *PFNINTERFACEMAPHELPER;
57typedef void (__stdcall FNATLTERMFUNC)(void *pv);
58typedef FNATLTERMFUNC *PFNATLTERMFUNC;
59
60struct _ATL_TERMFUNC_ELEM
61{
62 PFNATLTERMFUNC pfn;
63 void *pv;
64 _ATL_TERMFUNC_ELEM *pNext;
65};
66
67struct _ATL_INTMAP_ENTRY
68{
69 const IID *piid; // interface ID
70 DWORD_PTR dw;
71 PFNINTERFACEMAPHELPER pFunc; // NULL: end of array, 1: offset based map entry, other: function pointer
72};
73
74#define COM_SIMPLEMAPENTRY ((ATL::PFNINTERFACEMAPHELPER)1)
75
76#define DECLARE_CLASSFACTORY_EX(c) typedef ATL::CComCreator<ATL::CComObjectNoLock<c> > _ClassFactoryCreatorClass;
77#define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory)
78#define DECLARE_CLASSFACTORY_SINGLETON(o) DECLARE_CLASSFACTORY_EX(ATL::CComClassFactorySingleton<o>)
79#define DECLARE_AGGREGATABLE(c) \
80public: \
81 typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<c> >, ATL::CComCreator<ATL::CComAggObject<c> > > _CreatorClass;
82#define DECLARE_NOT_AGGREGATABLE(c) \
83public: \
84 typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<c> >, ATL::CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass;
85
86#define DECLARE_PROTECT_FINAL_CONSTRUCT() \
87 void InternalFinalConstructAddRef() \
88 { \
89 InternalAddRef(); \
90 } \
91 void InternalFinalConstructRelease() \
92 { \
93 InternalRelease(); \
94 }
95
96#define BEGIN_COM_MAP(c) \
97public: \
98 typedef c _ComClass; \
99 HRESULT _InternalQueryInterface(REFIID iid, void **ppvObj) throw() \
100 { \
101 return InternalQueryInterface(this, _GetEntries(), iid, ppvObj); \
102 } \
103 const static ATL::_ATL_INTMAP_ENTRY *WINAPI _GetEntries() throw() \
104 { \
105 static const ATL::_ATL_INTMAP_ENTRY _aInterfaces[] = \
106 {
107
108#define COM_INTERFACE_ENTRY(c) \
109 { &__uuidof(c), (DWORD_PTR)(static_cast<c *>((_ComClass *)8))-8, COM_SIMPLEMAPENTRY },
110
111#define COM_INTERFACE_ENTRY2(c, c2) \
112 { &__uuidof(c), (DWORD_PTR)(static_cast<c *>(static_cast<c2 *>((_ComClass *)8)))-8, COM_SIMPLEMAPENTRY },
113
114#define COM_INTERFACE_ENTRY_AGGREGATE(iid, pUnk) \
115 { &iid, (DWORD_PTR)RT_UOFFSETOF(_ComClass, pUnk), _Delegate},
116
117#define END_COM_MAP() \
118 { NULL, 0, NULL} \
119 }; \
120 return _aInterfaces; \
121 } \
122 virtual ULONG STDMETHODCALLTYPE AddRef(void) throw() = 0; \
123 virtual ULONG STDMETHODCALLTYPE Release(void) throw() = 0; \
124 STDMETHOD(QueryInterface)(REFIID, void **) throw() = 0;
125
126struct _ATL_OBJMAP_ENTRY
127{
128 const CLSID *pclsid;
129 PFNCREATEINSTANCE pfnGetClassObject;
130 PFNCREATEINSTANCE pfnCreateInstance;
131 IUnknown *pCF;
132 DWORD dwRegister;
133};
134
135#define BEGIN_OBJECT_MAP(o) static ATL::_ATL_OBJMAP_ENTRY o[] = {
136#define END_OBJECT_MAP() {NULL, NULL, NULL, NULL, 0}};
137#define OBJECT_ENTRY(clsid, c) {&clsid, c::_ClassFactoryCreatorClass::CreateInstance, c::_CreatorClass::CreateInstance, NULL, 0 },
138
139
140class CComCriticalSection
141{
142public:
143 CComCriticalSection() throw()
144 {
145 memset(&m_CritSect, 0, sizeof(m_CritSect));
146 }
147 ~CComCriticalSection()
148 {
149 }
150 HRESULT Lock() throw()
151 {
152 RTCritSectEnter(&m_CritSect);
153 return S_OK;
154 }
155 HRESULT Unlock() throw()
156 {
157 RTCritSectLeave(&m_CritSect);
158 return S_OK;
159 }
160 HRESULT Init() throw()
161 {
162 HRESULT hrc = S_OK;
163 if (RT_FAILURE(RTCritSectInit(&m_CritSect)))
164 hrc = E_FAIL;
165 return hrc;
166 }
167
168 HRESULT Term() throw()
169 {
170 RTCritSectDelete(&m_CritSect);
171 return S_OK;
172 }
173
174 RTCRITSECT m_CritSect;
175};
176
177template <class TLock> class CComCritSectLock
178{
179public:
180 CComCritSectLock(CComCriticalSection &cs, bool fInitialLock = true) :
181 m_cs(cs),
182 m_fLocked(false)
183 {
184 if (fInitialLock)
185 {
186 HRESULT hrc = Lock();
187 if (FAILED(hrc))
188 throw hrc;
189 }
190 }
191
192 ~CComCritSectLock() throw()
193 {
194 if (m_fLocked)
195 Unlock();
196 }
197
198 HRESULT Lock()
199 {
200 Assert(!m_fLocked);
201 HRESULT hrc = m_cs.Lock();
202 if (FAILED(hrc))
203 return hrc;
204 m_fLocked = true;
205 return S_OK;
206 }
207
208 void Unlock() throw()
209 {
210 Assert(m_fLocked);
211 m_cs.Unlock();
212 m_fLocked = false;
213 }
214
215
216private:
217 TLock &m_cs;
218 bool m_fLocked;
219
220 CComCritSectLock(const CComCritSectLock&) throw(); // Do not call.
221 CComCritSectLock &operator=(const CComCritSectLock &) throw(); // Do not call.
222};
223
224class CComFakeCriticalSection
225{
226public:
227 HRESULT Lock() throw()
228 {
229 return S_OK;
230 }
231 HRESULT Unlock() throw()
232 {
233 return S_OK;
234 }
235 HRESULT Init() throw()
236 {
237 return S_OK;
238 }
239 HRESULT Term() throw()
240 {
241 return S_OK;
242 }
243};
244
245class CComAutoCriticalSection : public CComCriticalSection
246{
247public:
248 CComAutoCriticalSection()
249 {
250 HRESULT hrc = CComCriticalSection::Init();
251 if (FAILED(hrc))
252 throw hrc;
253 }
254 ~CComAutoCriticalSection() throw()
255 {
256 CComCriticalSection::Term();
257 }
258private :
259 HRESULT Init() throw(); // Do not call.
260 HRESULT Term() throw(); // Do not call.
261};
262
263class CComAutoDeleteCriticalSection : public CComCriticalSection
264{
265public:
266 CComAutoDeleteCriticalSection(): m_fInit(false)
267 {
268 }
269
270 ~CComAutoDeleteCriticalSection() throw()
271 {
272 if (!m_fInit)
273 return;
274 m_fInit = false;
275 CComCriticalSection::Term();
276 }
277
278 HRESULT Init() throw()
279 {
280 Assert(!m_fInit);
281 HRESULT hrc = CComCriticalSection::Init();
282 if (SUCCEEDED(hrc))
283 m_fInit = true;
284 return hrc;
285 }
286
287 HRESULT Lock()
288 {
289 Assert(m_fInit);
290 return CComCriticalSection::Lock();
291 }
292
293 HRESULT Unlock()
294 {
295 Assert(m_fInit);
296 return CComCriticalSection::Unlock();
297 }
298
299private:
300 HRESULT Term() throw();
301 bool m_fInit;
302};
303
304
305class CComMultiThreadModelNoCS
306{
307public:
308 static ULONG WINAPI Increment(LONG *pL) throw()
309 {
310 return InterlockedIncrement(pL);
311 }
312 static ULONG WINAPI Decrement(LONG *pL) throw()
313 {
314 return InterlockedDecrement(pL);
315 }
316 typedef CComFakeCriticalSection AutoCriticalSection;
317 typedef CComFakeCriticalSection AutoDeleteCriticalSection;
318 typedef CComMultiThreadModelNoCS ThreadModelNoCS;
319};
320
321class CComMultiThreadModel
322{
323public:
324 static ULONG WINAPI Increment(LONG *pL) throw()
325 {
326 return InterlockedIncrement(pL);
327 }
328 static ULONG WINAPI Decrement(LONG *pL) throw()
329 {
330 return InterlockedDecrement(pL);
331 }
332 typedef CComAutoCriticalSection AutoCriticalSection;
333 typedef CComAutoDeleteCriticalSection AutoDeleteCriticalSection;
334 typedef CComMultiThreadModelNoCS ThreadModelNoCS;
335};
336
337class ATL_NO_VTABLE CAtlModule
338{
339public:
340 static GUID m_LibID;
341 CComCriticalSection m_csStaticDataInitAndTypeInfo;
342
343 CAtlModule() throw()
344 {
345 // One instance only per linking namespace!
346 AssertMsg(!_pAtlModule, ("CAtlModule: trying to create more than one instance per linking namespace\n"));
347
348 fInit = false;
349
350 m_cLock = 0;
351 m_pTermFuncs = NULL;
352 _pAtlModule = this;
353
354 if (FAILED(m_csStaticDataInitAndTypeInfo.Init()))
355 {
356 AssertMsgFailed(("CAtlModule: failed to init critsect\n"));
357 return;
358 }
359 fInit = true;
360 }
361
362 void Term() throw()
363 {
364 if (!fInit)
365 return;
366
367 // Call all term functions.
368 if (m_pTermFuncs)
369 {
370 _ATL_TERMFUNC_ELEM *p = m_pTermFuncs;
371 _ATL_TERMFUNC_ELEM *pNext;
372 while (p)
373 {
374 p->pfn(p->pv);
375 pNext = p->pNext;
376 delete p;
377 p = pNext;
378 }
379 m_pTermFuncs = NULL;
380 }
381 m_csStaticDataInitAndTypeInfo.Term();
382 fInit = false;
383 }
384
385 virtual ~CAtlModule() throw()
386 {
387 Term();
388 }
389
390 virtual LONG Lock() throw()
391 {
392 return CComMultiThreadModel::Increment(&m_cLock);
393 }
394
395 virtual LONG Unlock() throw()
396 {
397 return CComMultiThreadModel::Decrement(&m_cLock);
398 }
399
400 virtual LONG GetLockCount() throw()
401 {
402 return m_cLock;
403 }
404
405 HRESULT AddTermFunc(PFNATLTERMFUNC pfn, void *pv)
406 {
407 _ATL_TERMFUNC_ELEM *pNew = new(std::nothrow) _ATL_TERMFUNC_ELEM;
408 if (!pNew)
409 return E_OUTOFMEMORY;
410 pNew->pfn = pfn;
411 pNew->pv = pv;
412 CComCritSectLock<CComCriticalSection> lock(m_csStaticDataInitAndTypeInfo, false);
413 HRESULT 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 = new(std::nothrow) T(pv);
648 if (p)
649 {
650 p->SetVoid(pv);
651 p->InternalFinalConstructAddRef();
652 hrc = p->_AtlInitialConstruct();
653 if (SUCCEEDED(hrc))
654 hrc = p->FinalConstruct();
655 p->InternalFinalConstructRelease();
656 if (SUCCEEDED(hrc))
657 hrc = p->QueryInterface(riid, ppv);
658 if (FAILED(hrc))
659 delete p;
660 }
661 return hrc;
662 }
663};
664
665template <HRESULT hrc> class CComFailCreator
666{
667public:
668 static HRESULT WINAPI CreateInstance(void *, REFIID, void **ppv)
669 {
670 AssertReturn(ppv, E_POINTER);
671 *ppv = NULL;
672
673 return hrc;
674 }
675};
676
677template <class T1, class T2> class CComCreator2
678{
679public:
680 static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, void **ppv)
681 {
682 AssertReturn(ppv, E_POINTER);
683
684 return !pv ? T1::CreateInstance(NULL, riid, ppv) : T2::CreateInstance(pv, riid, ppv);
685 }
686};
687
688template <class Base> class CComObjectCached : public Base
689{
690public:
691 CComObjectCached(void * = NULL)
692 {
693 }
694 virtual ~CComObjectCached()
695 {
696 // Catch refcount screwups by setting refcount to -(LONG_MAX/2).
697 m_iRef = -(LONG_MAX/2);
698 FinalRelease();
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 = NULL;
1053 try
1054 {
1055 p = new CComObject<Base>();
1056 }
1057 catch (std::bad_alloc &)
1058 {
1059 p = NULL;
1060 }
1061 if (p)
1062 {
1063 p->InternalFinalConstructAddRef();
1064 try
1065 {
1066 hrc = p->_AtlInitialConstruct();
1067 if (SUCCEEDED(hrc))
1068 hrc = p->FinalConstruct();
1069 }
1070 catch (std::bad_alloc &)
1071 {
1072 hrc = E_OUTOFMEMORY;
1073 }
1074 p->InternalFinalConstructRelease();
1075 if (FAILED(hrc))
1076 {
1077 delete p;
1078 p = NULL;
1079 }
1080 }
1081 *pp = p;
1082 return hrc;
1083 }
1084};
1085
1086template <class T, const IID *piid, const GUID *pLibID, WORD iMajor = 1, WORD iMinor = 0> class ATL_NO_VTABLE IDispatchImpl : public T
1087{
1088public:
1089 // IDispatch
1090 STDMETHOD(GetTypeInfoCount)(UINT *pcTInfo)
1091 {
1092 if (!pcTInfo)
1093 return E_POINTER;
1094 *pcTInfo = 1;
1095 return S_OK;
1096 }
1097 STDMETHOD(GetTypeInfo)(UINT cTInfo, LCID lcid, ITypeInfo **ppTInfo)
1098 {
1099 return tih.GetTypeInfo(cTInfo, lcid, ppTInfo);
1100 }
1101 STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR *pwszNames, UINT cNames, LCID lcid, DISPID *pDispID)
1102 {
1103 return tih.GetIDsOfNames(riid, pwszNames, cNames, lcid, pDispID);
1104 }
1105 STDMETHOD(Invoke)(DISPID DispID, REFIID riid, LCID lcid, WORD iFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1106 {
1107 return tih.Invoke((IDispatch *)this, DispID, riid, lcid, iFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1108 }
1109protected:
1110 static CComTypeInfoHolder tih;
1111 static HRESULT GetTI(LCID lcid, ITypeInfo **ppTInfo)
1112 {
1113 return tih.GetTI(lcid, ppTInfo);
1114 }
1115};
1116
1117template <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 };
1118
1119
1120template <class Base> class CComContainedObject : public Base
1121{
1122public:
1123 CComContainedObject(void *pv)
1124 {
1125 m_pOuterUnknown = (IUnknown *)pv;
1126 }
1127
1128 STDMETHOD_(ULONG, AddRef)() throw()
1129 {
1130 return OuterAddRef();
1131 }
1132 STDMETHOD_(ULONG, Release)() throw()
1133 {
1134 return OuterRelease();
1135 }
1136 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw()
1137 {
1138 return OuterQueryInterface(iid, ppvObj);
1139 }
1140};
1141
1142template <class Aggregated> class CComAggObject :
1143 public IUnknown,
1144 public CComObjectRootEx<typename Aggregated::_ThreadModel::ThreadModelNoCS>
1145{
1146public:
1147 CComAggObject(void *pv) :
1148 m_Aggregated(pv)
1149 {
1150 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
1151 _pAtlModule->Lock();
1152 }
1153 virtual ~CComAggObject()
1154 {
1155 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
1156 // Catch refcount screwups by setting refcount to -(LONG_MAX/2).
1157 m_iRef = -(LONG_MAX/2);
1158 FinalRelease();
1159 _pAtlModule->Unlock();
1160 }
1161 HRESULT _AtlInitialConstruct()
1162 {
1163 HRESULT hrc = m_Aggregated._AtlInitialConstruct();
1164 if (SUCCEEDED(hrc))
1165 {
1166 hrc = CComObjectRootEx<typename Aggregated::_ThreadModel::ThreadModelNoCS>::_AtlInitialConstruct();
1167 }
1168 return hrc;
1169 }
1170 HRESULT FinalConstruct()
1171 {
1172 CComObjectRootEx<Aggregated::_ThreadModel::ThreadModelNoCS>::FinalConstruct();
1173 return m_Aggregated.FinalConstruct();
1174 }
1175 void FinalRelease()
1176 {
1177 CComObjectRootEx<Aggregated::_ThreadModel::ThreadModelNoCS>::FinalRelease();
1178 m_Aggregated.FinalRelease();
1179 }
1180
1181 STDMETHOD_(ULONG, AddRef)()
1182 {
1183 return InternalAddRef();
1184 }
1185 STDMETHOD_(ULONG, Release)()
1186 {
1187 ULONG l = InternalRelease();
1188 if (l == 0)
1189 delete this;
1190 return l;
1191 }
1192 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj)
1193 {
1194 AssertReturn(ppvObj, E_POINTER);
1195 *ppvObj = NULL;
1196
1197 HRESULT hrc = S_OK;
1198 if (iid == __uuidof(IUnknown))
1199 {
1200 *ppvObj = (void *)(IUnknown *)this;
1201 AddRef();
1202 }
1203 else
1204 hrc = m_Aggregated._InternalQueryInterface(iid, ppvObj);
1205 return hrc;
1206 }
1207 static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComAggObject<Aggregated> **pp)
1208 {
1209 AssertReturn(pp, E_POINTER);
1210 *pp = NULL;
1211
1212 HRESULT hrc = E_OUTOFMEMORY;
1213 CComAggObject<Aggregated> *p = new(std::nothrow) CComAggObject<Aggregated>(pUnkOuter);
1214 if (p)
1215 {
1216 p->SetVoid(NULL);
1217 p->InternalFinalConstructAddRef();
1218 hrc = p->_AtlInitialConstruct();
1219 if (SUCCEEDED(hrc))
1220 hrc = p->FinalConstruct();
1221 p->InternalFinalConstructRelease();
1222 if (FAILED(hrc))
1223 delete p;
1224 else
1225 *pp = p;
1226 }
1227 return hrc;
1228 }
1229
1230 CComContainedObject<Aggregated> m_Aggregated;
1231};
1232
1233class CComClassFactory:
1234 public IClassFactory,
1235 public CComObjectRootEx<CComMultiThreadModel>
1236{
1237public:
1238 BEGIN_COM_MAP(CComClassFactory)
1239 COM_INTERFACE_ENTRY(IClassFactory)
1240 END_COM_MAP()
1241
1242 virtual ~CComClassFactory()
1243 {
1244 }
1245
1246 // IClassFactory
1247 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj)
1248 {
1249 Assert(m_pfnCreateInstance);
1250 HRESULT hrc = E_POINTER;
1251 if (ppvObj)
1252 {
1253 *ppvObj = NULL;
1254 if (pUnkOuter && riid != __uuidof(IUnknown))
1255 {
1256 AssertMsgFailed(("CComClassFactory: cannot create an aggregated object other than IUnknown\n"));
1257 hrc = CLASS_E_NOAGGREGATION;
1258 }
1259 else
1260 hrc = m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
1261 }
1262 return hrc;
1263 }
1264
1265 STDMETHOD(LockServer)(BOOL fLock)
1266 {
1267 AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n"));
1268 if (fLock)
1269 _pAtlModule->Lock();
1270 else
1271 _pAtlModule->Unlock();
1272 return S_OK;
1273 }
1274
1275 // Set creator for use by the factory.
1276 void SetVoid(void *pv)
1277 {
1278 m_pfnCreateInstance = (PFNCREATEINSTANCE)pv;
1279 }
1280
1281 PFNCREATEINSTANCE m_pfnCreateInstance;
1282};
1283
1284template <class T> class CComClassFactorySingleton : public CComClassFactory
1285{
1286public:
1287 CComClassFactorySingleton() :
1288 m_hrc(S_OK),
1289 m_pObj(NULL)
1290 {
1291 }
1292 virtual ~CComClassFactorySingleton()
1293 {
1294 if (m_pObj)
1295 m_pObj->Release();
1296 }
1297 // IClassFactory
1298 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **pvObj)
1299 {
1300 HRESULT hrc = E_POINTER;
1301 if (ppvObj)
1302 {
1303 *ppvObj = NULL;
1304 // Singleton factories do not support aggregation.
1305 AssertReturn(!pUnkOuter, CLASS_E_NOAGGREGATION);
1306
1307 // Test if singleton is already created. Do it outside the lock,
1308 // relying on atomic checks. Remember the inherent race!
1309 if (SUCCEEDED(m_hrc) && !m_pObj)
1310 {
1311 Lock();
1312 // Make sure that the module is in use, otherwise the
1313 // module can terminate while we're creating a new
1314 // instance, which leads to strange errors.
1315 LockServer(true);
1316 __try
1317 {
1318 // Repeat above test to avoid races when multiple threads
1319 // want to create a singleton simultaneously.
1320 if (SUCCEEDED(m_hrc) && !m_pObj)
1321 {
1322 CComObjectCached<T> *p;
1323 m_hrc = CComObjectCached<T>::CreateInstance(&p);
1324 if (SUCCEEDED(m_hrc))
1325 {
1326 m_hrc = p->QueryInterface(IID_IUnknown, (void **)&m_pObj);
1327 if (FAILED(m_hrc))
1328 {
1329 delete p;
1330 }
1331 }
1332 }
1333 }
1334 __finally
1335 {
1336 Unlock();
1337 LockServer(false);
1338 }
1339 }
1340 if (SUCCEEDED(m_hrc))
1341 {
1342 hrc = m_pObj->QueryInterface(riid, ppvObj);
1343 }
1344 else
1345 {
1346 hrc = m_hrc;
1347 }
1348 }
1349 return hrc;
1350 }
1351 HRESULT m_hrc;
1352 IUnknown *m_pObj;
1353};
1354
1355
1356template <class T, const CLSID *pClsID = &CLSID_NULL> class CComCoClass
1357{
1358public:
1359 DECLARE_CLASSFACTORY()
1360 DECLARE_AGGREGATABLE(T)
1361 static const CLSID& WINAPI GetObjectCLSID()
1362 {
1363 return *pClsID;
1364 }
1365 template <class Q>
1366 static HRESULT CreateInstance(Q **pp)
1367 {
1368 return T::_CreatorClass::CreateInstance(NULL, __uuidof(Q), (void **)pp);
1369 }
1370};
1371
1372} /* namespace ATL */
1373
1374#endif /* !VBOX_INCLUDED_com_microatl_h */
1375
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