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