[CMAKE]
[reactos.git] / 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 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_REGISTRY_RESOURCEID(x)\
373 static HRESULT WINAPI UpdateRegistry(BOOL bRegister)\
374 {\
375 return ATL::_pAtlModule->UpdateRegistryFromResource(x, bRegister); \
376 }
377
378 #define DECLARE_NOT_AGGREGATABLE(x) \
379 public: \
380 typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<x> >, ATL::CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass;
381
382 #define DECLARE_AGGREGATABLE(x) \
383 public: \
384 typedef CComCreator2<CComCreator<CComObject<x> >, CComCreator<CComAggObject<x> > > _CreatorClass;
385
386 #define DECLARE_ONLY_AGGREGATABLE(x) \
387 public: \
388 typedef CComCreator2<CComFailCreator<E_FAIL>, CComCreator<CComAggObject<x> > > _CreatorClass;
389
390 #define DECLARE_POLY_AGGREGATABLE(x) \
391 public: \
392 typedef CComCreator<CComPolyObject<x> > _CreatorClass;
393
394 #define DECLARE_GET_CONTROLLING_UNKNOWN() \
395 public: \
396 virtual IUnknown *GetControllingUnknown() \
397 { \
398 return GetUnknown(); \
399 }
400
401 #define DECLARE_PROTECT_FINAL_CONSTRUCT() \
402 void InternalFinalConstructAddRef() \
403 { \
404 InternalAddRef(); \
405 } \
406 void InternalFinalConstructRelease() \
407 { \
408 InternalRelease(); \
409 }
410
411 #define BEGIN_OBJECT_MAP(x) static ATL::_ATL_OBJMAP_ENTRY x[] = {
412
413 #define END_OBJECT_MAP() {NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL}};
414
415 #define OBJECT_ENTRY(clsid, class) \
416 { \
417 &clsid, \
418 class::UpdateRegistry, \
419 class::_ClassFactoryCreatorClass::CreateInstance, \
420 class::_CreatorClass::CreateInstance, \
421 NULL, \
422 0, \
423 class::GetObjectDescription, \
424 class::GetCategoryMap, \
425 class::ObjectMain },
426
427 class CComClassFactory :
428 public IClassFactory,
429 public CComObjectRootEx<CComGlobalsThreadModel>
430 {
431 public:
432 _ATL_CREATORFUNC *m_pfnCreateInstance;
433 public:
434 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj)
435 {
436 HRESULT hResult;
437
438 ATLASSERT(m_pfnCreateInstance != NULL);
439
440 if (ppvObj == NULL)
441 return E_POINTER;
442 *ppvObj = NULL;
443
444 if (pUnkOuter != NULL && InlineIsEqualUnknown(riid) == FALSE)
445 hResult = CLASS_E_NOAGGREGATION;
446 else
447 hResult = m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
448 return hResult;
449 }
450
451 STDMETHOD(LockServer)(BOOL fLock)
452 {
453 if (fLock)
454 _pAtlModule->Lock();
455 else
456 _pAtlModule->Unlock();
457 return S_OK;
458 }
459
460 void SetVoid(void *pv)
461 {
462 m_pfnCreateInstance = (_ATL_CREATORFUNC *)pv;
463 }
464
465 BEGIN_COM_MAP(CComClassFactory)
466 COM_INTERFACE_ENTRY_IID(IID_IClassFactory, IClassFactory)
467 END_COM_MAP()
468 };
469
470 template <class T, const CLSID *pclsid = &CLSID_NULL>
471 class CComCoClass
472 {
473 public:
474 DECLARE_CLASSFACTORY()
475
476 static LPCTSTR WINAPI GetObjectDescription()
477 {
478 return NULL;
479 }
480 };
481
482 template <class T>
483 class _Copy
484 {
485 public:
486 static HRESULT copy(T *pTo, const T *pFrom)
487 {
488 memcpy(pTo, pFrom, sizeof(T));
489 return S_OK;
490 }
491
492 static void init(T *)
493 {
494 }
495
496 static void destroy(T *)
497 {
498 }
499 };
500
501 template<>
502 class _Copy<CONNECTDATA>
503 {
504 public:
505 static HRESULT copy(CONNECTDATA *pTo, const CONNECTDATA *pFrom)
506 {
507 *pTo = *pFrom;
508 if (pTo->pUnk)
509 pTo->pUnk->AddRef();
510 return S_OK;
511 }
512
513 static void init(CONNECTDATA *)
514 {
515 }
516
517 static void destroy(CONNECTDATA *p)
518 {
519 if (p->pUnk)
520 p->pUnk->Release();
521 }
522 };
523
524 template <class T>
525 class _CopyInterface
526 {
527 public:
528 static HRESULT copy(T **pTo, T **pFrom)
529 {
530 *pTo = *pFrom;
531 if (*pTo)
532 (*pTo)->AddRef();
533 return S_OK;
534 }
535
536 static void init(T **)
537 {
538 }
539
540 static void destroy(T **p)
541 {
542 if (*p)
543 (*p)->Release();
544 }
545 };
546
547 enum CComEnumFlags
548 {
549 AtlFlagNoCopy = 0,
550 AtlFlagTakeOwnership = 2, // BitOwn
551 AtlFlagCopy = 3 // BitOwn | BitCopy
552 };
553
554 template <class Base, const IID *piid, class T, class Copy>
555 class CComEnumImpl : public Base
556 {
557 private:
558 typedef CComObject<CComEnum<Base, piid, T, Copy> > enumeratorClass;
559 public:
560 CComPtr<IUnknown> m_spUnk;
561 DWORD m_dwFlags;
562 T *m_begin;
563 T *m_end;
564 T *m_iter;
565 public:
566 CComEnumImpl()
567 {
568 m_dwFlags = 0;
569 m_begin = NULL;
570 m_end = NULL;
571 m_iter = NULL;
572 }
573
574 virtual ~CComEnumImpl()
575 {
576 T *x;
577
578 if ((m_dwFlags & BitOwn) != 0)
579 {
580 for (x = m_begin; x != m_end; x++)
581 Copy::destroy(x);
582 delete [] m_begin;
583 }
584 }
585
586 HRESULT Init(T *begin, T *end, IUnknown *pUnk, CComEnumFlags flags = AtlFlagNoCopy)
587 {
588 T *newBuffer;
589 T *sourcePtr;
590 T *destPtr;
591 T *cleanupPtr;
592 HRESULT hResult;
593
594 if (flags == AtlFlagCopy)
595 {
596 ATLTRY(newBuffer = new T[end - begin])
597 if (newBuffer == NULL)
598 return E_OUTOFMEMORY;
599 destPtr = newBuffer;
600 for (sourcePtr = begin; sourcePtr != end; sourcePtr++)
601 {
602 Copy::init(destPtr);
603 hResult = Copy::copy(destPtr, sourcePtr);
604 if (FAILED(hResult))
605 {
606 cleanupPtr = m_begin;
607 while (cleanupPtr < destPtr)
608 Copy::destroy(cleanupPtr++);
609 delete [] newBuffer;
610 return hResult;
611 }
612 destPtr++;
613 }
614 m_begin = newBuffer;
615 m_end = m_begin + (end - begin);
616 }
617 else
618 {
619 m_begin = begin;
620 m_end = end;
621 }
622 m_spUnk = pUnk;
623 m_dwFlags = flags;
624 m_iter = m_begin;
625 return S_OK;
626 }
627
628 STDMETHOD(Next)(ULONG celt, T *rgelt, ULONG *pceltFetched)
629 {
630 ULONG numAvailable;
631 ULONG numToFetch;
632 T *rgeltTemp;
633 HRESULT hResult;
634
635 if (pceltFetched != NULL)
636 *pceltFetched = 0;
637 if (celt == 0)
638 return E_INVALIDARG;
639 if (rgelt == NULL || (celt != 1 && pceltFetched == NULL))
640 return E_POINTER;
641 if (m_begin == NULL || m_end == NULL || m_iter == NULL)
642 return E_FAIL;
643
644 numAvailable = static_cast<ULONG>(m_end - m_iter);
645 if (celt < numAvailable)
646 numToFetch = celt;
647 else
648 numToFetch = numAvailable;
649 if (pceltFetched != NULL)
650 *pceltFetched = numToFetch;
651 rgeltTemp = rgelt;
652 while (numToFetch != 0)
653 {
654 hResult = Copy::copy(rgeltTemp, m_iter);
655 if (FAILED(hResult))
656 {
657 while (rgelt < rgeltTemp)
658 Copy::destroy(rgelt++);
659 if (pceltFetched != NULL)
660 *pceltFetched = 0;
661 return hResult;
662 }
663 rgeltTemp++;
664 m_iter++;
665 numToFetch--;
666 }
667 if (numAvailable < celt)
668 return S_FALSE;
669 return S_OK;
670 }
671
672 STDMETHOD(Skip)(ULONG celt)
673 {
674 ULONG numAvailable;
675 ULONG numToSkip;
676
677 if (celt == 0)
678 return E_INVALIDARG;
679
680 numAvailable = static_cast<ULONG>(m_end - m_iter);
681 if (celt < numAvailable)
682 numToSkip = celt;
683 else
684 numToSkip = numAvailable;
685 m_iter += numToSkip;
686 if (numAvailable < celt)
687 return S_FALSE;
688 return S_OK;
689 }
690
691 STDMETHOD(Reset)()
692 {
693 m_iter = m_begin;
694 return S_OK;
695 }
696
697 STDMETHOD(Clone)(Base **ppEnum)
698 {
699 enumeratorClass *newInstance;
700 HRESULT hResult;
701
702 hResult = E_POINTER;
703 if (ppEnum != NULL)
704 {
705 *ppEnum = NULL;
706 hResult = enumeratorClass::CreateInstance(&newInstance);
707 if (SUCCEEDED(hResult))
708 {
709 hResult = newInstance->Init(m_begin, m_end, (m_dwFlags & BitOwn) ? this : m_spUnk);
710 if (SUCCEEDED(hResult))
711 {
712 newInstance->m_iter = m_iter;
713 hResult = newInstance->_InternalQueryInterface(*piid, (void **)ppEnum);
714 }
715 if (FAILED(hResult))
716 delete newInstance;
717 }
718 }
719 return hResult;
720 }
721
722 protected:
723 enum FlagBits
724 {
725 BitCopy = 1,
726 BitOwn = 2
727 };
728 };
729
730 template <class Base, const IID *piid, class T, class Copy, class ThreadModel>
731 class CComEnum :
732 public CComEnumImpl<Base, piid, T, Copy>,
733 public CComObjectRootEx<ThreadModel>
734 {
735 public:
736 typedef CComEnum<Base, piid, T, Copy > _CComEnum;
737 typedef CComEnumImpl<Base, piid, T, Copy > _CComEnumBase;
738
739 BEGIN_COM_MAP(_CComEnum)
740 COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase)
741 END_COM_MAP()
742 };
743
744 #ifndef _DEFAULT_VECTORLENGTH
745 #define _DEFAULT_VECTORLENGTH 4
746 #endif
747
748 class CComDynamicUnkArray
749 {
750 public:
751 int m_nSize;
752 IUnknown **m_ppUnk;
753 public:
754 CComDynamicUnkArray()
755 {
756 m_nSize = 0;
757 m_ppUnk = NULL;
758 }
759
760 ~CComDynamicUnkArray()
761 {
762 free(m_ppUnk);
763 }
764
765 IUnknown **begin()
766 {
767 return m_ppUnk;
768 }
769
770 IUnknown **end()
771 {
772 return &m_ppUnk[m_nSize];
773 }
774
775 IUnknown *GetAt(int nIndex)
776 {
777 ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
778 if (nIndex >= 0 && nIndex < m_nSize)
779 return m_ppUnk[nIndex];
780 else
781 return NULL;
782 }
783
784 IUnknown *WINAPI GetUnknown(DWORD dwCookie)
785 {
786 ATLASSERT(dwCookie != 0 && dwCookie <= static_cast<DWORD>(m_nSize));
787 if (dwCookie != 0 && dwCookie <= static_cast<DWORD>(m_nSize))
788 return GetAt(dwCookie - 1);
789 else
790 return NULL;
791 }
792
793 DWORD WINAPI GetCookie(IUnknown **ppFind)
794 {
795 IUnknown **x;
796 DWORD curCookie;
797
798 ATLASSERT(ppFind != NULL && *ppFind != NULL);
799 if (ppFind != NULL && *ppFind != NULL)
800 {
801 curCookie = 1;
802 for (x = begin(); x < end(); x++)
803 {
804 if (*x == *ppFind)
805 return curCookie;
806 curCookie++;
807 }
808 }
809 return 0;
810 }
811
812 DWORD Add(IUnknown *pUnk)
813 {
814 IUnknown **x;
815 IUnknown **newArray;
816 int newSize;
817 DWORD curCookie;
818
819 ATLASSERT(pUnk != NULL);
820 if (m_nSize == 0)
821 {
822 newSize = _DEFAULT_VECTORLENGTH * sizeof(IUnknown *);
823 ATLTRY(newArray = reinterpret_cast<IUnknown **>(malloc(newSize)));
824 if (newArray == NULL)
825 return 0;
826 memset(newArray, 0, newSize);
827 m_ppUnk = newArray;
828 m_nSize = _DEFAULT_VECTORLENGTH;
829 }
830 curCookie = 1;
831 for (x = begin(); x < end(); x++)
832 {
833 if (*x == NULL)
834 {
835 *x = pUnk;
836 return curCookie;
837 }
838 curCookie++;
839 }
840 newSize = m_nSize * 2;
841 newArray = reinterpret_cast<IUnknown **>(realloc(m_ppUnk, newSize * sizeof(IUnknown *)));
842 if (newArray == NULL)
843 return 0;
844 memset(&m_ppUnk[m_nSize], 0, (newSize - m_nSize) * sizeof(IUnknown *));
845 m_ppUnk = newArray;
846 m_nSize = newSize;
847 m_ppUnk[m_nSize] = pUnk;
848 return m_nSize + 1;
849 }
850
851 BOOL Remove(DWORD dwCookie)
852 {
853 DWORD index;
854
855 index = dwCookie - 1;
856 ATLASSERT(index < dwCookie && index < static_cast<DWORD>(m_nSize));
857 if (index < dwCookie && index < static_cast<DWORD>(m_nSize) && m_ppUnk[index] != NULL)
858 {
859 m_ppUnk[index] = NULL;
860 return TRUE;
861 }
862 return FALSE;
863 }
864
865 };
866
867 struct _ATL_CONNMAP_ENTRY
868 {
869 DWORD_PTR dwOffset;
870 };
871
872 template <const IID *piid>
873 class _ICPLocator
874 {
875 public:
876 STDMETHOD(_LocCPQueryInterface)(REFIID riid, void **ppvObject) = 0;
877 virtual ULONG STDMETHODCALLTYPE AddRef() = 0;
878 virtual ULONG STDMETHODCALLTYPE Release() = 0;
879 };
880
881 template<class T, const IID *piid, class CDV = CComDynamicUnkArray>
882 class IConnectionPointImpl : public _ICPLocator<piid>
883 {
884 typedef CComEnum<IEnumConnections, &IID_IEnumConnections, CONNECTDATA, _Copy<CONNECTDATA> > CComEnumConnections;
885 public:
886 CDV m_vec;
887 public:
888 ~IConnectionPointImpl()
889 {
890 IUnknown **x;
891
892 for (x = m_vec.begin(); x < m_vec.end(); x++)
893 if (*x != NULL)
894 (*x)->Release();
895 }
896
897 STDMETHOD(_LocCPQueryInterface)(REFIID riid, void **ppvObject)
898 {
899 IConnectionPointImpl<T, piid, CDV> *pThis;
900
901 pThis = reinterpret_cast<IConnectionPointImpl<T, piid, CDV>*>(this);
902
903 ATLASSERT(ppvObject != NULL);
904 if (ppvObject == NULL)
905 return E_POINTER;
906
907 if (InlineIsEqualGUID(riid, IID_IConnectionPoint) || InlineIsEqualUnknown(riid))
908 {
909 *ppvObject = this;
910 pThis->AddRef();
911 return S_OK;
912 }
913 else
914 {
915 *ppvObject = NULL;
916 return E_NOINTERFACE;
917 }
918 }
919
920 STDMETHOD(GetConnectionInterface)(IID *piid2)
921 {
922 if (piid2 == NULL)
923 return E_POINTER;
924 *piid2 = *piid;
925 return S_OK;
926 }
927
928 STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer **ppCPC)
929 {
930 T *pThis;
931
932 pThis = static_cast<T *>(this);
933 return pThis->QueryInterface(IID_IConnectionPointContainer, reinterpret_cast<void **>(ppCPC));
934 }
935
936 STDMETHOD(Advise)(IUnknown *pUnkSink, DWORD *pdwCookie)
937 {
938 IUnknown *adviseTarget;
939 IID interfaceID;
940 HRESULT hResult;
941
942 if (pdwCookie != NULL)
943 *pdwCookie = 0;
944 if (pUnkSink == NULL || pdwCookie == NULL)
945 return E_POINTER;
946 GetConnectionInterface(&interfaceID); // can't fail
947 hResult = pUnkSink->QueryInterface(interfaceID, reinterpret_cast<void **>(&adviseTarget));
948 if (SUCCEEDED(hResult))
949 {
950 *pdwCookie = m_vec.Add(adviseTarget);
951 if (*pdwCookie != 0)
952 hResult = S_OK;
953 else
954 {
955 adviseTarget->Release();
956 hResult = CONNECT_E_ADVISELIMIT;
957 }
958 }
959 else if (hResult == E_NOINTERFACE)
960 hResult = CONNECT_E_CANNOTCONNECT;
961 return hResult;
962 }
963
964 STDMETHOD(Unadvise)(DWORD dwCookie)
965 {
966 IUnknown *adviseTarget;
967 HRESULT hResult;
968
969 adviseTarget = m_vec.GetUnknown(dwCookie);
970 if (m_vec.Remove(dwCookie))
971 {
972 if (adviseTarget != NULL)
973 adviseTarget->Release();
974 hResult = S_OK;
975 }
976 else
977 hResult = CONNECT_E_NOCONNECTION;
978 return hResult;
979 }
980
981 STDMETHOD(EnumConnections)(IEnumConnections **ppEnum)
982 {
983 CComObject<CComEnumConnections> *newEnumerator;
984 CONNECTDATA *itemBuffer;
985 CONNECTDATA *itemBufferEnd;
986 IUnknown **x;
987 HRESULT hResult;
988
989 ATLASSERT(ppEnum != NULL);
990 if (ppEnum == NULL)
991 return E_POINTER;
992 *ppEnum = NULL;
993
994 ATLTRY(itemBuffer = new CONNECTDATA[m_vec.end() - m_vec.begin()])
995 if (itemBuffer == NULL)
996 return E_OUTOFMEMORY;
997 itemBufferEnd = itemBuffer;
998 for (x = m_vec.begin(); x < m_vec.end(); x++)
999 {
1000 if (*x != NULL)
1001 {
1002 (*x)->AddRef();
1003 itemBufferEnd->pUnk = *x;
1004 itemBufferEnd->dwCookie = m_vec.GetCookie(x);
1005 itemBufferEnd++;
1006 }
1007 }
1008 ATLTRY(newEnumerator = new CComObject<CComEnumConnections>)
1009 if (newEnumerator == NULL)
1010 return E_OUTOFMEMORY;
1011 newEnumerator->Init(itemBuffer, itemBufferEnd, NULL, AtlFlagTakeOwnership); // can't fail
1012 hResult = newEnumerator->_InternalQueryInterface(IID_IEnumConnections, (void **)ppEnum);
1013 if (FAILED(hResult))
1014 delete newEnumerator;
1015 return hResult;
1016 }
1017 };
1018
1019 template <class T>
1020 class IConnectionPointContainerImpl : public IConnectionPointContainer
1021 {
1022 typedef const _ATL_CONNMAP_ENTRY * (*handlerFunctionType)(int *);
1023 typedef CComEnum<IEnumConnectionPoints, &IID_IEnumConnectionPoints, IConnectionPoint *, _CopyInterface<IConnectionPoint> >
1024 CComEnumConnectionPoints;
1025
1026 public:
1027 STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints **ppEnum)
1028 {
1029 const _ATL_CONNMAP_ENTRY *entryPtr;
1030 int connectionPointCount;
1031 IConnectionPoint **itemBuffer;
1032 int destIndex;
1033 handlerFunctionType handlerFunction;
1034 CComEnumConnectionPoints *newEnumerator;
1035 HRESULT hResult;
1036
1037 ATLASSERT(ppEnum != NULL);
1038 if (ppEnum == NULL)
1039 return E_POINTER;
1040 *ppEnum = NULL;
1041
1042 entryPtr = T::GetConnMap(&connectionPointCount);
1043 ATLTRY(itemBuffer = new IConnectionPoint * [connectionPointCount])
1044 if (itemBuffer == NULL)
1045 return E_OUTOFMEMORY;
1046
1047 destIndex = 0;
1048 while (entryPtr->dwOffset != static_cast<DWORD_PTR>(-1))
1049 {
1050 if (entryPtr->dwOffset == static_cast<DWORD_PTR>(-2))
1051 {
1052 entryPtr++;
1053 handlerFunction = reinterpret_cast<handlerFunctionType>(entryPtr->dwOffset);
1054 entryPtr = handlerFunction(NULL);
1055 }
1056 else
1057 {
1058 itemBuffer[destIndex++] = reinterpret_cast<IConnectionPoint *>((char *)this + entryPtr->dwOffset);
1059 entryPtr++;
1060 }
1061 }
1062
1063 ATLTRY(newEnumerator = new CComObject<CComEnumConnectionPoints>)
1064 if (newEnumerator == NULL)
1065 {
1066 delete [] itemBuffer;
1067 return E_OUTOFMEMORY;
1068 }
1069
1070 newEnumerator->Init(&itemBuffer[0], &itemBuffer[destIndex], NULL, AtlFlagTakeOwnership); // can't fail
1071 hResult = newEnumerator->QueryInterface(IID_IEnumConnectionPoints, (void**)ppEnum);
1072 if (FAILED(hResult))
1073 delete newEnumerator;
1074 return hResult;
1075 }
1076
1077 STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint **ppCP)
1078 {
1079 IID interfaceID;
1080 const _ATL_CONNMAP_ENTRY *entryPtr;
1081 handlerFunctionType handlerFunction;
1082 IConnectionPoint *connectionPoint;
1083 HRESULT hResult;
1084
1085 if (ppCP == NULL)
1086 return E_POINTER;
1087 *ppCP = NULL;
1088 hResult = CONNECT_E_NOCONNECTION;
1089 entryPtr = T::GetConnMap(NULL);
1090 while (entryPtr->dwOffset != static_cast<DWORD_PTR>(-1))
1091 {
1092 if (entryPtr->dwOffset == static_cast<DWORD_PTR>(-2))
1093 {
1094 entryPtr++;
1095 handlerFunction = reinterpret_cast<handlerFunctionType>(entryPtr->dwOffset);
1096 entryPtr = handlerFunction(NULL);
1097 }
1098 else
1099 {
1100 connectionPoint = reinterpret_cast<IConnectionPoint *>(reinterpret_cast<char *>(this) + entryPtr->dwOffset);
1101 if (SUCCEEDED(connectionPoint->GetConnectionInterface(&interfaceID)) && InlineIsEqualGUID(riid, interfaceID))
1102 {
1103 *ppCP = connectionPoint;
1104 connectionPoint->AddRef();
1105 hResult = S_OK;
1106 break;
1107 }
1108 entryPtr++;
1109 }
1110 }
1111 return hResult;
1112 }
1113 };
1114
1115 #define BEGIN_CONNECTION_POINT_MAP(x) \
1116 typedef x _atl_conn_classtype; \
1117 static const ATL::_ATL_CONNMAP_ENTRY *GetConnMap(int *pnEntries) { \
1118 static const ATL::_ATL_CONNMAP_ENTRY _entries[] = {
1119
1120 #define END_CONNECTION_POINT_MAP() \
1121 {(DWORD_PTR)-1} }; \
1122 if (pnEntries) \
1123 *pnEntries = sizeof(_entries) / sizeof(ATL::_ATL_CONNMAP_ENTRY) - 1; \
1124 return _entries;}
1125
1126 #define CONNECTION_POINT_ENTRY(iid) \
1127 {offsetofclass(ATL::_ICPLocator<&iid>, _atl_conn_classtype) - \
1128 offsetofclass(ATL::IConnectionPointContainerImpl<_atl_conn_classtype>, _atl_conn_classtype)},
1129
1130 }; // namespace ATL