VirtualBox

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

Last change on this file since 98103 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

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