VirtualBox

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

最後變更 在這個檔案從96407是 96407,由 vboxsync 提交於 3 年 前

scm copyright and license note update

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

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