xref: /reactos/sdk/lib/atl/atlcom.h (revision d1288082)
1 /*
2  * ReactOS ATL
3  *
4  * Copyright 2009 Andrew Hill <ash77@reactos.org>
5  * Copyright 2013 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #pragma once
23 
24 #include <cguid.h>          // for GUID_NULL
25 #include <pseh/pseh2.h>
26 
27 namespace ATL
28 {
29 
30 template <class Base, const IID *piid, class T, class Copy, class ThreadModel = CComObjectThreadModel>
31 class CComEnum;
32 
33 #if defined(_WINDLL) | defined(_USRDLL)
34 #define DECLARE_CLASSFACTORY_EX(cf) typedef ATL::CComCreator<ATL::CComObjectCached<cf> > _ClassFactoryCreatorClass;
35 #else
36 // Class factory should not change lock count
37 #define DECLARE_CLASSFACTORY_EX(cf) typedef ATL::CComCreator<ATL::CComObjectNoLock<cf>> _ClassFactoryCreatorClass;
38 #endif
39 #define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory)
40 #define DECLARE_CLASSFACTORY_SINGLETON(obj) DECLARE_CLASSFACTORY_EX(ATL::CComClassFactorySingleton<obj>)
41 
42 class CComObjectRootBase
43 {
44 public:
45     LONG m_dwRef;
46 public:
CComObjectRootBase()47     CComObjectRootBase()
48     {
49         m_dwRef = 0;
50     }
51 
~CComObjectRootBase()52     ~CComObjectRootBase()
53     {
54     }
55 
SetVoid(void *)56     void SetVoid(void *)
57     {
58     }
59 
_AtlFinalConstruct()60     HRESULT _AtlFinalConstruct()
61     {
62         return S_OK;
63     }
64 
FinalConstruct()65     HRESULT FinalConstruct()
66     {
67         return S_OK;
68     }
69 
InternalFinalConstructAddRef()70     void InternalFinalConstructAddRef()
71     {
72     }
73 
InternalFinalConstructRelease()74     void InternalFinalConstructRelease()
75     {
76     }
77 
FinalRelease()78     void FinalRelease()
79     {
80     }
81 
ObjectMain(bool)82     static void WINAPI ObjectMain(bool)
83     {
84     }
85 
GetCategoryMap()86     static const struct _ATL_CATMAP_ENTRY *GetCategoryMap()
87     {
88         return NULL;
89     }
90 
InternalQueryInterface(void * pThis,const _ATL_INTMAP_ENTRY * pEntries,REFIID iid,void ** ppvObject)91     static HRESULT WINAPI InternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObject)
92     {
93         return AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject);
94     }
95 
96 };
97 
98 template <class ThreadModel>
99 class CComObjectRootEx : public CComObjectRootBase
100 {
101 private:
102     typename ThreadModel::AutoDeleteCriticalSection m_critsec;
103 public:
~CComObjectRootEx()104     ~CComObjectRootEx()
105     {
106     }
107 
InternalAddRef()108     ULONG InternalAddRef()
109     {
110         ATLASSERT(m_dwRef >= 0);
111         return ThreadModel::Increment(&m_dwRef);
112     }
113 
InternalRelease()114     ULONG InternalRelease()
115     {
116         ATLASSERT(m_dwRef > 0);
117         return ThreadModel::Decrement(&m_dwRef);
118     }
119 
Lock()120     void Lock()
121     {
122         m_critsec.Lock();
123     }
124 
Unlock()125     void Unlock()
126     {
127         m_critsec.Unlock();
128     }
129 
_AtlInitialConstruct()130     HRESULT _AtlInitialConstruct()
131     {
132         return m_critsec.Init();
133     }
134 };
135 
136 template <class Base>
137 class CComObject : public Base
138 {
139 public:
140     CComObject(void * = NULL)
141     {
142         _pAtlModule->Lock();
143     }
144 
~CComObject()145     virtual ~CComObject()
146     {
147         this->FinalRelease();
148         _pAtlModule->Unlock();
149     }
150 
STDMETHOD_(ULONG,AddRef)151     STDMETHOD_(ULONG, AddRef)()
152     {
153         return this->InternalAddRef();
154     }
155 
STDMETHOD_(ULONG,Release)156     STDMETHOD_(ULONG, Release)()
157     {
158         ULONG newRefCount;
159 
160         newRefCount = this->InternalRelease();
161         if (newRefCount == 0)
162             delete this;
163         return newRefCount;
164     }
165 
STDMETHOD(QueryInterface)166     STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
167     {
168         return this->_InternalQueryInterface(iid, ppvObject);
169     }
170 
CreateInstance(CComObject<Base> ** pp)171     static HRESULT WINAPI CreateInstance(CComObject<Base> **pp)
172     {
173         CComObject<Base> *newInstance;
174         HRESULT hResult;
175 
176         ATLASSERT(pp != NULL);
177         if (pp == NULL)
178             return E_POINTER;
179 
180         hResult = E_OUTOFMEMORY;
181         newInstance = NULL;
182         ATLTRY(newInstance = new CComObject<Base>())
183         if (newInstance != NULL)
184         {
185             newInstance->SetVoid(NULL);
186             newInstance->InternalFinalConstructAddRef();
187             hResult = newInstance->_AtlInitialConstruct();
188             if (SUCCEEDED(hResult))
189                 hResult = newInstance->FinalConstruct();
190             if (SUCCEEDED(hResult))
191                 hResult = newInstance->_AtlFinalConstruct();
192             newInstance->InternalFinalConstructRelease();
193             if (hResult != S_OK)
194             {
195                 delete newInstance;
196                 newInstance = NULL;
197             }
198         }
199         *pp = newInstance;
200         return hResult;
201     }
202 
203 
204 };
205 
206 template <class Base>
207 class CComContainedObject : public Base
208 {
209 public:
210     IUnknown* m_pUnkOuter;
m_pUnkOuter(static_cast<IUnknown * > (pv))211     CComContainedObject(void * pv = NULL) : m_pUnkOuter(static_cast<IUnknown*>(pv))
212     {
213     }
214 
STDMETHOD_(ULONG,AddRef)215     STDMETHOD_(ULONG, AddRef)()
216     {
217         return m_pUnkOuter->AddRef();
218     }
219 
STDMETHOD_(ULONG,Release)220     STDMETHOD_(ULONG, Release)()
221     {
222         return m_pUnkOuter->Release();
223     }
224 
STDMETHOD(QueryInterface)225     STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
226     {
227         return m_pUnkOuter->QueryInterface(iid, ppvObject);
228     }
229 
GetControllingUnknown()230     IUnknown* GetControllingUnknown()
231     {
232         return m_pUnkOuter;
233     }
234 };
235 
236 template <class contained>
237 class CComAggObject : public contained
238 {
239 public:
240     CComContainedObject<contained> m_contained;
241 
m_contained(static_cast<contained * > (pv))242     CComAggObject(void * pv = NULL) : m_contained(static_cast<contained*>(pv))
243     {
244         _pAtlModule->Lock();
245     }
246 
~CComAggObject()247     virtual ~CComAggObject()
248     {
249         this->FinalRelease();
250         _pAtlModule->Unlock();
251     }
252 
FinalConstruct()253     HRESULT FinalConstruct()
254     {
255         return m_contained.FinalConstruct();
256     }
FinalRelease()257     void FinalRelease()
258     {
259         m_contained.FinalRelease();
260     }
261 
STDMETHOD_(ULONG,AddRef)262     STDMETHOD_(ULONG, AddRef)()
263     {
264         return this->InternalAddRef();
265     }
266 
STDMETHOD_(ULONG,Release)267     STDMETHOD_(ULONG, Release)()
268     {
269         ULONG newRefCount;
270         newRefCount = this->InternalRelease();
271         if (newRefCount == 0)
272             delete this;
273         return newRefCount;
274     }
275 
STDMETHOD(QueryInterface)276     STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
277     {
278         if (ppvObject == NULL)
279             return E_POINTER;
280         if (iid == IID_IUnknown)
281             *ppvObject = reinterpret_cast<void*>(this);
282         else
283             return m_contained._InternalQueryInterface(iid, ppvObject);
284         return S_OK;
285     }
286 
CreateInstance(IUnknown * punkOuter,CComAggObject<contained> ** pp)287     static HRESULT WINAPI CreateInstance(IUnknown * punkOuter, CComAggObject<contained> **pp)
288     {
289         CComAggObject<contained> *newInstance;
290         HRESULT hResult;
291 
292         ATLASSERT(pp != NULL);
293         if (pp == NULL)
294             return E_POINTER;
295 
296         hResult = E_OUTOFMEMORY;
297         newInstance = NULL;
298         ATLTRY(newInstance = new CComAggObject<contained>(punkOuter))
299         if (newInstance != NULL)
300         {
301             newInstance->SetVoid(NULL);
302             newInstance->InternalFinalConstructAddRef();
303             hResult = newInstance->_AtlInitialConstruct();
304             if (SUCCEEDED(hResult))
305                 hResult = newInstance->FinalConstruct();
306             if (SUCCEEDED(hResult))
307                 hResult = newInstance->_AtlFinalConstruct();
308             newInstance->InternalFinalConstructRelease();
309             if (hResult != S_OK)
310             {
311                 delete newInstance;
312                 newInstance = NULL;
313             }
314         }
315         *pp = newInstance;
316         return hResult;
317     }
318 };
319 
320 template <class contained>
321 class CComPolyObject : public contained
322 {
323 public:
324     CComContainedObject<contained> m_contained;
325 
326     CComPolyObject(void * pv = NULL)
327         : m_contained(pv ? static_cast<contained*>(pv) : this)
328     {
329         _pAtlModule->Lock();
330     }
331 
~CComPolyObject()332     virtual ~CComPolyObject()
333     {
334         this->FinalRelease();
335         _pAtlModule->Unlock();
336     }
337 
FinalConstruct()338     HRESULT FinalConstruct()
339     {
340         return m_contained.FinalConstruct();
341     }
FinalRelease()342     void FinalRelease()
343     {
344         m_contained.FinalRelease();
345     }
346 
STDMETHOD_(ULONG,AddRef)347     STDMETHOD_(ULONG, AddRef)()
348     {
349         return this->InternalAddRef();
350     }
351 
STDMETHOD_(ULONG,Release)352     STDMETHOD_(ULONG, Release)()
353     {
354         ULONG newRefCount;
355         newRefCount = this->InternalRelease();
356         if (newRefCount == 0)
357             delete this;
358         return newRefCount;
359     }
360 
STDMETHOD(QueryInterface)361     STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
362     {
363         if (ppvObject == NULL)
364             return E_POINTER;
365         if (iid == IID_IUnknown)
366             *ppvObject = reinterpret_cast<void*>(this);
367         else
368             return m_contained._InternalQueryInterface(iid, ppvObject);
369         return S_OK;
370     }
371 
CreateInstance(IUnknown * punkOuter,CComPolyObject<contained> ** pp)372     static HRESULT WINAPI CreateInstance(IUnknown * punkOuter, CComPolyObject<contained> **pp)
373     {
374         CComPolyObject<contained> *newInstance;
375         HRESULT hResult;
376 
377         ATLASSERT(pp != NULL);
378         if (pp == NULL)
379             return E_POINTER;
380 
381         hResult = E_OUTOFMEMORY;
382         newInstance = NULL;
383         ATLTRY(newInstance = new CComPolyObject<contained>(punkOuter))
384         if (newInstance != NULL)
385         {
386             newInstance->SetVoid(NULL);
387             newInstance->InternalFinalConstructAddRef();
388             hResult = newInstance->_AtlInitialConstruct();
389             if (SUCCEEDED(hResult))
390                 hResult = newInstance->FinalConstruct();
391             if (SUCCEEDED(hResult))
392                 hResult = newInstance->_AtlFinalConstruct();
393             newInstance->InternalFinalConstructRelease();
394             if (hResult != S_OK)
395             {
396                 delete newInstance;
397                 newInstance = NULL;
398             }
399         }
400         *pp = newInstance;
401         return hResult;
402     }
403 };
404 
405 template <HRESULT hResult>
406 class CComFailCreator
407 {
408 public:
CreateInstance(void *,REFIID,LPVOID * ppv)409     static HRESULT WINAPI CreateInstance(void *, REFIID, LPVOID *ppv)
410     {
411         ATLASSERT(ppv != NULL);
412         if (ppv == NULL)
413             return E_POINTER;
414         *ppv = NULL;
415 
416         return hResult;
417     }
418 };
419 
420 template <class T1>
421 class CComCreator
422 {
423 public:
CreateInstance(void * pv,REFIID riid,LPVOID * ppv)424     static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, LPVOID *ppv)
425     {
426         T1 *newInstance;
427         HRESULT hResult;
428 
429         ATLASSERT(ppv != NULL);
430         if (ppv == NULL)
431             return E_POINTER;
432         *ppv = NULL;
433 
434         hResult = E_OUTOFMEMORY;
435         newInstance = NULL;
436         ATLTRY(newInstance = new T1(pv))
437         if (newInstance != NULL)
438         {
439             newInstance->SetVoid(pv);
440             newInstance->InternalFinalConstructAddRef();
441             hResult = newInstance->_AtlInitialConstruct();
442             if (SUCCEEDED(hResult))
443                 hResult = newInstance->FinalConstruct();
444             if (SUCCEEDED(hResult))
445                 hResult = newInstance->_AtlFinalConstruct();
446             newInstance->InternalFinalConstructRelease();
447             if (SUCCEEDED(hResult))
448                 hResult = newInstance->QueryInterface(riid, ppv);
449             if (FAILED(hResult))
450             {
451                 delete newInstance;
452                 newInstance = NULL;
453             }
454         }
455         return hResult;
456     }
457 };
458 
459 template <class T1, class T2>
460 class CComCreator2
461 {
462 public:
CreateInstance(void * pv,REFIID riid,LPVOID * ppv)463     static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, LPVOID *ppv)
464     {
465         ATLASSERT(ppv != NULL);
466 
467         if (pv == NULL)
468             return T1::CreateInstance(NULL, riid, ppv);
469         else
470             return T2::CreateInstance(pv, riid, ppv);
471     }
472 };
473 
474 template <class Base>
475 class CComObjectCached : public Base
476 {
477 public:
478     CComObjectCached(void * = NULL)
479     {
480     }
481 
~CComObjectCached()482     virtual ~CComObjectCached()
483     {
484         this->FinalRelease();
485     }
486 
STDMETHOD_(ULONG,AddRef)487     STDMETHOD_(ULONG, AddRef)()
488     {
489         ULONG newRefCount;
490 
491         newRefCount = this->InternalAddRef();
492         if (newRefCount == 2)
493             _pAtlModule->Lock();
494         return newRefCount;
495     }
496 
STDMETHOD_(ULONG,Release)497     STDMETHOD_(ULONG, Release)()
498     {
499         ULONG newRefCount;
500 
501         newRefCount = this->InternalRelease();
502         if (newRefCount == 0)
503             delete this;
504         else if (newRefCount == 1)
505             _pAtlModule->Unlock();
506         return newRefCount;
507     }
508 
STDMETHOD(QueryInterface)509     STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
510     {
511         return this->_InternalQueryInterface(iid, ppvObject);
512     }
513 
CreateInstance(CComObjectCached<Base> ** pp)514     static HRESULT WINAPI CreateInstance(CComObjectCached<Base> **pp)
515     {
516         CComObjectCached<Base> *newInstance;
517         HRESULT hResult;
518 
519         ATLASSERT(pp != NULL);
520         if (pp == NULL)
521             return E_POINTER;
522 
523         hResult = E_OUTOFMEMORY;
524         newInstance = NULL;
525         ATLTRY(newInstance = new CComObjectCached<Base>())
526         if (newInstance != NULL)
527         {
528             newInstance->SetVoid(NULL);
529             newInstance->InternalFinalConstructAddRef();
530             hResult = newInstance->_AtlInitialConstruct();
531             if (SUCCEEDED(hResult))
532                 hResult = newInstance->FinalConstruct();
533             if (SUCCEEDED(hResult))
534                 hResult = newInstance->_AtlFinalConstruct();
535             newInstance->InternalFinalConstructRelease();
536             if (hResult != S_OK)
537             {
538                 delete newInstance;
539                 newInstance = NULL;
540             }
541         }
542         *pp = newInstance;
543         return hResult;
544     }
545 };
546 
547 
548 template <class Base>
549 class CComObjectNoLock : public Base
550 {
551   public:
552     CComObjectNoLock(void* = NULL)
553     {
554     }
555 
~CComObjectNoLock()556     virtual ~CComObjectNoLock()
557     {
558         this->FinalRelease();
559     }
560 
STDMETHOD_(ULONG,AddRef)561     STDMETHOD_(ULONG, AddRef)()
562     {
563         return this->InternalAddRef();
564     }
565 
STDMETHOD_(ULONG,Release)566     STDMETHOD_(ULONG, Release)()
567     {
568         ULONG newRefCount = this->InternalRelease();
569         if (newRefCount == 0)
570             delete this;
571         return newRefCount;
572     }
573 
STDMETHOD(QueryInterface)574     STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
575     {
576         return this->_InternalQueryInterface(iid, ppvObject);
577     }
578 };
579 
580 
581 #define BEGIN_COM_MAP(x)                                                        \
582 public:                                                                            \
583     typedef x _ComMapClass;                                                        \
584     HRESULT _InternalQueryInterface(REFIID iid, void **ppvObject)                \
585     {                                                                            \
586         return this->InternalQueryInterface(this, _GetEntries(), iid, ppvObject);        \
587     }                                                                            \
588     const static ATL::_ATL_INTMAP_ENTRY *WINAPI _GetEntries()                    \
589     {                                                                            \
590         static const ATL::_ATL_INTMAP_ENTRY _entries[] = {
591 
592 #define END_COM_MAP()                                                            \
593             {NULL, 0, 0}                                                        \
594         };                                                                        \
595         return _entries;                                                        \
596     }                                                                            \
597     virtual ULONG STDMETHODCALLTYPE AddRef() = 0;                                \
598     virtual ULONG STDMETHODCALLTYPE Release() = 0;                                \
599     STDMETHOD(QueryInterface)(REFIID, void **) = 0;
600 
601 #define COM_INTERFACE_ENTRY_IID(iid, x)                                            \
602     {&iid, offsetofclass(x, _ComMapClass), _ATL_SIMPLEMAPENTRY},
603 
604 #define COM_INTERFACE_ENTRY(x)                                                  \
605     {&_ATL_IIDOF(x),                                                            \
606     offsetofclass(x, _ComMapClass),                                             \
607     _ATL_SIMPLEMAPENTRY},
608 
609 #define COM_INTERFACE_ENTRY2_IID(iid, x, x2)                                    \
610     {&iid,                                                                        \
611             reinterpret_cast<DWORD_PTR>(static_cast<x *>(static_cast<x2 *>(reinterpret_cast<_ComMapClass *>(_ATL_PACKING)))) - _ATL_PACKING,    \
612             _ATL_SIMPLEMAPENTRY},
613 
614 #define COM_INTERFACE_ENTRY_BREAK(x)                                            \
615     {&_ATL_IIDOF(x),                                                            \
616     NULL,                                                                        \
617     _Break},    // Break is a function that issues int 3.
618 
619 #define COM_INTERFACE_ENTRY_NOINTERFACE(x)                                        \
620     {&_ATL_IIDOF(x),                                                            \
621     NULL,                                                                        \
622     _NoInterface}, // NoInterface returns E_NOINTERFACE.
623 
624 #define COM_INTERFACE_ENTRY_FUNC(iid, dw, func)                                    \
625     {&iid,                                                                        \
626     dw,                                                                            \
627     func},
628 
629 #define COM_INTERFACE_ENTRY_FUNC_BLIND(dw, func)                                \
630     {NULL,                                                                        \
631     dw,                                                                            \
632     func},
633 
634 #define COM_INTERFACE_ENTRY_CHAIN(classname)                                    \
635     {NULL,                                                                        \
636     reinterpret_cast<DWORD>(&_CComChainData<classname, _ComMapClass>::data),    \
637     _Chain},
638 
639 #define DECLARE_NO_REGISTRY()\
640     static HRESULT WINAPI UpdateRegistry(BOOL /*bRegister*/)                    \
641     {                                                                            \
642         return S_OK;                                                            \
643     }
644 
645 #define DECLARE_REGISTRY_RESOURCEID(x)                                            \
646     static HRESULT WINAPI UpdateRegistry(BOOL bRegister)                        \
647     {                                                                            \
648         return ATL::_pAtlModule->UpdateRegistryFromResource(x, bRegister);        \
649     }
650 
651 #define DECLARE_NOT_AGGREGATABLE(x)                                                \
652 public:                                                                            \
653     typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<x> >, ATL::CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass;
654 
655 #define DECLARE_AGGREGATABLE(x)                                                    \
656 public:                                                                            \
657     typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<x> >, ATL::CComCreator<ATL::CComAggObject<x> > > _CreatorClass;
658 
659 #define DECLARE_ONLY_AGGREGATABLE(x)                                            \
660 public:                                                                            \
661     typedef ATL::CComCreator2<ATL::CComFailCreator<E_FAIL>, ATL::CComCreator<ATL::CComAggObject<x> > > _CreatorClass;
662 
663 #define DECLARE_POLY_AGGREGATABLE(x)                                            \
664 public:                                                                            \
665     typedef ATL::CComCreator<ATL::CComPolyObject<x> > _CreatorClass;
666 
667 #define COM_INTERFACE_ENTRY_AGGREGATE(iid, punk)                                \
668     {&iid,                                                                      \
669     (DWORD_PTR)offsetof(_ComMapClass, punk),                                    \
670     _Delegate},
671 
672 #define DECLARE_GET_CONTROLLING_UNKNOWN()                                        \
673 public:                                                                            \
674     virtual IUnknown *GetControllingUnknown()                                    \
675     {                                                                            \
676         return GetUnknown();                                                    \
677     }
678 
679 #define DECLARE_PROTECT_FINAL_CONSTRUCT()                                        \
680     void InternalFinalConstructAddRef()                                            \
681     {                                                                            \
682         InternalAddRef();                                                        \
683     }                                                                            \
684     void InternalFinalConstructRelease()                                        \
685     {                                                                            \
686         InternalRelease();                                                        \
687     }
688 
689 #define BEGIN_OBJECT_MAP(x) static ATL::_ATL_OBJMAP_ENTRY x[] = {
690 
691 #define END_OBJECT_MAP()   {NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL}};
692 
693 #define OBJECT_ENTRY(clsid, class)                                                \
694 {                                                                                \
695     &clsid,                                                                        \
696     class::UpdateRegistry,                                                        \
697     class::_ClassFactoryCreatorClass::CreateInstance,                            \
698     class::_CreatorClass::CreateInstance,                                        \
699     NULL,                                                                        \
700     0,                                                                            \
701     class::GetObjectDescription,                                                \
702     class::GetCategoryMap,                                                        \
703     class::ObjectMain },
704 
705 
706 
707 #define OBJECT_ENTRY_AUTO(clsid, class)                                                                                \
708     ATL::_ATL_OBJMAP_ENTRY __objMap_##class = {                                                                        \
709         &clsid,                                                                                                        \
710         class ::UpdateRegistry,                                                                                        \
711         class ::_ClassFactoryCreatorClass::CreateInstance,                                                             \
712         class ::_CreatorClass::CreateInstance,                                                                         \
713         NULL,                                                                                                          \
714         0,                                                                                                             \
715         class ::GetObjectDescription,                                                                                  \
716         class ::GetCategoryMap,                                                                                        \
717         class ::ObjectMain};                                                                                           \
718     extern "C" _ATLALLOC("ATL$__m") ATL::_ATL_OBJMAP_ENTRY *const __pobjMap_##class = &__objMap_##class;               \
719     OBJECT_ENTRY_PRAGMA(class)
720 
721 
722 
723 class CComClassFactory :
724     public IClassFactory,
725     public CComObjectRootEx<CComGlobalsThreadModel>
726 {
727 public:
728     _ATL_CREATORFUNC *m_pfnCreateInstance;
729 
~CComClassFactory()730     virtual ~CComClassFactory()
731     {
732     }
733 
734 public:
STDMETHOD(CreateInstance)735     STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj)
736     {
737         HRESULT hResult;
738 
739         ATLASSERT(m_pfnCreateInstance != NULL);
740 
741         if (ppvObj == NULL)
742             return E_POINTER;
743         *ppvObj = NULL;
744 
745         if (pUnkOuter != NULL && InlineIsEqualUnknown(riid) == FALSE)
746             hResult = CLASS_E_NOAGGREGATION;
747         else
748             hResult = m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
749         return hResult;
750     }
751 
STDMETHOD(LockServer)752     STDMETHOD(LockServer)(BOOL fLock)
753     {
754         if (fLock)
755             _pAtlModule->Lock();
756         else
757             _pAtlModule->Unlock();
758         return S_OK;
759     }
760 
SetVoid(void * pv)761     void SetVoid(void *pv)
762     {
763         m_pfnCreateInstance = (_ATL_CREATORFUNC *)pv;
764     }
765 
766     BEGIN_COM_MAP(CComClassFactory)
767         COM_INTERFACE_ENTRY_IID(IID_IClassFactory, IClassFactory)
768     END_COM_MAP()
769 };
770 
771 template <class T>
772 class CComClassFactorySingleton :
773     public CComClassFactory
774 {
775 public:
776     HRESULT m_hrCreate;
777     IUnknown *m_spObj;
778 
779 public:
CComClassFactorySingleton()780     CComClassFactorySingleton() :
781         m_hrCreate(S_OK),
782         m_spObj(NULL)
783     {
784     }
785 
STDMETHOD(CreateInstance)786     STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj)
787     {
788         HRESULT hResult;
789 
790         if (ppvObj == NULL)
791             return E_POINTER;
792         *ppvObj = NULL;
793 
794         if (pUnkOuter != NULL)
795             hResult = CLASS_E_NOAGGREGATION;
796         else if (m_hrCreate == S_OK && m_spObj == NULL)
797         {
798             _SEH2_TRY
799             {
800                 Lock();
801                 if (m_hrCreate == S_OK && m_spObj == NULL)
802                 {
803                     CComObjectCached<T> *pObj;
804                     m_hrCreate = CComObjectCached<T>::CreateInstance(&pObj);
805                     if (SUCCEEDED(m_hrCreate))
806                     {
807                         m_hrCreate = pObj->QueryInterface(IID_IUnknown, reinterpret_cast<PVOID *>(&m_spObj));
808                         if (FAILED(m_hrCreate))
809                             delete pObj;
810                     }
811                 }
812             }
813             _SEH2_FINALLY
814             {
815                 Unlock();
816             }
817             _SEH2_END;
818         }
819         if (m_hrCreate == S_OK)
820             hResult = m_spObj->QueryInterface(riid, ppvObj);
821         else
822             hResult = m_hrCreate;
823         return hResult;
824     }
825 };
826 
827 template <class T, const CLSID *pclsid = &CLSID_NULL>
828 class CComCoClass
829 {
830 public:
DECLARE_CLASSFACTORY()831     DECLARE_CLASSFACTORY()
832     //DECLARE_AGGREGATABLE(T)   // This should be here, but gcc...
833 
834     static LPCTSTR WINAPI GetObjectDescription()
835     {
836         return NULL;
837     }
838 };
839 
840 template <class T>
841 class _Copy
842 {
843 public:
copy(T * pTo,const T * pFrom)844     static HRESULT copy(T *pTo, const T *pFrom)
845     {
846         memcpy(pTo, pFrom, sizeof(T));
847         return S_OK;
848     }
849 
init(T *)850     static void init(T *)
851     {
852     }
853 
destroy(T *)854     static void destroy(T *)
855     {
856     }
857 };
858 
859 template<>
860 class _Copy<CONNECTDATA>
861 {
862 public:
copy(CONNECTDATA * pTo,const CONNECTDATA * pFrom)863     static HRESULT copy(CONNECTDATA *pTo, const CONNECTDATA *pFrom)
864     {
865         *pTo = *pFrom;
866         if (pTo->pUnk)
867             pTo->pUnk->AddRef();
868         return S_OK;
869     }
870 
init(CONNECTDATA *)871     static void init(CONNECTDATA *)
872     {
873     }
874 
destroy(CONNECTDATA * p)875     static void destroy(CONNECTDATA *p)
876     {
877         if (p->pUnk)
878             p->pUnk->Release();
879     }
880 };
881 
882 template <class T>
883 class _CopyInterface
884 {
885 public:
copy(T ** pTo,T ** pFrom)886     static HRESULT copy(T **pTo, T **pFrom)
887     {
888         *pTo = *pFrom;
889         if (*pTo)
890             (*pTo)->AddRef();
891         return S_OK;
892     }
893 
init(T **)894     static void init(T **)
895     {
896     }
897 
destroy(T ** p)898     static void destroy(T **p)
899     {
900         if (*p)
901             (*p)->Release();
902     }
903 };
904 
905 enum CComEnumFlags
906 {
907     AtlFlagNoCopy = 0,
908     AtlFlagTakeOwnership = 2,        // BitOwn
909     AtlFlagCopy = 3                    // BitOwn | BitCopy
910 };
911 
912 template <class Base, const IID *piid, class T, class Copy>
913 class CComEnumImpl : public Base
914 {
915 private:
916     typedef CComObject<CComEnum<Base, piid, T, Copy> > enumeratorClass;
917 public:
918     CComPtr<IUnknown> m_spUnk;
919     DWORD m_dwFlags;
920     T *m_begin;
921     T *m_end;
922     T *m_iter;
923 public:
CComEnumImpl()924     CComEnumImpl()
925     {
926         m_dwFlags = 0;
927         m_begin = NULL;
928         m_end = NULL;
929         m_iter = NULL;
930     }
931 
~CComEnumImpl()932     virtual ~CComEnumImpl()
933     {
934         T *x;
935 
936         if ((m_dwFlags & BitOwn) != 0)
937         {
938             for (x = m_begin; x != m_end; x++)
939                 Copy::destroy(x);
940             delete [] m_begin;
941         }
942     }
943 
944     HRESULT Init(T *begin, T *end, IUnknown *pUnk, CComEnumFlags flags = AtlFlagNoCopy)
945     {
946         T *newBuffer;
947         T *sourcePtr;
948         T *destPtr;
949         T *cleanupPtr;
950         HRESULT hResult;
951 
952         if (flags == AtlFlagCopy)
953         {
954             ATLTRY(newBuffer = new T[end - begin])
955             if (newBuffer == NULL)
956                 return E_OUTOFMEMORY;
957             destPtr = newBuffer;
958             for (sourcePtr = begin; sourcePtr != end; sourcePtr++)
959             {
960                 Copy::init(destPtr);
961                 hResult = Copy::copy(destPtr, sourcePtr);
962                 if (FAILED(hResult))
963                 {
964                     cleanupPtr = m_begin;
965                     while (cleanupPtr < destPtr)
966                         Copy::destroy(cleanupPtr++);
967                     delete [] newBuffer;
968                     return hResult;
969                 }
970                 destPtr++;
971             }
972             m_begin = newBuffer;
973             m_end = m_begin + (end - begin);
974         }
975         else
976         {
977             m_begin = begin;
978             m_end = end;
979         }
980         m_spUnk = pUnk;
981         m_dwFlags = flags;
982         m_iter = m_begin;
983         return S_OK;
984     }
985 
STDMETHOD(Next)986     STDMETHOD(Next)(ULONG celt, T *rgelt, ULONG *pceltFetched)
987     {
988         ULONG numAvailable;
989         ULONG numToFetch;
990         T *rgeltTemp;
991         HRESULT hResult;
992 
993         if (pceltFetched != NULL)
994             *pceltFetched = 0;
995         if (celt == 0)
996             return E_INVALIDARG;
997         if (rgelt == NULL || (celt != 1 && pceltFetched == NULL))
998             return E_POINTER;
999         if (m_begin == NULL || m_end == NULL || m_iter == NULL)
1000             return E_FAIL;
1001 
1002         numAvailable = static_cast<ULONG>(m_end - m_iter);
1003         if (celt < numAvailable)
1004             numToFetch = celt;
1005         else
1006             numToFetch = numAvailable;
1007         if (pceltFetched != NULL)
1008             *pceltFetched = numToFetch;
1009         rgeltTemp = rgelt;
1010         while (numToFetch != 0)
1011         {
1012             hResult = Copy::copy(rgeltTemp, m_iter);
1013             if (FAILED(hResult))
1014             {
1015                 while (rgelt < rgeltTemp)
1016                     Copy::destroy(rgelt++);
1017                 if (pceltFetched != NULL)
1018                     *pceltFetched = 0;
1019                 return hResult;
1020             }
1021             rgeltTemp++;
1022             m_iter++;
1023             numToFetch--;
1024         }
1025         if (numAvailable < celt)
1026             return S_FALSE;
1027         return S_OK;
1028     }
1029 
STDMETHOD(Skip)1030     STDMETHOD(Skip)(ULONG celt)
1031     {
1032         ULONG numAvailable;
1033         ULONG numToSkip;
1034 
1035         if (celt == 0)
1036             return E_INVALIDARG;
1037 
1038         numAvailable = static_cast<ULONG>(m_end - m_iter);
1039         if (celt < numAvailable)
1040             numToSkip = celt;
1041         else
1042             numToSkip = numAvailable;
1043         m_iter += numToSkip;
1044         if (numAvailable < celt)
1045             return S_FALSE;
1046         return S_OK;
1047     }
1048 
STDMETHOD(Reset)1049     STDMETHOD(Reset)()
1050     {
1051         m_iter = m_begin;
1052         return S_OK;
1053     }
1054 
STDMETHOD(Clone)1055     STDMETHOD(Clone)(Base **ppEnum)
1056     {
1057         enumeratorClass *newInstance;
1058         HRESULT hResult;
1059 
1060         hResult = E_POINTER;
1061         if (ppEnum != NULL)
1062         {
1063             *ppEnum = NULL;
1064             hResult = enumeratorClass::CreateInstance(&newInstance);
1065             if (SUCCEEDED(hResult))
1066             {
1067                 hResult = newInstance->Init(m_begin, m_end, (m_dwFlags & BitOwn) ? this : m_spUnk);
1068                 if (SUCCEEDED(hResult))
1069                 {
1070                     newInstance->m_iter = m_iter;
1071                     hResult = newInstance->_InternalQueryInterface(*piid, (void **)ppEnum);
1072                 }
1073                 if (FAILED(hResult))
1074                     delete newInstance;
1075             }
1076         }
1077         return hResult;
1078     }
1079 
1080 protected:
1081     enum FlagBits
1082     {
1083         BitCopy = 1,
1084         BitOwn = 2
1085     };
1086 };
1087 
1088 template <class Base, const IID *piid, class T, class Copy, class ThreadModel>
1089 class CComEnum :
1090     public CComEnumImpl<Base, piid, T, Copy>,
1091     public CComObjectRootEx<ThreadModel>
1092 {
1093 public:
1094     typedef CComEnum<Base, piid, T, Copy > _CComEnum;
1095     typedef CComEnumImpl<Base, piid, T, Copy > _CComEnumBase;
1096 
1097     BEGIN_COM_MAP(_CComEnum)
1098         COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase)
1099     END_COM_MAP()
1100 };
1101 
1102 #ifndef _DEFAULT_VECTORLENGTH
1103 #define _DEFAULT_VECTORLENGTH 4
1104 #endif
1105 
1106 class CComDynamicUnkArray
1107 {
1108 public:
1109     int m_nSize;
1110     IUnknown **m_ppUnk;
1111 public:
CComDynamicUnkArray()1112     CComDynamicUnkArray()
1113     {
1114         m_nSize = 0;
1115         m_ppUnk = NULL;
1116     }
1117 
~CComDynamicUnkArray()1118     ~CComDynamicUnkArray()
1119     {
1120         free(m_ppUnk);
1121     }
1122 
begin()1123     IUnknown **begin()
1124     {
1125         return m_ppUnk;
1126     }
1127 
end()1128     IUnknown **end()
1129     {
1130         return &m_ppUnk[m_nSize];
1131     }
1132 
GetAt(int nIndex)1133     IUnknown *GetAt(int nIndex)
1134     {
1135         ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
1136         if (nIndex >= 0 && nIndex < m_nSize)
1137             return m_ppUnk[nIndex];
1138         else
1139             return NULL;
1140     }
1141 
GetUnknown(DWORD dwCookie)1142     IUnknown *WINAPI GetUnknown(DWORD dwCookie)
1143     {
1144         ATLASSERT(dwCookie != 0 && dwCookie <= static_cast<DWORD>(m_nSize));
1145         if (dwCookie != 0 && dwCookie <= static_cast<DWORD>(m_nSize))
1146             return GetAt(dwCookie - 1);
1147         else
1148             return NULL;
1149     }
1150 
GetCookie(IUnknown ** ppFind)1151     DWORD WINAPI GetCookie(IUnknown **ppFind)
1152     {
1153         IUnknown **x;
1154         DWORD curCookie;
1155 
1156         ATLASSERT(ppFind != NULL && *ppFind != NULL);
1157         if (ppFind != NULL && *ppFind != NULL)
1158         {
1159             curCookie = 1;
1160             for (x = begin(); x < end(); x++)
1161             {
1162                 if (*x == *ppFind)
1163                     return curCookie;
1164                 curCookie++;
1165             }
1166         }
1167         return 0;
1168     }
1169 
Add(IUnknown * pUnk)1170     DWORD Add(IUnknown *pUnk)
1171     {
1172         IUnknown **x;
1173         IUnknown **newArray;
1174         int newSize;
1175         DWORD curCookie;
1176 
1177         ATLASSERT(pUnk != NULL);
1178         if (m_nSize == 0)
1179         {
1180             newSize = _DEFAULT_VECTORLENGTH * sizeof(IUnknown *);
1181             ATLTRY(newArray = reinterpret_cast<IUnknown **>(malloc(newSize)));
1182             if (newArray == NULL)
1183                 return 0;
1184             memset(newArray, 0, newSize);
1185             m_ppUnk = newArray;
1186             m_nSize = _DEFAULT_VECTORLENGTH;
1187         }
1188         curCookie = 1;
1189         for (x = begin(); x < end(); x++)
1190         {
1191             if (*x == NULL)
1192             {
1193                 *x = pUnk;
1194                 return curCookie;
1195             }
1196             curCookie++;
1197         }
1198         newSize = m_nSize * 2;
1199         newArray = reinterpret_cast<IUnknown **>(realloc(m_ppUnk, newSize * sizeof(IUnknown *)));
1200         if (newArray == NULL)
1201             return 0;
1202         m_ppUnk = newArray;
1203         memset(&m_ppUnk[m_nSize], 0, (newSize - m_nSize) * sizeof(IUnknown *));
1204         curCookie = m_nSize + 1;
1205         m_nSize = newSize;
1206         m_ppUnk[curCookie - 1] = pUnk;
1207         return curCookie;
1208     }
1209 
Remove(DWORD dwCookie)1210     BOOL Remove(DWORD dwCookie)
1211     {
1212         DWORD index;
1213 
1214         index = dwCookie - 1;
1215         ATLASSERT(index < dwCookie && index < static_cast<DWORD>(m_nSize));
1216         if (index < dwCookie && index < static_cast<DWORD>(m_nSize) && m_ppUnk[index] != NULL)
1217         {
1218             m_ppUnk[index] = NULL;
1219             return TRUE;
1220         }
1221         return FALSE;
1222     }
1223 
1224 private:
1225     CComDynamicUnkArray &operator = (const CComDynamicUnkArray &)
1226     {
1227         return *this;
1228     }
1229 
CComDynamicUnkArray(const CComDynamicUnkArray &)1230     CComDynamicUnkArray(const CComDynamicUnkArray &)
1231     {
1232     }
1233 };
1234 
1235 struct _ATL_CONNMAP_ENTRY
1236 {
1237     DWORD_PTR dwOffset;
1238 };
1239 
1240 template <const IID *piid>
1241 class _ICPLocator
1242 {
1243 public:
1244     STDMETHOD(_LocCPQueryInterface)(REFIID riid, void **ppvObject) = 0;
1245     virtual ULONG STDMETHODCALLTYPE AddRef() = 0;
1246     virtual ULONG STDMETHODCALLTYPE Release() = 0;
1247 };
1248 
1249 template<class T, const IID *piid, class CDV = CComDynamicUnkArray>
1250 class IConnectionPointImpl : public _ICPLocator<piid>
1251 {
1252     typedef CComEnum<IEnumConnections, &IID_IEnumConnections, CONNECTDATA, _Copy<CONNECTDATA> > CComEnumConnections;
1253 public:
1254     CDV m_vec;
1255 public:
~IConnectionPointImpl()1256     ~IConnectionPointImpl()
1257     {
1258         IUnknown **x;
1259 
1260         for (x = m_vec.begin(); x < m_vec.end(); x++)
1261             if (*x != NULL)
1262                 (*x)->Release();
1263     }
1264 
STDMETHOD(_LocCPQueryInterface)1265     STDMETHOD(_LocCPQueryInterface)(REFIID riid, void **ppvObject)
1266     {
1267         IConnectionPointImpl<T, piid, CDV> *pThis;
1268 
1269         pThis = reinterpret_cast<IConnectionPointImpl<T, piid, CDV>*>(this);
1270 
1271         ATLASSERT(ppvObject != NULL);
1272         if (ppvObject == NULL)
1273             return E_POINTER;
1274 
1275         if (InlineIsEqualGUID(riid, IID_IConnectionPoint) || InlineIsEqualUnknown(riid))
1276         {
1277             *ppvObject = this;
1278             pThis->AddRef();
1279             return S_OK;
1280         }
1281         else
1282         {
1283             *ppvObject = NULL;
1284             return E_NOINTERFACE;
1285         }
1286     }
1287 
STDMETHOD(GetConnectionInterface)1288     STDMETHOD(GetConnectionInterface)(IID *piid2)
1289     {
1290         if (piid2 == NULL)
1291             return E_POINTER;
1292         *piid2 = *piid;
1293         return S_OK;
1294     }
1295 
STDMETHOD(GetConnectionPointContainer)1296     STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer **ppCPC)
1297     {
1298         T *pThis;
1299 
1300         pThis = static_cast<T *>(this);
1301         return pThis->QueryInterface(IID_IConnectionPointContainer, reinterpret_cast<void **>(ppCPC));
1302     }
1303 
STDMETHOD(Advise)1304     STDMETHOD(Advise)(IUnknown *pUnkSink, DWORD *pdwCookie)
1305     {
1306         IUnknown *adviseTarget;
1307         IID interfaceID;
1308         HRESULT hResult;
1309 
1310         if (pdwCookie != NULL)
1311             *pdwCookie = 0;
1312         if (pUnkSink == NULL || pdwCookie == NULL)
1313             return E_POINTER;
1314         GetConnectionInterface(&interfaceID);            // can't fail
1315         hResult = pUnkSink->QueryInterface(interfaceID, reinterpret_cast<void **>(&adviseTarget));
1316         if (SUCCEEDED(hResult))
1317         {
1318             *pdwCookie = m_vec.Add(adviseTarget);
1319             if (*pdwCookie != 0)
1320                 hResult = S_OK;
1321             else
1322             {
1323                 adviseTarget->Release();
1324                 hResult = CONNECT_E_ADVISELIMIT;
1325             }
1326         }
1327         else if (hResult == E_NOINTERFACE)
1328             hResult = CONNECT_E_CANNOTCONNECT;
1329         return hResult;
1330     }
1331 
STDMETHOD(Unadvise)1332     STDMETHOD(Unadvise)(DWORD dwCookie)
1333     {
1334         IUnknown *adviseTarget;
1335         HRESULT hResult;
1336 
1337         adviseTarget = m_vec.GetUnknown(dwCookie);
1338         if (m_vec.Remove(dwCookie))
1339         {
1340             if (adviseTarget != NULL)
1341                 adviseTarget->Release();
1342             hResult = S_OK;
1343         }
1344         else
1345             hResult = CONNECT_E_NOCONNECTION;
1346         return hResult;
1347     }
1348 
STDMETHOD(EnumConnections)1349     STDMETHOD(EnumConnections)(IEnumConnections **ppEnum)
1350     {
1351         CComObject<CComEnumConnections> *newEnumerator;
1352         CONNECTDATA *itemBuffer;
1353         CONNECTDATA *itemBufferEnd;
1354         IUnknown **x;
1355         HRESULT hResult;
1356 
1357         ATLASSERT(ppEnum != NULL);
1358         if (ppEnum == NULL)
1359             return E_POINTER;
1360         *ppEnum = NULL;
1361 
1362         ATLTRY(itemBuffer = new CONNECTDATA[m_vec.end() - m_vec.begin()])
1363         if (itemBuffer == NULL)
1364             return E_OUTOFMEMORY;
1365         itemBufferEnd = itemBuffer;
1366         for (x = m_vec.begin(); x < m_vec.end(); x++)
1367         {
1368             if (*x != NULL)
1369             {
1370                 (*x)->AddRef();
1371                 itemBufferEnd->pUnk = *x;
1372                 itemBufferEnd->dwCookie = m_vec.GetCookie(x);
1373                 itemBufferEnd++;
1374             }
1375         }
1376         ATLTRY(newEnumerator = new CComObject<CComEnumConnections>)
1377         if (newEnumerator == NULL)
1378             return E_OUTOFMEMORY;
1379         newEnumerator->Init(itemBuffer, itemBufferEnd, NULL, AtlFlagTakeOwnership);        // can't fail
1380         hResult = newEnumerator->_InternalQueryInterface(IID_IEnumConnections, (void **)ppEnum);
1381         if (FAILED(hResult))
1382             delete newEnumerator;
1383         return hResult;
1384     }
1385 };
1386 
1387 template <class T>
1388 class IConnectionPointContainerImpl : public IConnectionPointContainer
1389 {
1390         typedef const _ATL_CONNMAP_ENTRY * (*handlerFunctionType)(int *);
1391         typedef CComEnum<IEnumConnectionPoints, &IID_IEnumConnectionPoints, IConnectionPoint *, _CopyInterface<IConnectionPoint> >
1392                         CComEnumConnectionPoints;
1393 
1394 public:
STDMETHOD(EnumConnectionPoints)1395     STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints **ppEnum)
1396     {
1397         const _ATL_CONNMAP_ENTRY *entryPtr;
1398         int connectionPointCount;
1399         IConnectionPoint **itemBuffer;
1400         int destIndex;
1401         handlerFunctionType handlerFunction;
1402         CComEnumConnectionPoints *newEnumerator;
1403         HRESULT hResult;
1404 
1405         ATLASSERT(ppEnum != NULL);
1406         if (ppEnum == NULL)
1407             return E_POINTER;
1408         *ppEnum = NULL;
1409 
1410         entryPtr = T::GetConnMap(&connectionPointCount);
1411         ATLTRY(itemBuffer = new IConnectionPoint * [connectionPointCount])
1412         if (itemBuffer == NULL)
1413             return E_OUTOFMEMORY;
1414 
1415         destIndex = 0;
1416         while (entryPtr->dwOffset != static_cast<DWORD_PTR>(-1))
1417         {
1418             if (entryPtr->dwOffset == static_cast<DWORD_PTR>(-2))
1419             {
1420                 entryPtr++;
1421                 handlerFunction = reinterpret_cast<handlerFunctionType>(entryPtr->dwOffset);
1422                 entryPtr = handlerFunction(NULL);
1423             }
1424             else
1425             {
1426                 itemBuffer[destIndex++] = reinterpret_cast<IConnectionPoint *>((char *)this + entryPtr->dwOffset);
1427                 entryPtr++;
1428             }
1429         }
1430 
1431         ATLTRY(newEnumerator = new CComObject<CComEnumConnectionPoints>)
1432         if (newEnumerator == NULL)
1433         {
1434             delete [] itemBuffer;
1435             return E_OUTOFMEMORY;
1436         }
1437 
1438         newEnumerator->Init(&itemBuffer[0], &itemBuffer[destIndex], NULL, AtlFlagTakeOwnership);    // can't fail
1439         hResult = newEnumerator->QueryInterface(IID_IEnumConnectionPoints, (void**)ppEnum);
1440         if (FAILED(hResult))
1441             delete newEnumerator;
1442         return hResult;
1443     }
1444 
STDMETHOD(FindConnectionPoint)1445     STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint **ppCP)
1446     {
1447         IID interfaceID;
1448         const _ATL_CONNMAP_ENTRY *entryPtr;
1449         handlerFunctionType handlerFunction;
1450         IConnectionPoint *connectionPoint;
1451         HRESULT hResult;
1452 
1453         if (ppCP == NULL)
1454             return E_POINTER;
1455         *ppCP = NULL;
1456         hResult = CONNECT_E_NOCONNECTION;
1457         entryPtr = T::GetConnMap(NULL);
1458         while (entryPtr->dwOffset != static_cast<DWORD_PTR>(-1))
1459         {
1460             if (entryPtr->dwOffset == static_cast<DWORD_PTR>(-2))
1461             {
1462                 entryPtr++;
1463                 handlerFunction = reinterpret_cast<handlerFunctionType>(entryPtr->dwOffset);
1464                 entryPtr = handlerFunction(NULL);
1465             }
1466             else
1467             {
1468                 connectionPoint = reinterpret_cast<IConnectionPoint *>(reinterpret_cast<char *>(this) + entryPtr->dwOffset);
1469                 if (SUCCEEDED(connectionPoint->GetConnectionInterface(&interfaceID)) && InlineIsEqualGUID(riid, interfaceID))
1470                 {
1471                     *ppCP = connectionPoint;
1472                     connectionPoint->AddRef();
1473                     hResult = S_OK;
1474                     break;
1475                 }
1476                 entryPtr++;
1477             }
1478         }
1479         return hResult;
1480     }
1481 };
1482 
1483 #define BEGIN_CONNECTION_POINT_MAP(x)                                            \
1484     typedef x _atl_conn_classtype;                                                \
1485     static const ATL::_ATL_CONNMAP_ENTRY *GetConnMap(int *pnEntries) {            \
1486     static const ATL::_ATL_CONNMAP_ENTRY _entries[] = {
1487 
1488 #define END_CONNECTION_POINT_MAP()                                                \
1489     {(DWORD_PTR)-1} };                                                            \
1490     if (pnEntries)                                                                \
1491         *pnEntries = sizeof(_entries) / sizeof(ATL::_ATL_CONNMAP_ENTRY) - 1;    \
1492     return _entries;}
1493 
1494 #define CONNECTION_POINT_ENTRY(iid)                                                \
1495     {offsetofclass(ATL::_ICPLocator<&iid>, _atl_conn_classtype) -                \
1496     offsetofclass(ATL::IConnectionPointContainerImpl<_atl_conn_classtype>, _atl_conn_classtype)},
1497 
1498 
1499 
1500 /* TODO:
1501  - IDispatchImpl contains a static member of type CComTypeInfoHolder that manages the type information for the dual interface.
1502    If you have multiple objects that implement the same dual interface, only one instance of CComTypeInfoHolder is used.
1503  - By default, the IDispatchImpl class looks up the type information for T in the registry.
1504    To implement an unregistered interface, you can use the IDispatchImpl class without accessing the registry by using a predefined version number.
1505    If you create an IDispatchImpl object that has 0xFFFF as the value for wMajor and 0xFFFF as the value for wMinor,
1506    the IDispatchImpl class retrieves the type library from the .dll file instead of the registry.
1507 */
1508 template<class T, const IID* piid /*= &__uuidof(T)*/, const GUID* plibid = &CAtlModule::m_libid, WORD wMajor = 1, WORD wMinor = 0>
1509 class IDispatchImpl :
1510     public T
1511 {
1512 private:
1513     CComPtr<ITypeInfo> m_pTypeInfo;
1514 
STDMETHOD(EnsureTILoaded)1515     STDMETHOD(EnsureTILoaded)(LCID lcid)
1516     {
1517         HRESULT hr = S_OK;
1518         if (m_pTypeInfo != NULL)
1519             return hr;
1520 
1521         if (IsEqualCLSID(CLSID_NULL, *plibid))
1522             OutputDebugStringA("IDispatchImpl: plibid is CLSID_NULL!\r\n");
1523 
1524         // Should we assert here?
1525         if (wMajor == 0xffff && wMinor == 0xffff)
1526             OutputDebugStringA("IDispatchImpl: not fully implemented, missing functionality to load TLB from file!\r\n");
1527 
1528         CComPtr<ITypeLib> spTypeLib;
1529         hr = LoadRegTypeLib(*plibid, wMajor, wMinor, lcid, &spTypeLib);
1530         if (SUCCEEDED(hr))
1531         {
1532             hr = spTypeLib->GetTypeInfoOfGuid(*piid, &m_pTypeInfo);
1533         }
1534         return hr;
1535     }
1536 
1537 public:
IDispatchImpl()1538     IDispatchImpl()
1539     {
1540     }
1541 
1542 
1543     // *** IDispatch methods ***
STDMETHOD(GetTypeInfoCount)1544     STDMETHOD(GetTypeInfoCount)(UINT *pctinfo)
1545     {
1546         if (pctinfo == NULL)
1547             return E_POINTER;
1548 
1549         *pctinfo = 1;
1550         return S_OK;
1551     }
1552 
STDMETHOD(GetTypeInfo)1553     STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
1554     {
1555         if (iTInfo != 0)
1556             return DISP_E_BADINDEX;
1557         if (ppTInfo == NULL)
1558             return E_POINTER;
1559 
1560         HRESULT hr = EnsureTILoaded(lcid);
1561         *ppTInfo = m_pTypeInfo;
1562         if (*ppTInfo)
1563             (*ppTInfo)->AddRef();
1564 
1565         return hr;
1566     }
1567 
STDMETHOD(GetIDsOfNames)1568     STDMETHOD(GetIDsOfNames)(REFIID /*riid*/, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
1569     {
1570         HRESULT hr = EnsureTILoaded(lcid);
1571         if (SUCCEEDED(hr))
1572             hr = m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId);
1573         return hr;
1574     }
1575 
STDMETHOD(Invoke)1576     STDMETHOD(Invoke)(DISPID dispIdMember, REFIID /*riid*/, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
1577     {
1578         HRESULT hr = EnsureTILoaded(lcid);
1579         if (SUCCEEDED(hr))
1580             hr = m_pTypeInfo->Invoke(this, dispIdMember, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1581         return hr;
1582     }
1583 };
1584 
1585 }; // namespace ATL
1586