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