* The Shell.. for a long time we dreamed of having a compatible, properly working...
[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 <class Base>
198 class CComContainedObject : public Base
199 {
200 public:
201 IUnknown* m_pUnkOuter;
202 CComContainedObject(void * pv = NULL) : m_pUnkOuter(static_cast<IUnknown*>(pv))
203 {
204 }
205
206 STDMETHOD_(ULONG, AddRef)()
207 {
208 return m_pUnkOuter->AddRef();
209 }
210
211 STDMETHOD_(ULONG, Release)()
212 {
213 return m_pUnkOuter->Release();
214 }
215
216 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
217 {
218 return m_pUnkOuter->QueryInterface(iid, ppvObject);
219 }
220
221 IUnknown* GetControllingUnknown()
222 {
223 return m_pUnkOuter;
224 }
225 };
226
227 template <class contained>
228 class CComAggObject : public contained
229 {
230 public:
231 CComContainedObject<contained> m_contained;
232
233 CComAggObject(void * pv = NULL) : m_contained(static_cast<contained*>(pv))
234 {
235 _pAtlModule->Lock();
236 }
237
238 virtual ~CComAggObject()
239 {
240 this->FinalRelease();
241 _pAtlModule->Unlock();
242 }
243
244 HRESULT FinalConstruct()
245 {
246 return m_contained.FinalConstruct();
247 }
248 void FinalRelease()
249 {
250 m_contained.FinalRelease();
251 }
252
253 STDMETHOD_(ULONG, AddRef)()
254 {
255 return this->InternalAddRef();
256 }
257
258 STDMETHOD_(ULONG, Release)()
259 {
260 ULONG newRefCount;
261 newRefCount = this->InternalRelease();
262 if (newRefCount == 0)
263 delete this;
264 return newRefCount;
265 }
266
267 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
268 {
269 if (ppvObject == NULL)
270 return E_POINTER;
271 if (iid == IID_IUnknown)
272 *ppvObject = reinterpret_cast<void*>(this);
273 else
274 return m_contained._InternalQueryInterface(iid, ppvObject);
275 return S_OK;
276 }
277
278 static HRESULT WINAPI CreateInstance(IUnknown * punkOuter, CComAggObject<contained> **pp)
279 {
280 CComAggObject<contained> *newInstance;
281 HRESULT hResult;
282
283 ATLASSERT(pp != NULL);
284 if (pp == NULL)
285 return E_POINTER;
286
287 hResult = E_OUTOFMEMORY;
288 newInstance = NULL;
289 ATLTRY(newInstance = new CComAggObject<contained>(punkOuter))
290 if (newInstance != NULL)
291 {
292 newInstance->SetVoid(NULL);
293 newInstance->InternalFinalConstructAddRef();
294 hResult = newInstance->_AtlInitialConstruct();
295 if (SUCCEEDED(hResult))
296 hResult = newInstance->FinalConstruct();
297 if (SUCCEEDED(hResult))
298 hResult = newInstance->_AtlFinalConstruct();
299 newInstance->InternalFinalConstructRelease();
300 if (hResult != S_OK)
301 {
302 delete newInstance;
303 newInstance = NULL;
304 }
305 }
306 *pp = newInstance;
307 return hResult;
308 }
309 };
310
311 template <class contained>
312 class CComPolyObject : public contained
313 {
314 public:
315 CComContainedObject<contained> m_contained;
316
317 CComPolyObject(void * pv = NULL)
318 : m_contained(pv ? static_cast<contained*>(pv) : this)
319 {
320 _pAtlModule->Lock();
321 }
322
323 virtual ~CComPolyObject()
324 {
325 this->FinalRelease();
326 _pAtlModule->Unlock();
327 }
328
329 HRESULT FinalConstruct()
330 {
331 return m_contained.FinalConstruct();
332 }
333 void FinalRelease()
334 {
335 m_contained.FinalRelease();
336 }
337
338 STDMETHOD_(ULONG, AddRef)()
339 {
340 return this->InternalAddRef();
341 }
342
343 STDMETHOD_(ULONG, Release)()
344 {
345 ULONG newRefCount;
346 newRefCount = this->InternalRelease();
347 if (newRefCount == 0)
348 delete this;
349 return newRefCount;
350 }
351
352 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
353 {
354 if (ppvObject == NULL)
355 return E_POINTER;
356 if (iid == IID_IUnknown)
357 *ppvObject = reinterpret_cast<void*>(this);
358 else
359 return m_contained._InternalQueryInterface(iid, ppvObject);
360 return S_OK;
361 }
362
363 static HRESULT WINAPI CreateInstance(IUnknown * punkOuter, CComPolyObject<contained> **pp)
364 {
365 CComPolyObject<contained> *newInstance;
366 HRESULT hResult;
367
368 ATLASSERT(pp != NULL);
369 if (pp == NULL)
370 return E_POINTER;
371
372 hResult = E_OUTOFMEMORY;
373 newInstance = NULL;
374 ATLTRY(newInstance = new CComPolyObject<contained>(punkOuter))
375 if (newInstance != NULL)
376 {
377 newInstance->SetVoid(NULL);
378 newInstance->InternalFinalConstructAddRef();
379 hResult = newInstance->_AtlInitialConstruct();
380 if (SUCCEEDED(hResult))
381 hResult = newInstance->FinalConstruct();
382 if (SUCCEEDED(hResult))
383 hResult = newInstance->_AtlFinalConstruct();
384 newInstance->InternalFinalConstructRelease();
385 if (hResult != S_OK)
386 {
387 delete newInstance;
388 newInstance = NULL;
389 }
390 }
391 *pp = newInstance;
392 return hResult;
393 }
394 };
395
396 template <HRESULT hResult>
397 class CComFailCreator
398 {
399 public:
400 static HRESULT WINAPI CreateInstance(void *, REFIID, LPVOID *ppv)
401 {
402 ATLASSERT(ppv != NULL);
403 if (ppv == NULL)
404 return E_POINTER;
405 *ppv = NULL;
406
407 return hResult;
408 }
409 };
410
411 template <class T1>
412 class CComCreator
413 {
414 public:
415 static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, LPVOID *ppv)
416 {
417 T1 *newInstance;
418 HRESULT hResult;
419
420 ATLASSERT(ppv != NULL);
421 if (ppv == NULL)
422 return E_POINTER;
423 *ppv = NULL;
424
425 hResult = E_OUTOFMEMORY;
426 newInstance = NULL;
427 ATLTRY(newInstance = new T1(pv))
428 if (newInstance != NULL)
429 {
430 newInstance->SetVoid(pv);
431 newInstance->InternalFinalConstructAddRef();
432 hResult = newInstance->_AtlInitialConstruct();
433 if (SUCCEEDED(hResult))
434 hResult = newInstance->FinalConstruct();
435 if (SUCCEEDED(hResult))
436 hResult = newInstance->_AtlFinalConstruct();
437 newInstance->InternalFinalConstructRelease();
438 if (SUCCEEDED(hResult))
439 hResult = newInstance->QueryInterface(riid, ppv);
440 if (FAILED(hResult))
441 {
442 delete newInstance;
443 newInstance = NULL;
444 }
445 }
446 return hResult;
447 }
448 };
449
450 template <class T1, class T2>
451 class CComCreator2
452 {
453 public:
454 static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, LPVOID *ppv)
455 {
456 ATLASSERT(ppv != NULL && riid != NULL);
457
458 if (pv == NULL)
459 return T1::CreateInstance(NULL, riid, ppv);
460 else
461 return T2::CreateInstance(pv, riid, ppv);
462 }
463 };
464
465 template <class Base>
466 class CComObjectCached : public Base
467 {
468 public:
469 CComObjectCached(void * = NULL)
470 {
471 }
472
473 STDMETHOD_(ULONG, AddRef)()
474 {
475 ULONG newRefCount;
476
477 newRefCount = this->InternalAddRef();
478 if (newRefCount == 2)
479 _pAtlModule->Lock();
480 return newRefCount;
481 }
482
483 STDMETHOD_(ULONG, Release)()
484 {
485 ULONG newRefCount;
486
487 newRefCount = this->InternalRelease();
488 if (newRefCount == 0)
489 delete this;
490 else if (newRefCount == 1)
491 _pAtlModule->Unlock();
492 return newRefCount;
493 }
494
495 STDMETHOD(QueryInterface)(REFIID iid, void **ppvObject)
496 {
497 return this->_InternalQueryInterface(iid, ppvObject);
498 }
499 };
500
501 #define BEGIN_COM_MAP(x) \
502 public: \
503 typedef x _ComMapClass; \
504 HRESULT _InternalQueryInterface(REFIID iid, void **ppvObject) \
505 { \
506 return this->InternalQueryInterface(this, _GetEntries(), iid, ppvObject); \
507 } \
508 const static ATL::_ATL_INTMAP_ENTRY *WINAPI _GetEntries() \
509 { \
510 static const ATL::_ATL_INTMAP_ENTRY _entries[] = {
511
512 #define END_COM_MAP() \
513 {NULL, 0, 0} \
514 }; \
515 return _entries; \
516 } \
517 virtual ULONG STDMETHODCALLTYPE AddRef() = 0; \
518 virtual ULONG STDMETHODCALLTYPE Release() = 0; \
519 STDMETHOD(QueryInterface)(REFIID, void **) = 0;
520
521 #define COM_INTERFACE_ENTRY_IID(iid, x) \
522 {&iid, offsetofclass(x, _ComMapClass), _ATL_SIMPLEMAPENTRY},
523
524 #define COM_INTERFACE_ENTRY(x) \
525 {&_ATL_IIDOF(x), \
526 offsetofclass(x, _ComMapClass), \
527 _ATL_SIMPLEMAPENTRY},
528
529 #define COM_INTERFACE_ENTRY2_IID(iid, x, x2) \
530 {&iid, \
531 reinterpret_cast<DWORD_PTR>(static_cast<x *>(static_cast<x2 *>(reinterpret_cast<_ComMapClass *>(_ATL_PACKING)))) - _ATL_PACKING, \
532 _ATL_SIMPLEMAPENTRY},
533
534 #define COM_INTERFACE_ENTRY_BREAK(x) \
535 {&_ATL_IIDOF(x), \
536 NULL, \
537 _Break}, // Break is a function that issues int 3.
538
539 #define COM_INTERFACE_ENTRY_NOINTERFACE(x) \
540 {&_ATL_IIDOF(x), \
541 NULL, \
542 _NoInterface}, // NoInterface returns E_NOINTERFACE.
543
544 #define COM_INTERFACE_ENTRY_FUNC(iid, dw, func) \
545 {&iid, \
546 dw, \
547 func},
548
549 #define COM_INTERFACE_ENTRY_FUNC_BLIND(dw, func) \
550 {NULL, \
551 dw, \
552 func},
553
554 #define COM_INTERFACE_ENTRY_CHAIN(classname) \
555 {NULL, \
556 reinterpret_cast<DWORD>(&_CComChainData<classname, _ComMapClass>::data), \
557 _Chain},
558
559 #define DECLARE_NO_REGISTRY()\
560 static HRESULT WINAPI UpdateRegistry(BOOL /*bRegister*/) \
561 { \
562 return S_OK; \
563 }
564
565 #define DECLARE_REGISTRY_RESOURCEID(x) \
566 static HRESULT WINAPI UpdateRegistry(BOOL bRegister) \
567 { \
568 return ATL::_pAtlModule->UpdateRegistryFromResource(x, bRegister); \
569 }
570
571 #define DECLARE_NOT_AGGREGATABLE(x) \
572 public: \
573 typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<x> >, ATL::CComFailCreator<CLASS_E_NOAGGREGATION> > _CreatorClass;
574
575 #define DECLARE_AGGREGATABLE(x) \
576 public: \
577 typedef ATL::CComCreator2<ATL::CComCreator<ATL::CComObject<x> >, ATL::CComCreator<ATL::CComAggObject<x> > > _CreatorClass;
578
579 #define DECLARE_ONLY_AGGREGATABLE(x) \
580 public: \
581 typedef ATL::CComCreator2<ATL::CComFailCreator<E_FAIL>, ATL::CComCreator<ATL::CComAggObject<x> > > _CreatorClass;
582
583 #define DECLARE_POLY_AGGREGATABLE(x) \
584 public: \
585 typedef ATL::CComCreator<ATL::CComPolyObject<x> > _CreatorClass;
586
587 #define COM_INTERFACE_ENTRY_AGGREGATE(iid, punk) \
588 {&iid, \
589 (DWORD_PTR)offsetof(_ComMapClass, punk), \
590 _Delegate},
591
592 #define DECLARE_GET_CONTROLLING_UNKNOWN() \
593 public: \
594 virtual IUnknown *GetControllingUnknown() \
595 { \
596 return GetUnknown(); \
597 }
598
599 #define DECLARE_PROTECT_FINAL_CONSTRUCT() \
600 void InternalFinalConstructAddRef() \
601 { \
602 InternalAddRef(); \
603 } \
604 void InternalFinalConstructRelease() \
605 { \
606 InternalRelease(); \
607 }
608
609 #define BEGIN_OBJECT_MAP(x) static ATL::_ATL_OBJMAP_ENTRY x[] = {
610
611 #define END_OBJECT_MAP() {NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL}};
612
613 #define OBJECT_ENTRY(clsid, class) \
614 { \
615 &clsid, \
616 class::UpdateRegistry, \
617 class::_ClassFactoryCreatorClass::CreateInstance, \
618 class::_CreatorClass::CreateInstance, \
619 NULL, \
620 0, \
621 class::GetObjectDescription, \
622 class::GetCategoryMap, \
623 class::ObjectMain },
624
625 class CComClassFactory :
626 public IClassFactory,
627 public CComObjectRootEx<CComGlobalsThreadModel>
628 {
629 public:
630 _ATL_CREATORFUNC *m_pfnCreateInstance;
631
632 virtual ~CComClassFactory()
633 {
634 }
635
636 public:
637 STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj)
638 {
639 HRESULT hResult;
640
641 ATLASSERT(m_pfnCreateInstance != NULL);
642
643 if (ppvObj == NULL)
644 return E_POINTER;
645 *ppvObj = NULL;
646
647 if (pUnkOuter != NULL && InlineIsEqualUnknown(riid) == FALSE)
648 hResult = CLASS_E_NOAGGREGATION;
649 else
650 hResult = m_pfnCreateInstance(pUnkOuter, riid, ppvObj);
651 return hResult;
652 }
653
654 STDMETHOD(LockServer)(BOOL fLock)
655 {
656 if (fLock)
657 _pAtlModule->Lock();
658 else
659 _pAtlModule->Unlock();
660 return S_OK;
661 }
662
663 void SetVoid(void *pv)
664 {
665 m_pfnCreateInstance = (_ATL_CREATORFUNC *)pv;
666 }
667
668 BEGIN_COM_MAP(CComClassFactory)
669 COM_INTERFACE_ENTRY_IID(IID_IClassFactory, IClassFactory)
670 END_COM_MAP()
671 };
672
673 template <class T, const CLSID *pclsid = &CLSID_NULL>
674 class CComCoClass
675 {
676 public:
677 DECLARE_CLASSFACTORY()
678
679 static LPCTSTR WINAPI GetObjectDescription()
680 {
681 return NULL;
682 }
683 };
684
685 template <class T>
686 class _Copy
687 {
688 public:
689 static HRESULT copy(T *pTo, const T *pFrom)
690 {
691 memcpy(pTo, pFrom, sizeof(T));
692 return S_OK;
693 }
694
695 static void init(T *)
696 {
697 }
698
699 static void destroy(T *)
700 {
701 }
702 };
703
704 template<>
705 class _Copy<CONNECTDATA>
706 {
707 public:
708 static HRESULT copy(CONNECTDATA *pTo, const CONNECTDATA *pFrom)
709 {
710 *pTo = *pFrom;
711 if (pTo->pUnk)
712 pTo->pUnk->AddRef();
713 return S_OK;
714 }
715
716 static void init(CONNECTDATA *)
717 {
718 }
719
720 static void destroy(CONNECTDATA *p)
721 {
722 if (p->pUnk)
723 p->pUnk->Release();
724 }
725 };
726
727 template <class T>
728 class _CopyInterface
729 {
730 public:
731 static HRESULT copy(T **pTo, T **pFrom)
732 {
733 *pTo = *pFrom;
734 if (*pTo)
735 (*pTo)->AddRef();
736 return S_OK;
737 }
738
739 static void init(T **)
740 {
741 }
742
743 static void destroy(T **p)
744 {
745 if (*p)
746 (*p)->Release();
747 }
748 };
749
750 enum CComEnumFlags
751 {
752 AtlFlagNoCopy = 0,
753 AtlFlagTakeOwnership = 2, // BitOwn
754 AtlFlagCopy = 3 // BitOwn | BitCopy
755 };
756
757 template <class Base, const IID *piid, class T, class Copy>
758 class CComEnumImpl : public Base
759 {
760 private:
761 typedef CComObject<CComEnum<Base, piid, T, Copy> > enumeratorClass;
762 public:
763 CComPtr<IUnknown> m_spUnk;
764 DWORD m_dwFlags;
765 T *m_begin;
766 T *m_end;
767 T *m_iter;
768 public:
769 CComEnumImpl()
770 {
771 m_dwFlags = 0;
772 m_begin = NULL;
773 m_end = NULL;
774 m_iter = NULL;
775 }
776
777 virtual ~CComEnumImpl()
778 {
779 T *x;
780
781 if ((m_dwFlags & BitOwn) != 0)
782 {
783 for (x = m_begin; x != m_end; x++)
784 Copy::destroy(x);
785 delete [] m_begin;
786 }
787 }
788
789 HRESULT Init(T *begin, T *end, IUnknown *pUnk, CComEnumFlags flags = AtlFlagNoCopy)
790 {
791 T *newBuffer;
792 T *sourcePtr;
793 T *destPtr;
794 T *cleanupPtr;
795 HRESULT hResult;
796
797 if (flags == AtlFlagCopy)
798 {
799 ATLTRY(newBuffer = new T[end - begin])
800 if (newBuffer == NULL)
801 return E_OUTOFMEMORY;
802 destPtr = newBuffer;
803 for (sourcePtr = begin; sourcePtr != end; sourcePtr++)
804 {
805 Copy::init(destPtr);
806 hResult = Copy::copy(destPtr, sourcePtr);
807 if (FAILED(hResult))
808 {
809 cleanupPtr = m_begin;
810 while (cleanupPtr < destPtr)
811 Copy::destroy(cleanupPtr++);
812 delete [] newBuffer;
813 return hResult;
814 }
815 destPtr++;
816 }
817 m_begin = newBuffer;
818 m_end = m_begin + (end - begin);
819 }
820 else
821 {
822 m_begin = begin;
823 m_end = end;
824 }
825 m_spUnk = pUnk;
826 m_dwFlags = flags;
827 m_iter = m_begin;
828 return S_OK;
829 }
830
831 STDMETHOD(Next)(ULONG celt, T *rgelt, ULONG *pceltFetched)
832 {
833 ULONG numAvailable;
834 ULONG numToFetch;
835 T *rgeltTemp;
836 HRESULT hResult;
837
838 if (pceltFetched != NULL)
839 *pceltFetched = 0;
840 if (celt == 0)
841 return E_INVALIDARG;
842 if (rgelt == NULL || (celt != 1 && pceltFetched == NULL))
843 return E_POINTER;
844 if (m_begin == NULL || m_end == NULL || m_iter == NULL)
845 return E_FAIL;
846
847 numAvailable = static_cast<ULONG>(m_end - m_iter);
848 if (celt < numAvailable)
849 numToFetch = celt;
850 else
851 numToFetch = numAvailable;
852 if (pceltFetched != NULL)
853 *pceltFetched = numToFetch;
854 rgeltTemp = rgelt;
855 while (numToFetch != 0)
856 {
857 hResult = Copy::copy(rgeltTemp, m_iter);
858 if (FAILED(hResult))
859 {
860 while (rgelt < rgeltTemp)
861 Copy::destroy(rgelt++);
862 if (pceltFetched != NULL)
863 *pceltFetched = 0;
864 return hResult;
865 }
866 rgeltTemp++;
867 m_iter++;
868 numToFetch--;
869 }
870 if (numAvailable < celt)
871 return S_FALSE;
872 return S_OK;
873 }
874
875 STDMETHOD(Skip)(ULONG celt)
876 {
877 ULONG numAvailable;
878 ULONG numToSkip;
879
880 if (celt == 0)
881 return E_INVALIDARG;
882
883 numAvailable = static_cast<ULONG>(m_end - m_iter);
884 if (celt < numAvailable)
885 numToSkip = celt;
886 else
887 numToSkip = numAvailable;
888 m_iter += numToSkip;
889 if (numAvailable < celt)
890 return S_FALSE;
891 return S_OK;
892 }
893
894 STDMETHOD(Reset)()
895 {
896 m_iter = m_begin;
897 return S_OK;
898 }
899
900 STDMETHOD(Clone)(Base **ppEnum)
901 {
902 enumeratorClass *newInstance;
903 HRESULT hResult;
904
905 hResult = E_POINTER;
906 if (ppEnum != NULL)
907 {
908 *ppEnum = NULL;
909 hResult = enumeratorClass::CreateInstance(&newInstance);
910 if (SUCCEEDED(hResult))
911 {
912 hResult = newInstance->Init(m_begin, m_end, (m_dwFlags & BitOwn) ? this : m_spUnk);
913 if (SUCCEEDED(hResult))
914 {
915 newInstance->m_iter = m_iter;
916 hResult = newInstance->_InternalQueryInterface(*piid, (void **)ppEnum);
917 }
918 if (FAILED(hResult))
919 delete newInstance;
920 }
921 }
922 return hResult;
923 }
924
925 protected:
926 enum FlagBits
927 {
928 BitCopy = 1,
929 BitOwn = 2
930 };
931 };
932
933 template <class Base, const IID *piid, class T, class Copy, class ThreadModel>
934 class CComEnum :
935 public CComEnumImpl<Base, piid, T, Copy>,
936 public CComObjectRootEx<ThreadModel>
937 {
938 public:
939 typedef CComEnum<Base, piid, T, Copy > _CComEnum;
940 typedef CComEnumImpl<Base, piid, T, Copy > _CComEnumBase;
941
942 BEGIN_COM_MAP(_CComEnum)
943 COM_INTERFACE_ENTRY_IID(*piid, _CComEnumBase)
944 END_COM_MAP()
945 };
946
947 #ifndef _DEFAULT_VECTORLENGTH
948 #define _DEFAULT_VECTORLENGTH 4
949 #endif
950
951 class CComDynamicUnkArray
952 {
953 public:
954 int m_nSize;
955 IUnknown **m_ppUnk;
956 public:
957 CComDynamicUnkArray()
958 {
959 m_nSize = 0;
960 m_ppUnk = NULL;
961 }
962
963 ~CComDynamicUnkArray()
964 {
965 free(m_ppUnk);
966 }
967
968 IUnknown **begin()
969 {
970 return m_ppUnk;
971 }
972
973 IUnknown **end()
974 {
975 return &m_ppUnk[m_nSize];
976 }
977
978 IUnknown *GetAt(int nIndex)
979 {
980 ATLASSERT(nIndex >= 0 && nIndex < m_nSize);
981 if (nIndex >= 0 && nIndex < m_nSize)
982 return m_ppUnk[nIndex];
983 else
984 return NULL;
985 }
986
987 IUnknown *WINAPI GetUnknown(DWORD dwCookie)
988 {
989 ATLASSERT(dwCookie != 0 && dwCookie <= static_cast<DWORD>(m_nSize));
990 if (dwCookie != 0 && dwCookie <= static_cast<DWORD>(m_nSize))
991 return GetAt(dwCookie - 1);
992 else
993 return NULL;
994 }
995
996 DWORD WINAPI GetCookie(IUnknown **ppFind)
997 {
998 IUnknown **x;
999 DWORD curCookie;
1000
1001 ATLASSERT(ppFind != NULL && *ppFind != NULL);
1002 if (ppFind != NULL && *ppFind != NULL)
1003 {
1004 curCookie = 1;
1005 for (x = begin(); x < end(); x++)
1006 {
1007 if (*x == *ppFind)
1008 return curCookie;
1009 curCookie++;
1010 }
1011 }
1012 return 0;
1013 }
1014
1015 DWORD Add(IUnknown *pUnk)
1016 {
1017 IUnknown **x;
1018 IUnknown **newArray;
1019 int newSize;
1020 DWORD curCookie;
1021
1022 ATLASSERT(pUnk != NULL);
1023 if (m_nSize == 0)
1024 {
1025 newSize = _DEFAULT_VECTORLENGTH * sizeof(IUnknown *);
1026 ATLTRY(newArray = reinterpret_cast<IUnknown **>(malloc(newSize)));
1027 if (newArray == NULL)
1028 return 0;
1029 memset(newArray, 0, newSize);
1030 m_ppUnk = newArray;
1031 m_nSize = _DEFAULT_VECTORLENGTH;
1032 }
1033 curCookie = 1;
1034 for (x = begin(); x < end(); x++)
1035 {
1036 if (*x == NULL)
1037 {
1038 *x = pUnk;
1039 return curCookie;
1040 }
1041 curCookie++;
1042 }
1043 newSize = m_nSize * 2;
1044 newArray = reinterpret_cast<IUnknown **>(realloc(m_ppUnk, newSize * sizeof(IUnknown *)));
1045 if (newArray == NULL)
1046 return 0;
1047 m_ppUnk = newArray;
1048 memset(&m_ppUnk[m_nSize], 0, (newSize - m_nSize) * sizeof(IUnknown *));
1049 curCookie = m_nSize + 1;
1050 m_nSize = newSize;
1051 m_ppUnk[curCookie - 1] = pUnk;
1052 return curCookie;
1053 }
1054
1055 BOOL Remove(DWORD dwCookie)
1056 {
1057 DWORD index;
1058
1059 index = dwCookie - 1;
1060 ATLASSERT(index < dwCookie && index < static_cast<DWORD>(m_nSize));
1061 if (index < dwCookie && index < static_cast<DWORD>(m_nSize) && m_ppUnk[index] != NULL)
1062 {
1063 m_ppUnk[index] = NULL;
1064 return TRUE;
1065 }
1066 return FALSE;
1067 }
1068
1069 private:
1070 CComDynamicUnkArray &operator = (const CComDynamicUnkArray &)
1071 {
1072 return *this;
1073 }
1074
1075 CComDynamicUnkArray(const CComDynamicUnkArray &)
1076 {
1077 }
1078 };
1079
1080 struct _ATL_CONNMAP_ENTRY
1081 {
1082 DWORD_PTR dwOffset;
1083 };
1084
1085 template <const IID *piid>
1086 class _ICPLocator
1087 {
1088 public:
1089 STDMETHOD(_LocCPQueryInterface)(REFIID riid, void **ppvObject) = 0;
1090 virtual ULONG STDMETHODCALLTYPE AddRef() = 0;
1091 virtual ULONG STDMETHODCALLTYPE Release() = 0;
1092 };
1093
1094 template<class T, const IID *piid, class CDV = CComDynamicUnkArray>
1095 class IConnectionPointImpl : public _ICPLocator<piid>
1096 {
1097 typedef CComEnum<IEnumConnections, &IID_IEnumConnections, CONNECTDATA, _Copy<CONNECTDATA> > CComEnumConnections;
1098 public:
1099 CDV m_vec;
1100 public:
1101 ~IConnectionPointImpl()
1102 {
1103 IUnknown **x;
1104
1105 for (x = m_vec.begin(); x < m_vec.end(); x++)
1106 if (*x != NULL)
1107 (*x)->Release();
1108 }
1109
1110 STDMETHOD(_LocCPQueryInterface)(REFIID riid, void **ppvObject)
1111 {
1112 IConnectionPointImpl<T, piid, CDV> *pThis;
1113
1114 pThis = reinterpret_cast<IConnectionPointImpl<T, piid, CDV>*>(this);
1115
1116 ATLASSERT(ppvObject != NULL);
1117 if (ppvObject == NULL)
1118 return E_POINTER;
1119
1120 if (InlineIsEqualGUID(riid, IID_IConnectionPoint) || InlineIsEqualUnknown(riid))
1121 {
1122 *ppvObject = this;
1123 pThis->AddRef();
1124 return S_OK;
1125 }
1126 else
1127 {
1128 *ppvObject = NULL;
1129 return E_NOINTERFACE;
1130 }
1131 }
1132
1133 STDMETHOD(GetConnectionInterface)(IID *piid2)
1134 {
1135 if (piid2 == NULL)
1136 return E_POINTER;
1137 *piid2 = *piid;
1138 return S_OK;
1139 }
1140
1141 STDMETHOD(GetConnectionPointContainer)(IConnectionPointContainer **ppCPC)
1142 {
1143 T *pThis;
1144
1145 pThis = static_cast<T *>(this);
1146 return pThis->QueryInterface(IID_IConnectionPointContainer, reinterpret_cast<void **>(ppCPC));
1147 }
1148
1149 STDMETHOD(Advise)(IUnknown *pUnkSink, DWORD *pdwCookie)
1150 {
1151 IUnknown *adviseTarget;
1152 IID interfaceID;
1153 HRESULT hResult;
1154
1155 if (pdwCookie != NULL)
1156 *pdwCookie = 0;
1157 if (pUnkSink == NULL || pdwCookie == NULL)
1158 return E_POINTER;
1159 GetConnectionInterface(&interfaceID); // can't fail
1160 hResult = pUnkSink->QueryInterface(interfaceID, reinterpret_cast<void **>(&adviseTarget));
1161 if (SUCCEEDED(hResult))
1162 {
1163 *pdwCookie = m_vec.Add(adviseTarget);
1164 if (*pdwCookie != 0)
1165 hResult = S_OK;
1166 else
1167 {
1168 adviseTarget->Release();
1169 hResult = CONNECT_E_ADVISELIMIT;
1170 }
1171 }
1172 else if (hResult == E_NOINTERFACE)
1173 hResult = CONNECT_E_CANNOTCONNECT;
1174 return hResult;
1175 }
1176
1177 STDMETHOD(Unadvise)(DWORD dwCookie)
1178 {
1179 IUnknown *adviseTarget;
1180 HRESULT hResult;
1181
1182 adviseTarget = m_vec.GetUnknown(dwCookie);
1183 if (m_vec.Remove(dwCookie))
1184 {
1185 if (adviseTarget != NULL)
1186 adviseTarget->Release();
1187 hResult = S_OK;
1188 }
1189 else
1190 hResult = CONNECT_E_NOCONNECTION;
1191 return hResult;
1192 }
1193
1194 STDMETHOD(EnumConnections)(IEnumConnections **ppEnum)
1195 {
1196 CComObject<CComEnumConnections> *newEnumerator;
1197 CONNECTDATA *itemBuffer;
1198 CONNECTDATA *itemBufferEnd;
1199 IUnknown **x;
1200 HRESULT hResult;
1201
1202 ATLASSERT(ppEnum != NULL);
1203 if (ppEnum == NULL)
1204 return E_POINTER;
1205 *ppEnum = NULL;
1206
1207 ATLTRY(itemBuffer = new CONNECTDATA[m_vec.end() - m_vec.begin()])
1208 if (itemBuffer == NULL)
1209 return E_OUTOFMEMORY;
1210 itemBufferEnd = itemBuffer;
1211 for (x = m_vec.begin(); x < m_vec.end(); x++)
1212 {
1213 if (*x != NULL)
1214 {
1215 (*x)->AddRef();
1216 itemBufferEnd->pUnk = *x;
1217 itemBufferEnd->dwCookie = m_vec.GetCookie(x);
1218 itemBufferEnd++;
1219 }
1220 }
1221 ATLTRY(newEnumerator = new CComObject<CComEnumConnections>)
1222 if (newEnumerator == NULL)
1223 return E_OUTOFMEMORY;
1224 newEnumerator->Init(itemBuffer, itemBufferEnd, NULL, AtlFlagTakeOwnership); // can't fail
1225 hResult = newEnumerator->_InternalQueryInterface(IID_IEnumConnections, (void **)ppEnum);
1226 if (FAILED(hResult))
1227 delete newEnumerator;
1228 return hResult;
1229 }
1230 };
1231
1232 template <class T>
1233 class IConnectionPointContainerImpl : public IConnectionPointContainer
1234 {
1235 typedef const _ATL_CONNMAP_ENTRY * (*handlerFunctionType)(int *);
1236 typedef CComEnum<IEnumConnectionPoints, &IID_IEnumConnectionPoints, IConnectionPoint *, _CopyInterface<IConnectionPoint> >
1237 CComEnumConnectionPoints;
1238
1239 public:
1240 STDMETHOD(EnumConnectionPoints)(IEnumConnectionPoints **ppEnum)
1241 {
1242 const _ATL_CONNMAP_ENTRY *entryPtr;
1243 int connectionPointCount;
1244 IConnectionPoint **itemBuffer;
1245 int destIndex;
1246 handlerFunctionType handlerFunction;
1247 CComEnumConnectionPoints *newEnumerator;
1248 HRESULT hResult;
1249
1250 ATLASSERT(ppEnum != NULL);
1251 if (ppEnum == NULL)
1252 return E_POINTER;
1253 *ppEnum = NULL;
1254
1255 entryPtr = T::GetConnMap(&connectionPointCount);
1256 ATLTRY(itemBuffer = new IConnectionPoint * [connectionPointCount])
1257 if (itemBuffer == NULL)
1258 return E_OUTOFMEMORY;
1259
1260 destIndex = 0;
1261 while (entryPtr->dwOffset != static_cast<DWORD_PTR>(-1))
1262 {
1263 if (entryPtr->dwOffset == static_cast<DWORD_PTR>(-2))
1264 {
1265 entryPtr++;
1266 handlerFunction = reinterpret_cast<handlerFunctionType>(entryPtr->dwOffset);
1267 entryPtr = handlerFunction(NULL);
1268 }
1269 else
1270 {
1271 itemBuffer[destIndex++] = reinterpret_cast<IConnectionPoint *>((char *)this + entryPtr->dwOffset);
1272 entryPtr++;
1273 }
1274 }
1275
1276 ATLTRY(newEnumerator = new CComObject<CComEnumConnectionPoints>)
1277 if (newEnumerator == NULL)
1278 {
1279 delete [] itemBuffer;
1280 return E_OUTOFMEMORY;
1281 }
1282
1283 newEnumerator->Init(&itemBuffer[0], &itemBuffer[destIndex], NULL, AtlFlagTakeOwnership); // can't fail
1284 hResult = newEnumerator->QueryInterface(IID_IEnumConnectionPoints, (void**)ppEnum);
1285 if (FAILED(hResult))
1286 delete newEnumerator;
1287 return hResult;
1288 }
1289
1290 STDMETHOD(FindConnectionPoint)(REFIID riid, IConnectionPoint **ppCP)
1291 {
1292 IID interfaceID;
1293 const _ATL_CONNMAP_ENTRY *entryPtr;
1294 handlerFunctionType handlerFunction;
1295 IConnectionPoint *connectionPoint;
1296 HRESULT hResult;
1297
1298 if (ppCP == NULL)
1299 return E_POINTER;
1300 *ppCP = NULL;
1301 hResult = CONNECT_E_NOCONNECTION;
1302 entryPtr = T::GetConnMap(NULL);
1303 while (entryPtr->dwOffset != static_cast<DWORD_PTR>(-1))
1304 {
1305 if (entryPtr->dwOffset == static_cast<DWORD_PTR>(-2))
1306 {
1307 entryPtr++;
1308 handlerFunction = reinterpret_cast<handlerFunctionType>(entryPtr->dwOffset);
1309 entryPtr = handlerFunction(NULL);
1310 }
1311 else
1312 {
1313 connectionPoint = reinterpret_cast<IConnectionPoint *>(reinterpret_cast<char *>(this) + entryPtr->dwOffset);
1314 if (SUCCEEDED(connectionPoint->GetConnectionInterface(&interfaceID)) && InlineIsEqualGUID(riid, interfaceID))
1315 {
1316 *ppCP = connectionPoint;
1317 connectionPoint->AddRef();
1318 hResult = S_OK;
1319 break;
1320 }
1321 entryPtr++;
1322 }
1323 }
1324 return hResult;
1325 }
1326 };
1327
1328 #define BEGIN_CONNECTION_POINT_MAP(x) \
1329 typedef x _atl_conn_classtype; \
1330 static const ATL::_ATL_CONNMAP_ENTRY *GetConnMap(int *pnEntries) { \
1331 static const ATL::_ATL_CONNMAP_ENTRY _entries[] = {
1332
1333 #define END_CONNECTION_POINT_MAP() \
1334 {(DWORD_PTR)-1} }; \
1335 if (pnEntries) \
1336 *pnEntries = sizeof(_entries) / sizeof(ATL::_ATL_CONNMAP_ENTRY) - 1; \
1337 return _entries;}
1338
1339 #define CONNECTION_POINT_ENTRY(iid) \
1340 {offsetofclass(ATL::_ICPLocator<&iid>, _atl_conn_classtype) - \
1341 offsetofclass(ATL::IConnectionPointContainerImpl<_atl_conn_classtype>, _atl_conn_classtype)},
1342
1343 }; // namespace ATL