[REACTOS]
[reactos.git] / reactos / lib / atl / atlcom.h
1 /*
2 * ReactOS ATL
3 *
4 * Copyright 2009 Andrew Hill <ash77@reactos.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #pragma once
22
23 namespace ATL
24 {
25
26 template <class Base, const IID *piid, class T, class Copy, class ThreadModel = CComObjectThreadModel>
27 class CComEnum;
28
29 #define DECLARE_CLASSFACTORY_EX(cf) typedef ATL::CComCreator<ATL::CComObjectCached<cf> > _ClassFactoryCreatorClass;
30 #define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory)
31
32 class CComObjectRootBase
33 {
34 public:
35 LONG m_dwRef;
36 public:
37 CComObjectRootBase()
38 {
39 m_dwRef = 0;
40 }
41
42 ~CComObjectRootBase()
43 {
44 }
45
46 void SetVoid(void *)
47 {
48 }
49
50 HRESULT _AtlFinalConstruct()
51 {
52 return S_OK;
53 }
54
55 HRESULT FinalConstruct()
56 {
57 return S_OK;
58 }
59
60 void InternalFinalConstructAddRef()
61 {
62 }
63
64 void InternalFinalConstructRelease()
65 {
66 }
67
68 void FinalRelease()
69 {
70 }
71
72 static void WINAPI ObjectMain(bool)
73 {
74 }
75
76 static const struct _ATL_CATMAP_ENTRY *GetCategoryMap()
77 {
78 return NULL;
79 }
80
81 static HRESULT WINAPI InternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObject)
82 {
83 return AtlInternalQueryInterface(pThis, pEntries, iid, ppvObject);
84 }
85
86 };
87
88 template <class ThreadModel>
89 class CComObjectRootEx : public CComObjectRootBase
90 {
91 private:
92 typename ThreadModel::AutoDeleteCriticalSection m_critsec;
93 public:
94 ~CComObjectRootEx()
95 {
96 }
97
98 ULONG InternalAddRef()
99 {
100 ATLASSERT(m_dwRef >= 0);
101 return ThreadModel::Increment(&m_dwRef);
102 }
103
104 ULONG InternalRelease()
105 {
106 ATLASSERT(m_dwRef > 0);
107 return ThreadModel::Decrement(&m_dwRef);
108 }
109
110 void Lock()
111 {
112 m_critsec.Lock();
113 }
114
115 void Unlock()
116 {
117 m_critsec.Unlock();
118 }
119
120 HRESULT _AtlInitialConstruct()
121 {
122 return m_critsec.Init();
123 }
124 };
125
126 template <class Base>
127 class CComObject : public Base
128 {
129 public:
130 CComObject(void * = NULL)
131 {
132 _pAtlModule->Lock();
133 }
134
135 virtual ~CComObject()
136 {
137 CComObject<Base> *pThis;
138
139 pThis = reinterpret_cast<CComObject<Base> *>(this);
140 pThis->FinalRelease();
141 _pAtlModule->Unlock();
142 }
143
144 STDMETHOD_(ULONG, AddRef)()
145 {
146 CComObject<Base> *pThis;
147
148 pThis = reinterpret_cast<CComObject<Base> *>(this);
149 return pThis->InternalAddRef();
150 }
151
152 STDMETHOD_(ULONG, Release)()
153 {
154 CComObject<Base> *pThis;
155 ULONG l;
156
157 pThis = reinterpret_cast<CComObject<Base> *>(this);
158 l = pThis->InternalRelease();
159 if (l == 0)
160 delete this;
161 return l;
162 }
163
164 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
165 {
166 CComObject<Base> *pThis;
167
168 pThis = reinterpret_cast<CComObject<Base> *>(this);
169 return pThis->_InternalQueryInterface(iid, ppvObject);
170 }
171
172 static HRESULT WINAPI CreateInstance(CComObject<Base> **pp)
173 {
174 CComObject<Base> *newInstance;
175 HRESULT hResult;
176
177 ATLASSERT(pp != NULL);
178 if (pp == NULL)
179 return E_POINTER;
180
181 hResult = E_OUTOFMEMORY;
182 newInstance = NULL;
183 ATLTRY(newInstance = new CComObject<Base>())
184 if (newInstance != NULL)
185 {
186 newInstance->SetVoid(NULL);
187 newInstance->InternalFinalConstructAddRef();
188 hResult = newInstance->_AtlInitialConstruct();
189 if (SUCCEEDED(hResult))
190 hResult = newInstance->FinalConstruct();
191 if (SUCCEEDED(hResult))
192 hResult = newInstance->_AtlFinalConstruct();
193 newInstance->InternalFinalConstructRelease();
194 if (hResult != S_OK)
195 {
196 delete newInstance;
197 newInstance = NULL;
198 }
199 }
200 *pp = newInstance;
201 return hResult;
202 }
203
204
205 };
206
207 template <HRESULT hResult>
208 class CComFailCreator
209 {
210 public:
211 static HRESULT WINAPI CreateInstance(void *, REFIID, LPVOID *ppv)
212 {
213 ATLASSERT(ppv != NULL);
214 if (ppv == NULL)
215 return E_POINTER;
216 *ppv = NULL;
217
218 return hResult;
219 }
220 };
221
222 template <class T1>
223 class CComCreator
224 {
225 public:
226 static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, LPVOID *ppv)
227 {
228 T1 *newInstance;
229 HRESULT hResult;
230
231 ATLASSERT(ppv != NULL);
232 if (ppv == NULL)
233 return E_POINTER;
234 *ppv = NULL;
235
236 hResult = E_OUTOFMEMORY;
237 newInstance = NULL;
238 ATLTRY(newInstance = new T1())
239 if (newInstance != NULL)
240 {
241 newInstance->SetVoid(pv);
242 newInstance->InternalFinalConstructAddRef();
243 hResult = newInstance->_AtlInitialConstruct();
244 if (SUCCEEDED(hResult))
245 hResult = newInstance->FinalConstruct();
246 if (SUCCEEDED(hResult))
247 hResult = newInstance->_AtlFinalConstruct();
248 newInstance->InternalFinalConstructRelease();
249 if (SUCCEEDED(hResult))
250 hResult = newInstance->QueryInterface(riid, ppv);
251 if (FAILED(hResult))
252 {
253 delete newInstance;
254 newInstance = NULL;
255 }
256 }
257 return hResult;
258 }
259 };
260
261 template <class T1, class T2>
262 class CComCreator2
263 {
264 public:
265 static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, LPVOID *ppv)
266 {
267 ATLASSERT(ppv != NULL && ppv != NULL);
268
269 if (pv == NULL)
270 return T1::CreateInstance(NULL, riid, ppv);
271 else
272 return T2::CreateInstance(pv, riid, ppv);
273 }
274 };
275
276 template <class Base>
277 class CComObjectCached : public Base
278 {
279 public:
280 CComObjectCached(void * = NULL)
281 {
282 }
283
284 STDMETHOD_(ULONG, AddRef)()
285 {
286 CComObjectCached<Base> *pThis;
287 ULONG newRefCount;
288
289 pThis = reinterpret_cast<CComObjectCached<Base>*>(this);
290 newRefCount = pThis->InternalAddRef();
291 if (newRefCount == 2)
292 _pAtlModule->Lock();
293 return newRefCount;
294 }
295
296 STDMETHOD_(ULONG, Release)()
297 {
298 CComObjectCached<Base> *pThis;
299 ULONG newRefCount;
300
301 pThis = reinterpret_cast<CComObjectCached<Base>*>(this);
302 newRefCount = pThis->InternalRelease();
303 if (newRefCount == 0)
304 delete this;
305 else if (newRefCount == 1)
306 _pAtlModule->Unlock();
307 return newRefCount;
308 }
309
310 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
311 {
312 CComObjectCached<Base> *pThis;
313
314 pThis = reinterpret_cast<CComObjectCached<Base>*>(this);
315 return pThis->_InternalQueryInterface(iid, ppvObject);
316 }
317 };
318
319 #define BEGIN_COM_MAP(x) \
320 public: \
321 typedef x _ComMapClass; \
322 HRESULT _InternalQueryInterface(REFIID iid, void **ppvObject) \
323 { \
324 return this->InternalQueryInterface(this, _GetEntries(), iid, ppvObject); \
325 } \
326 const static ATL::_ATL_INTMAP_ENTRY *WINAPI _GetEntries() \
327 { \
328 static const ATL::_ATL_INTMAP_ENTRY _entries[] = {
329
330 #define END_COM_MAP() \
331 {NULL, 0, 0} \
332 }; \
333 return _entries; \
334 } \
335 virtual ULONG STDMETHODCALLTYPE AddRef() = 0; \
336 virtual ULONG STDMETHODCALLTYPE Release() = 0; \
337 STDMETHOD(QueryInterface)(REFIID, void **) = 0;
338
339 #define COM_INTERFACE_ENTRY_IID(iid, x) \
340 {&iid, offsetofclass(x, _ComMapClass), _ATL_SIMPLEMAPENTRY},
341
342 #define COM_INTERFACE_ENTRY2_IID(iid, x, x2) \
343 {&iid, \
344 reinterpret_cast<DWORD_PTR>(static_cast<x *>(static_cast<x2 *>(reinterpret_cast<_ComMapClass *>(_ATL_PACKING)))) - _ATL_PACKING, \
345 _ATL_SIMPLEMAPENTRY},
346
347 #define COM_INTERFACE_ENTRY_BREAK(x) \
348 {&_ATL_IIDOF(x), \
349 NULL, \
350 _Break}, // Break is a function that issues int 3.
351
352 #define COM_INTERFACE_ENTRY_NOINTERFACE(x) \
353 {&_ATL_IIDOF(x), \
354 NULL, \
355 _NoInterface}, // NoInterface returns E_NOINTERFACE.
356
357 #define COM_INTERFACE_ENTRY_FUNC(iid, dw, func) \
358 {&iid, \
359 dw, \
360 func},
361
362 #define COM_INTERFACE_ENTRY_FUNC_BLIND(dw, func) \
363 {NULL, \
364 dw, \
365 func},
366
367 #define COM_INTERFACE_ENTRY_CHAIN(classname) \
368 {NULL, \
369 reinterpret_cast<DWORD>(&_CComChainData<classname, _ComMapClass>::data), \
370 _Chain},
371
372 #define DECLARE_NO_REGISTRY()\
373 static HRESULT WINAPI UpdateRegistry(BOOL /*bRegister*/) \
374 { \
375 return S_OK; \
376 }
377
378 #define DECLARE_REGISTRY_RESOURCEID(x) \
379 static HRESULT WINAPI UpdateRegistry(BOOL bRegister) \
380 { \
381 return ATL::_pAtlModule->UpdateRegistryFromResource(x, bRegister); \
382 }
383
384 #define DECLARE_NOT_AGGREGATABLE(x) \
385 public: \
386 typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<x> >, ATL::CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass;
387
388 #define DECLARE_AGGREGATABLE(x) \
389 public: \
390 typedef CComCreator2<CComCreator<CComObject<x> >, CComCreator<CComAggObject<x> > > _CreatorClass;
391
392 #define DECLARE_ONLY_AGGREGATABLE(x) \
393 public: \
394 typedef CComCreator2<CComFailCreator<E_FAIL>, CComCreator<CComAggObject<x> > > _CreatorClass;
395
396 #define DECLARE_POLY_AGGREGATABLE(x) \
397 public: \
398 typedef CComCreator<CComPolyObject<x> > _CreatorClass;
399
400 #define DECLARE_GET_CONTROLLING_UNKNOWN() \
401 public: \
402 virtual IUnknown *GetControllingUnknown() \
403 { \
404 return GetUnknown(); \
405 }
406
407 #define DECLARE_PROTECT_FINAL_CONSTRUCT() \
408 void InternalFinalConstructAddRef() \
409 { \
410 InternalAddRef(); \
411 } \
412 void InternalFinalConstructRelease() \
413 { \
414 InternalRelease(); \
415 }
416
417 #define BEGIN_OBJECT_MAP(x) static ATL::_ATL_OBJMAP_ENTRY x[] = {
418
419 #define END_OBJECT_MAP() {NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL}};
420
421 #define OBJECT_ENTRY(clsid, class) \
422 { \
423 &clsid, \
424 class::UpdateRegistry, \
425 class::_ClassFactoryCreatorClass::CreateInstance, \
426 class::_CreatorClass::CreateInstance, \
427 NULL, \
428 0, \
429 class::GetObjectDescription, \
430 class::GetCategoryMap, \
431 class::ObjectMain },
432
433 class CComClassFactory :
434 public IClassFactory,
435 public CComObjectRootEx<CComGlobalsThreadModel>
436 {
437 public:
438 _ATL_CREATORFUNC *m_pfnCreateInstance;
439 public:
440 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj)
441 {
442 HRESULT hResult;
443
444 ATLASSERT(m_pfnCreateInstance != NULL);
445
446 if (ppvObj == NULL)
447 return E_POINTER;
448 *ppvObj = NULL;
449
450 if (pUnkOuter != NULL && InlineIsEqualUnknown(riid) == FALSE)
451 hResult = CLASS_E_NOAGGREGATION;
452 else
453 hResult = m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
454 return hResult;
455 }
456
457 STDMETHOD(LockServer)(BOOL fLock)
458 {
459 if (fLock)
460 _pAtlModule->Lock();
461 else
462 _pAtlModule->Unlock();
463 return S_OK;
464 }
465
466 void SetVoid(void *pv)
467 {
468 m_pfnCreateInstance = (_ATL_CREATORFUNC *)pv;
469 }
470
471 BEGIN_COM_MAP(CComClassFactory)
472 COM_INTERFACE_ENTRY_IID(IID_IClassFactory, IClassFactory)
473 END_COM_MAP()
474 };
475
476 template <class T, const CLSID *pclsid = &CLSID_NULL>
477 class CComCoClass
478 {
479 public:
480 DECLARE_CLASSFACTORY()
481
482 static LPCTSTR WINAPI GetObjectDescription()
483 {
484 return NULL;
485 }
486 };
487
488 template <class T>
489 class _Copy
490 {
491 public:
492 static HRESULT copy(T *pTo, const T *pFrom)
493 {
494 memcpy(pTo, pFrom, sizeof(T));
495 return S_OK;
496 }
497
498 static void init(T *)
499 {
500 }
501
502 static void destroy(T *)
503 {
504 }
505 };
506
507 template<>
508 class _Copy<CONNECTDATA>
509 {
510 public:
511 static HRESULT copy(CONNECTDATA *pTo, const CONNECTDATA *pFrom)
512 {
513 *pTo = *pFrom;
514 if (pTo->pUnk)
515 pTo->pUnk->AddRef();
516 return S_OK;
517 }
518
519 static void init(CONNECTDATA *)
520 {
521 }
522
523 static void destroy(CONNECTDATA *p)
524 {
525 if (p->pUnk)
526 p->pUnk->Release();
527 }
528 };
529
530 template <class T>
531 class _CopyInterface
532 {
533 public:
534 static HRESULT copy(T **pTo, T **pFrom)
535 {
536 *pTo = *pFrom;
537 if (*pTo)
538 (*pTo)->AddRef();
539 return S_OK;
540 }
541
542 static void init(T **)
543 {
544 }
545
546 static void destroy(T **p)
547 {
548 if (*p)
549 (*p)->Release();
550 }
551 };
552
553 enum CComEnumFlags
554 {
555 AtlFlagNoCopy = 0,
556 AtlFlagTakeOwnership = 2, // BitOwn
557 AtlFlagCopy = 3 // BitOwn | BitCopy
558 };
559
560 template <class Base, const IID *piid, class T, class Copy>
561 class CComEnumImpl : public Base
562 {
563 private:
564 typedef CComObject<CComEnum<Base, piid, T, Copy> > enumeratorClass;
565 public:
566 CComPtr<IUnknown> m_spUnk;
567 DWORD m_dwFlags;
568 T *m_begin;
569 T *m_end;
570 T *m_iter;
571 public:
572 CComEnumImpl()
573 {
574 m_dwFlags = 0;
575 m_begin = NULL;
576 m_end = NULL;
577 m_iter = NULL;
578 }
579
580 virtual ~CComEnumImpl()
581 {
582 T *x;
583
584 if ((m_dwFlags & BitOwn) != 0)
585 {
586 for (x = m_begin; x != m_end; x++)
587 Copy::destroy(x);
588 delete [] m_begin;
589 }
590 }
591
592 HRESULT Init(T *begin, T *end, IUnknown *pUnk, CComEnumFlags flags = AtlFlagNoCopy)
593 {
594 T *newBuffer;
595 T *sourcePtr;
596 T *destPtr;
597 T *cleanupPtr;
598 HRESULT hResult;
599
600 if (flags == AtlFlagCopy)
601 {
602 ATLTRY(newBuffer = new T[end - begin])
603 if (newBuffer == NULL)
604 return E_OUTOFMEMORY;
605 destPtr = newBuffer;
606 for (sourcePtr = begin; sourcePtr != end; sourcePtr++)
607 {
608 Copy::init(destPtr);
609 hResult = Copy::copy(destPtr, sourcePtr);
610 if (FAILED(hResult))
611 {
612 cleanupPtr = m_begin;
613 while (cleanupPtr < destPtr)
614 Copy::destroy(cleanupPtr++);
615 delete [] newBuffer;
616 return hResult;
617 }
618 destPtr++;
619 }
620 m_begin = newBuffer;
621 m_end = m_begin + (end - begin);
622 }
623 else
624 {
625 m_begin = begin;
626 m_end = end;
627 }
628 m_spUnk = pUnk;
629 m_dwFlags = flags;
630 m_iter = m_begin;
631 return S_OK;
632 }
633
634 STDMETHOD(Next)(ULONG celt, T *rgelt, ULONG *pceltFetched)
635 {
636 ULONG numAvailable;
637 ULONG numToFetch;
638 T *rgeltTemp;
639 HRESULT hResult;
640
641 if (pceltFetched != NULL)
642 *pceltFetched = 0;
643 if (celt == 0)
644 return E_INVALIDARG;
645 if (rgelt == NULL || (celt != 1 && pceltFetched == NULL))
646 return E_POINTER;
647 if (m_begin == NULL || m_end == NULL || m_iter == NULL)
648 return E_FAIL;
649
650 numAvailable = static_cast<ULONG>(m_end - m_iter);
651 if (celt < numAvailable)
652 numToFetch = celt;
653 else
654 numToFetch = numAvailable;
655 if (pceltFetched != NULL)
656 *pceltFetched = numToFetch;
657 rgeltTemp = rgelt;
658 while (numToFetch != 0)
659 {
660 hResult = Copy::copy(rgeltTemp, m_iter);
661 if (FAILED(hResult))
662 {
663 while (rgelt < rgeltTemp)
664 Copy::destroy(rgelt++);
665 if (pceltFetched != NULL)
666 *pceltFetched = 0;
667 return hResult;
668 }
669 rgeltTemp++;
670 m_iter++;
671 numToFetch--;
672 }
673 if (numAvailable < celt)
674 return S_FALSE;
675 return S_OK;
676 }
677
678 STDMETHOD(Skip)(ULONG celt)
679 {
680 ULONG numAvailable;
681 ULONG numToSkip;
682
683 if (celt == 0)
684 return E_INVALIDARG;
685
686 numAvailable = static_cast<ULONG>(m_end - m_iter);
687 if (celt < numAvailable)
688 numToSkip = celt;
689 else
690 numToSkip = numAvailable;
691 m_iter += numToSkip;
692 if (numAvailable < celt)
693 return S_FALSE;
694 return S_OK;
695 }
696
697 STDMETHOD(Reset)()
698 {
699 m_iter = m_begin;
700 return S_OK;
701 }
702
703 STDMETHOD(Clone)(Base **ppEnum)
704 {
705 enumeratorClass *newInstance;
706 HRESULT hResult;
707
708 hResult = E_POINTER;
709 if (ppEnum != NULL)
710 {
711 *ppEnum = NULL;
712 hResult = enumeratorClass::CreateInstance(&newInstance);
713 if (SUCCEEDED(hResult))
714 {
715 hResult = newInstance->Init(m_begin, m_end, (m_dwFlags & BitOwn) ? this : m_spUnk);
716 if (SUCCEEDED(hResult))
717 {
718 newInstance->m_iter = m_iter;
719 hResult = newInstance->_InternalQueryInterface(*piid, (void **)ppEnum);
720 }
721 if (FAILED(hResult))
722 delete newInstance;
723 }
724 }
725 return hResult;
726 }
727
728 protected:
729 enum FlagBits
730 {
731 BitCopy = 1,
732 BitOwn = 2
733 };
734 };
735
736 template <class Base, const IID *piid, class T, class Copy, class ThreadModel>
737 class CComEnum :
738 public CComEnumImpl<Base, piid, T, Copy>,
739 public CComObjectRootEx<ThreadModel>
740 {
741 public:
742 typedef CComEnum<Base, piid, T, Copy > _CComEnum;
743 typedef CComEnumImpl<Base, piid, T, Copy > _CComEnumBase;
744
745 BEGIN_COM_MAP(_CComEnum)
746 COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase)
747 END_COM_MAP()
748 };
749
750 #ifndef _DEFAULT_VECTORLENGTH
751 #define _DEFAULT_VECTORLENGTH 4
752 #endif
753
754 class CComDynamicUnkArray
755 {
756 public:
757 int m_nSize;
758 IUnknown **m_ppUnk;
759 public:
760 CComDynamicUnkArray()
761 {
762 m_nSize = 0;
763 m_ppUnk = NULL;
764 }
765
766 ~CComDynamicUnkArray()
767 {
768 free(m_ppUnk);
769 }
770
771 IUnknown **begin()
772 {
773 return m_ppUnk;
774 }
775
776 IUnknown **end()
777 {
778 return &m_ppUnk[m_nSize];
779 }
780
781 IUnknown *GetAt(int nIndex)
782 {
783 ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
784 if (nIndex >= 0 && nIndex < m_nSize)
785 return m_ppUnk[nIndex];
786 else
787 return NULL;
788 }
789
790 IUnknown *WINAPI GetUnknown(DWORD dwCookie)
791 {
792 ATLASSERT(dwCookie != 0 && dwCookie <= static_cast<DWORD>(m_nSize));
793 if (dwCookie != 0 && dwCookie <= static_cast<DWORD>(m_nSize))
794 return GetAt(dwCookie - 1);
795 else
796 return NULL;
797 }
798
799 DWORD WINAPI GetCookie(IUnknown **ppFind)
800 {
801 IUnknown **x;
802 DWORD curCookie;
803
804 ATLASSERT(ppFind != NULL && *ppFind != NULL);
805 if (ppFind != NULL && *ppFind != NULL)
806 {
807 curCookie = 1;
808 for (x = begin(); x < end(); x++)
809 {
810 if (*x == *ppFind)
811 return curCookie;
812 curCookie++;
813 }
814 }
815 return 0;
816 }
817
818 DWORD Add(IUnknown *pUnk)
819 {
820 IUnknown **x;
821 IUnknown **newArray;
822 int newSize;
823 DWORD curCookie;
824
825 ATLASSERT(pUnk != NULL);
826 if (m_nSize == 0)
827 {
828 newSize = _DEFAULT_VECTORLENGTH * sizeof(IUnknown *);
829 ATLTRY(newArray = reinterpret_cast<IUnknown **>(malloc(newSize)));
830 if (newArray == NULL)
831 return 0;
832 memset(newArray, 0, newSize);
833 m_ppUnk = newArray;
834 m_nSize = _DEFAULT_VECTORLENGTH;
835 }
836 curCookie = 1;
837 for (x = begin(); x < end(); x++)
838 {
839 if (*x == NULL)
840 {
841 *x = pUnk;
842 return curCookie;
843 }
844 curCookie++;
845 }
846 newSize = m_nSize * 2;
847 newArray = reinterpret_cast<IUnknown **>(realloc(m_ppUnk, newSize * sizeof(IUnknown *)));
848 if (newArray == NULL)
849 return 0;
850 m_ppUnk = newArray;
851 memset(&m_ppUnk[m_nSize], 0, (newSize - m_nSize) * sizeof(IUnknown *));
852 curCookie = m_nSize + 1;
853 m_nSize = newSize;
854 m_ppUnk[curCookie - 1] = pUnk;
855 return curCookie;
856 }
857
858 BOOL Remove(DWORD dwCookie)
859 {
860 DWORD index;
861
862 index = dwCookie - 1;
863 ATLASSERT(index < dwCookie && index < static_cast<DWORD>(m_nSize));
864 if (index < dwCookie && index < static_cast<DWORD>(m_nSize) && m_ppUnk[index] != NULL)
865 {
866 m_ppUnk[index] = NULL;
867 return TRUE;
868 }
869 return FALSE;
870 }
871
872 private:
873 CComDynamicUnkArray &operator = (const CComDynamicUnkArray &)
874 {
875 return *this;
876 }
877
878 CComDynamicUnkArray(const CComDynamicUnkArray &)
879 {
880 }
881 };
882
883 struct _ATL_CONNMAP_ENTRY
884 {
885 DWORD_PTR dwOffset;
886 };
887
888 template <const IID *piid>
889 class _ICPLocator
890 {
891 public:
892 STDMETHOD(_LocCPQueryInterface)(REFIID riid, void **ppvObject) = 0;
893 virtual ULONG STDMETHODCALLTYPE AddRef() = 0;
894 virtual ULONG STDMETHODCALLTYPE Release() = 0;
895 };
896
897 template<class T, const IID *piid, class CDV = CComDynamicUnkArray>
898 class IConnectionPointImpl : public _ICPLocator<piid>
899 {
900 typedef CComEnum<IEnumConnections, &IID_IEnumConnections, CONNECTDATA, _Copy<CONNECTDATA> > CComEnumConnections;
901 public:
902 CDV m_vec;
903 public:
904 ~IConnectionPointImpl()
905 {
906 IUnknown **x;
907
908 for (x = m_vec.begin(); x < m_vec.end(); x++)
909 if (*x != NULL)
910 (*x)->Release();
911 }
912
913 STDMETHOD(_LocCPQueryInterface)(REFIID riid, void **ppvObject)
914 {
915 IConnectionPointImpl<T, piid, CDV> *pThis;
916
917 pThis = reinterpret_cast<IConnectionPointImpl<T, piid, CDV>*>(this);
918
919 ATLASSERT(ppvObject != NULL);
920 if (ppvObject == NULL)
921 return E_POINTER;
922
923 if (InlineIsEqualGUID(riid, IID_IConnectionPoint) || InlineIsEqualUnknown(riid))
924 {
925 *ppvObject = this;
926 pThis->AddRef();
927 return S_OK;
928 }
929 else
930 {
931 *ppvObject = NULL;
932 return E_NOINTERFACE;
933 }
934 }
935
936 STDMETHOD(GetConnectionInterface)(IID *piid2)
937 {
938 if (piid2 == NULL)
939 return E_POINTER;
940 *piid2 = *piid;
941 return S_OK;
942 }
943
944 STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer **ppCPC)
945 {
946 T *pThis;
947
948 pThis = static_cast<T *>(this);
949 return pThis->QueryInterface(IID_IConnectionPointContainer, reinterpret_cast<void **>(ppCPC));
950 }
951
952 STDMETHOD(Advise)(IUnknown *pUnkSink, DWORD *pdwCookie)
953 {
954 IUnknown *adviseTarget;
955 IID interfaceID;
956 HRESULT hResult;
957
958 if (pdwCookie != NULL)
959 *pdwCookie = 0;
960 if (pUnkSink == NULL || pdwCookie == NULL)
961 return E_POINTER;
962 GetConnectionInterface(&interfaceID); // can't fail
963 hResult = pUnkSink->QueryInterface(interfaceID, reinterpret_cast<void **>(&adviseTarget));
964 if (SUCCEEDED(hResult))
965 {
966 *pdwCookie = m_vec.Add(adviseTarget);
967 if (*pdwCookie != 0)
968 hResult = S_OK;
969 else
970 {
971 adviseTarget->Release();
972 hResult = CONNECT_E_ADVISELIMIT;
973 }
974 }
975 else if (hResult == E_NOINTERFACE)
976 hResult = CONNECT_E_CANNOTCONNECT;
977 return hResult;
978 }
979
980 STDMETHOD(Unadvise)(DWORD dwCookie)
981 {
982 IUnknown *adviseTarget;
983 HRESULT hResult;
984
985 adviseTarget = m_vec.GetUnknown(dwCookie);
986 if (m_vec.Remove(dwCookie))
987 {
988 if (adviseTarget != NULL)
989 adviseTarget->Release();
990 hResult = S_OK;
991 }
992 else
993 hResult = CONNECT_E_NOCONNECTION;
994 return hResult;
995 }
996
997 STDMETHOD(EnumConnections)(IEnumConnections **ppEnum)
998 {
999 CComObject<CComEnumConnections> *newEnumerator;
1000 CONNECTDATA *itemBuffer;
1001 CONNECTDATA *itemBufferEnd;
1002 IUnknown **x;
1003 HRESULT hResult;
1004
1005 ATLASSERT(ppEnum != NULL);
1006 if (ppEnum == NULL)
1007 return E_POINTER;
1008 *ppEnum = NULL;
1009
1010 ATLTRY(itemBuffer = new CONNECTDATA[m_vec.end() - m_vec.begin()])
1011 if (itemBuffer == NULL)
1012 return E_OUTOFMEMORY;
1013 itemBufferEnd = itemBuffer;
1014 for (x = m_vec.begin(); x < m_vec.end(); x++)
1015 {
1016 if (*x != NULL)
1017 {
1018 (*x)->AddRef();
1019 itemBufferEnd->pUnk = *x;
1020 itemBufferEnd->dwCookie = m_vec.GetCookie(x);
1021 itemBufferEnd++;
1022 }
1023 }
1024 ATLTRY(newEnumerator = new CComObject<CComEnumConnections>)
1025 if (newEnumerator == NULL)
1026 return E_OUTOFMEMORY;
1027 newEnumerator->Init(itemBuffer, itemBufferEnd, NULL, AtlFlagTakeOwnership); // can't fail
1028 hResult = newEnumerator->_InternalQueryInterface(IID_IEnumConnections, (void **)ppEnum);
1029 if (FAILED(hResult))
1030 delete newEnumerator;
1031 return hResult;
1032 }
1033 };
1034
1035 template <class T>
1036 class IConnectionPointContainerImpl : public IConnectionPointContainer
1037 {
1038 typedef const _ATL_CONNMAP_ENTRY * (*handlerFunctionType)(int *);
1039 typedef CComEnum<IEnumConnectionPoints, &IID_IEnumConnectionPoints, IConnectionPoint *, _CopyInterface<IConnectionPoint> >
1040 CComEnumConnectionPoints;
1041
1042 public:
1043 STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints **ppEnum)
1044 {
1045 const _ATL_CONNMAP_ENTRY *entryPtr;
1046 int connectionPointCount;
1047 IConnectionPoint **itemBuffer;
1048 int destIndex;
1049 handlerFunctionType handlerFunction;
1050 CComEnumConnectionPoints *newEnumerator;
1051 HRESULT hResult;
1052
1053 ATLASSERT(ppEnum != NULL);
1054 if (ppEnum == NULL)
1055 return E_POINTER;
1056 *ppEnum = NULL;
1057
1058 entryPtr = T::GetConnMap(&connectionPointCount);
1059 ATLTRY(itemBuffer = new IConnectionPoint * [connectionPointCount])
1060 if (itemBuffer == NULL)
1061 return E_OUTOFMEMORY;
1062
1063 destIndex = 0;
1064 while (entryPtr->dwOffset != static_cast<DWORD_PTR>(-1))
1065 {
1066 if (entryPtr->dwOffset == static_cast<DWORD_PTR>(-2))
1067 {
1068 entryPtr++;
1069 handlerFunction = reinterpret_cast<handlerFunctionType>(entryPtr->dwOffset);
1070 entryPtr = handlerFunction(NULL);
1071 }
1072 else
1073 {
1074 itemBuffer[destIndex++] = reinterpret_cast<IConnectionPoint *>((char *)this + entryPtr->dwOffset);
1075 entryPtr++;
1076 }
1077 }
1078
1079 ATLTRY(newEnumerator = new CComObject<CComEnumConnectionPoints>)
1080 if (newEnumerator == NULL)
1081 {
1082 delete [] itemBuffer;
1083 return E_OUTOFMEMORY;
1084 }
1085
1086 newEnumerator->Init(&itemBuffer[0], &itemBuffer[destIndex], NULL, AtlFlagTakeOwnership); // can't fail
1087 hResult = newEnumerator->QueryInterface(IID_IEnumConnectionPoints, (void**)ppEnum);
1088 if (FAILED(hResult))
1089 delete newEnumerator;
1090 return hResult;
1091 }
1092
1093 STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint **ppCP)
1094 {
1095 IID interfaceID;
1096 const _ATL_CONNMAP_ENTRY *entryPtr;
1097 handlerFunctionType handlerFunction;
1098 IConnectionPoint *connectionPoint;
1099 HRESULT hResult;
1100
1101 if (ppCP == NULL)
1102 return E_POINTER;
1103 *ppCP = NULL;
1104 hResult = CONNECT_E_NOCONNECTION;
1105 entryPtr = T::GetConnMap(NULL);
1106 while (entryPtr->dwOffset != static_cast<DWORD_PTR>(-1))
1107 {
1108 if (entryPtr->dwOffset == static_cast<DWORD_PTR>(-2))
1109 {
1110 entryPtr++;
1111 handlerFunction = reinterpret_cast<handlerFunctionType>(entryPtr->dwOffset);
1112 entryPtr = handlerFunction(NULL);
1113 }
1114 else
1115 {
1116 connectionPoint = reinterpret_cast<IConnectionPoint *>(reinterpret_cast<char *>(this) + entryPtr->dwOffset);
1117 if (SUCCEEDED(connectionPoint->GetConnectionInterface(&interfaceID)) && InlineIsEqualGUID(riid, interfaceID))
1118 {
1119 *ppCP = connectionPoint;
1120 connectionPoint->AddRef();
1121 hResult = S_OK;
1122 break;
1123 }
1124 entryPtr++;
1125 }
1126 }
1127 return hResult;
1128 }
1129 };
1130
1131 #define BEGIN_CONNECTION_POINT_MAP(x) \
1132 typedef x _atl_conn_classtype; \
1133 static const ATL::_ATL_CONNMAP_ENTRY *GetConnMap(int *pnEntries) { \
1134 static const ATL::_ATL_CONNMAP_ENTRY _entries[] = {
1135
1136 #define END_CONNECTION_POINT_MAP() \
1137 {(DWORD_PTR)-1} }; \
1138 if (pnEntries) \
1139 *pnEntries = sizeof(_entries) / sizeof(ATL::_ATL_CONNMAP_ENTRY) - 1; \
1140 return _entries;}
1141
1142 #define CONNECTION_POINT_ENTRY(iid) \
1143 {offsetofclass(ATL::_ICPLocator<&iid>, _atl_conn_classtype) - \
1144 offsetofclass(ATL::IConnectionPointContainerImpl<_atl_conn_classtype>, _atl_conn_classtype)},
1145
1146 }; // namespace ATL