1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //*****************************************************************************
8 // Implementation of CordbEnumerator, a templated COM enumeration pattern on Rs
10 //*****************************************************************************
14 // This CordbEnumerator is a templated enumerator from which COM enumerators for RS types can quickly be fashioned.
15 // It uses a private array to store the items it enumerates over so by default it does not reference any
16 // other RS type except the process it is associated with. The internal storage type does not need to match the
17 // the item type exposed publically so that you can easily create an enumeration that holds RsSmartPtr<CordbThread>
18 // but enumerates ICorDebugThread objects as an example. The enumerator has 4 templated parameters which must be
20 // ElemType: this is the item type used for storage internal to the enumerator. For most Rs objects you will want
21 // to use an RsSmartPtr<T> type to ensure the enumerator holds references to the objects it is
22 // containing. The enumerator does not do any explicit Add/Release, it just copies items.
23 // ElemPublicType: this is the item type exposed publically via the Next enumeration method. Typically this is
24 // an ICorDebugX interface type but it can be anything.
25 // EnumInterfaceType: this is the COM interface that the instantiated template will implement. It is expected that
26 // this interface type follows the standard ICorDebug COM enumerator pattern, that the interface inherits
27 // ICorDebugEnum and defines a strongly typed Next, enumerating over the ElemPublicType.
28 // GetPublicType: this is a function which converts from ElemType -> ElemPublicType. It is used to produce the
29 // elements that Next actually enumerates from the internal data the enumerator stores. Two conversion
30 // functions are already defined here for convenience: QueryInterfaceConvert and IdentityConvert. If
31 // neither of those suits your needs then you can define your own.
33 // Note: As of right now (10/13/08) most of the ICorDebug enumerators are not implemented using this base class,
34 // however it might be good if we converged on this solution. There seems to be quite a bit of redundant and
35 // one-off enumeration code that could be eliminated.
38 // A conversion function that converts from T to U by performing COM QueryInterface
39 template<typename T, typename U>
40 U * QueryInterfaceConvert(T obj)
43 obj->QueryInterface(__uuidof(U), (void**) &pPublic);
47 // A conversion identity function that just returns its argument
49 T IdentityConvert(T obj)
54 // Constructor for an CordbEnumerator.
56 // pProcess - the CordbProcess with which to associate this enumerator
57 // items - the set of items which should be enumerated
58 // countItems - the number of items in the array pointed to by items
60 // Note that the items are copied into an internal array, and no reference is kept to the users array.
61 // Use RsSmartPtr types instead of Rs types directly to keep accurate ref counting for types which need it
62 template< typename ElemType,
63 typename ElemPublicType,
64 typename EnumInterfaceType,
65 ElemPublicType (*GetPublicType)(ElemType)>
66 CordbEnumerator<ElemType,
69 GetPublicType>::CordbEnumerator(CordbProcess *pProcess,
72 CordbBase(pProcess, 0, enumCordbEnumerator),
73 m_countItems(countItems),
76 m_items = new ElemType[countItems];
77 for(UINT i = 0; i < countItems; i++)
79 m_items[i] = items[i];
83 // Constructor for an CordbEnumerator.
85 // pProcess - the CordbProcess with which to associate this enumerator
86 // items - the address of an array of items which should be enumerated
87 // countItems - the number of items in the array pointed to by items
89 // Note that the items array is simply taken over, setting *items to NULL.
90 // Use RsSmartPtr types instead of Rs types directly to keep accurate ref counting for types which need it
91 template< typename ElemType,
92 typename ElemPublicType,
93 typename EnumInterfaceType,
94 ElemPublicType (*GetPublicType)(ElemType)>
95 CordbEnumerator<ElemType,
98 GetPublicType>::CordbEnumerator(CordbProcess *pProcess,
101 CordbBase(pProcess, 0, enumCordbEnumerator),
102 m_countItems(countItems),
105 _ASSERTE(items != NULL);
111 template< typename ElemType,
112 typename ElemPublicType,
113 typename EnumInterfaceType,
114 ElemPublicType (*GetPublicType)(ElemType)>
115 CordbEnumerator<ElemType,
118 GetPublicType>::~CordbEnumerator()
120 // for now at least all of these enumerators should be in neuter lists and get neutered prior to destruction
121 _ASSERTE(IsNeutered());
124 // COM IUnknown::QueryInterface - provides ICorDebugEnum, IUnknown, and templated EnumInterfaceType
127 // riid - IID of the interface to query for
128 // ppInterface - on output set to a pointer to the desired interface
131 // S_OK for the supported interfaces and E_NOINTERFACE otherwise
132 template< typename ElemType,
133 typename ElemPublicType,
134 typename EnumInterfaceType,
135 ElemPublicType (*GetPublicType)(ElemType)>
136 HRESULT CordbEnumerator<ElemType,
139 GetPublicType>::QueryInterface(REFIID riid, VOID** ppInterface)
141 if(riid == __uuidof(ICorDebugEnum))
143 *ppInterface = static_cast<ICorDebugEnum*>(this);
147 else if(riid == __uuidof(IUnknown))
149 *ppInterface = static_cast<IUnknown*>(static_cast<CordbBase*>(this));
153 else if(riid == __uuidof(EnumInterfaceType))
155 *ppInterface = static_cast<EnumInterfaceType*>(this);
161 return E_NOINTERFACE;
165 // COM IUnknown::AddRef()
166 template< typename ElemType,
167 typename ElemPublicType,
168 typename EnumInterfaceType,
169 ElemPublicType (*GetPublicType)(ElemType)>
170 ULONG CordbEnumerator<ElemType,
173 GetPublicType>::AddRef()
178 // COM IUnknown::Release()
179 template< typename ElemType,
180 typename ElemPublicType,
181 typename EnumInterfaceType,
182 ElemPublicType (*GetPublicType)(ElemType)>
183 ULONG CordbEnumerator<ElemType,
186 GetPublicType>::Release()
188 return BaseRelease();
191 // ICorDebugEnum::Clone
192 // Makes a duplicate of the enumeration. The internal items are copied by value and there is no explicit reference
193 // between the new and old enumerations.
196 // ppEnum - on output filled with a duplicate enumeration
199 // S_OK if the clone was created succesfully, otherwise some appropriate failing HRESULT
200 template< typename ElemType,
201 typename ElemPublicType,
202 typename EnumInterfaceType,
203 ElemPublicType (*GetPublicType)(ElemType)>
204 HRESULT CordbEnumerator<ElemType,
207 GetPublicType>::Clone(ICorDebugEnum **ppEnum)
209 FAIL_IF_NEUTERED(this);
210 VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorDebugEnum **);
214 CordbEnumerator<ElemType, ElemPublicType, EnumInterfaceType, GetPublicType>* clone =
215 new CordbEnumerator<ElemType, ElemPublicType, EnumInterfaceType,GetPublicType>(
216 GetProcess(), m_items, m_countItems);
217 clone->QueryInterface(__uuidof(ICorDebugEnum), (void**)ppEnum);
225 // ICorDebugEnum::GetCount
226 // Gets the number of items in the the list that is being enumerated
229 // pcelt - on return the number of items being enumerated
232 // S_OK or failing HRESULTS for other error conditions
233 template< typename ElemType,
234 typename ElemPublicType,
235 typename EnumInterfaceType,
236 ElemPublicType (*GetPublicType)(ElemType)>
237 HRESULT CordbEnumerator<ElemType,
240 GetPublicType>::GetCount(ULONG *pcelt)
242 FAIL_IF_NEUTERED(this);
243 VALIDATE_POINTER_TO_OBJECT(pcelt, ULONG *);
245 *pcelt = m_countItems;
249 // ICorDebugEnum::Reset
250 // Restarts the enumeration at the beginning of the list
253 // S_OK or failing HRESULTS for other error conditions
254 template< typename ElemType,
255 typename ElemPublicType,
256 typename EnumInterfaceType,
257 ElemPublicType (*GetPublicType)(ElemType)>
258 HRESULT CordbEnumerator<ElemType,
261 GetPublicType>::Reset()
263 FAIL_IF_NEUTERED(this);
269 // ICorDebugEnum::Skip
270 // Skips over celt items in the enumeration, if celt is greater than the number of remaining items then all
271 // remaining items are skipped.
274 // celt - number of items to be skipped
277 // S_OK or failing HRESULTS for other error conditions
278 template< typename ElemType,
279 typename ElemPublicType,
280 typename EnumInterfaceType,
281 ElemPublicType (*GetPublicType)(ElemType)>
282 HRESULT CordbEnumerator<ElemType,
285 GetPublicType>::Skip(ULONG celt)
287 FAIL_IF_NEUTERED(this);
290 if(m_nextIndex > m_countItems)
292 m_nextIndex = m_countItems;
297 // EnumInterfaceType::Next
298 // Attempts to enumerate the next celt items by copying them in the items array. If fewer than celt
299 // items remain all remaining items are enumerated. In either case pceltFetched indicates the number
300 // of items actually fetched.
303 // celt - the number of enumerated items requested
304 // items - an array of size celt where the enumerated items will be copied
305 // pceltFetched - on return, the actual number of items enumerated
308 // S_OK if all items could be enumerated, S_FALSE if not all the requested items were enumerated,
309 // failing HRESULTS for other error conditions
310 template< typename ElemType,
311 typename ElemPublicType,
312 typename EnumInterfaceType,
313 ElemPublicType (*GetPublicType)(ElemType)>
314 HRESULT CordbEnumerator<ElemType,
317 GetPublicType>::Next(ULONG celt,
318 ElemPublicType items[],
321 FAIL_IF_NEUTERED(this);
322 VALIDATE_POINTER_TO_OBJECT_ARRAY(items, ElemInterfaceType *,
324 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pceltFetched, ULONG *);
326 if ((pceltFetched == NULL) && (celt != 1))
332 for(countFetched = 0; countFetched < celt && m_nextIndex < m_countItems; countFetched++, m_nextIndex++)
334 items[countFetched] = GetPublicType(m_items[m_nextIndex]);
337 if(pceltFetched != NULL)
339 *pceltFetched = countFetched;
342 return countFetched == celt ? S_OK : S_FALSE;
346 // neuters the enumerator and deletes the contents (the contents are not explicitly neutered though)
347 template< typename ElemType,
348 typename ElemPublicType,
349 typename EnumInterfaceType,
350 ElemPublicType (*GetPublicType)(ElemType)>
351 VOID CordbEnumerator<ElemType,
354 GetPublicType>::Neuter()