2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
5 //*****************************************************************************
9 // Implementation of CordbEnumerator, a templated COM enumeration pattern on Rs
11 //*****************************************************************************
15 // This CordbEnumerator is a templated enumerator from which COM enumerators for RS types can quickly be fashioned.
16 // It uses a private array to store the items it enumerates over so by default it does not reference any
17 // other RS type except the process it is associated with. The internal storage type does not need to match the
18 // the item type exposed publically so that you can easily create an enumeration that holds RsSmartPtr<CordbThread>
19 // but enumerates ICorDebugThread objects as an example. The enumerator has 4 templated parameters which must be
21 // ElemType: this is the item type used for storage internal to the enumerator. For most Rs objects you will want
22 // to use an RsSmartPtr<T> type to ensure the enumerator holds references to the objects it is
23 // containing. The enumerator does not do any explicit Add/Release, it just copies items.
24 // ElemPublicType: this is the item type exposed publically via the Next enumeration method. Typically this is
25 // an ICorDebugX interface type but it can be anything.
26 // EnumInterfaceType: this is the COM interface that the instantiated template will implement. It is expected that
27 // this interface type follows the standard ICorDebug COM enumerator pattern, that the interface inherits
28 // ICorDebugEnum and defines a strongly typed Next, enumerating over the ElemPublicType.
29 // GetPublicType: this is a function which converts from ElemType -> ElemPublicType. It is used to produce the
30 // elements that Next actually enumerates from the internal data the enumerator stores. Two conversion
31 // functions are already defined here for convenience: QueryInterfaceConvert and IdentityConvert. If
32 // neither of those suits your needs then you can define your own.
34 // Note: As of right now (10/13/08) most of the ICorDebug enumerators are not implemented using this base class,
35 // however it might be good if we converged on this solution. There seems to be quite a bit of redundant and
36 // one-off enumeration code that could be eliminated.
39 // A conversion function that converts from T to U by performing COM QueryInterface
40 template<typename T, typename U>
41 U * QueryInterfaceConvert(T obj)
44 obj->QueryInterface(__uuidof(U), (void**) &pPublic);
48 // A conversion identity function that just returns its argument
50 T IdentityConvert(T obj)
55 // Constructor for an CordbEnumerator.
57 // pProcess - the CordbProcess with which to associate this enumerator
58 // items - the set of items which should be enumerated
59 // countItems - the number of items in the array pointed to by items
61 // Note that the items are copied into an internal array, and no reference is kept to the users array.
62 // Use RsSmartPtr types instead of Rs types directly to keep accurate ref counting for types which need it
63 template< typename ElemType,
64 typename ElemPublicType,
65 typename EnumInterfaceType,
66 ElemPublicType (*GetPublicType)(ElemType)>
67 CordbEnumerator<ElemType,
70 GetPublicType>::CordbEnumerator(CordbProcess *pProcess,
73 CordbBase(pProcess, 0, enumCordbEnumerator),
75 m_countItems(countItems)
77 m_items = new ElemType[countItems];
78 for(UINT i = 0; i < countItems; i++)
80 m_items[i] = items[i];
84 // Constructor for an CordbEnumerator.
86 // pProcess - the CordbProcess with which to associate this enumerator
87 // items - the address of an array of items which should be enumerated
88 // countItems - the number of items in the array pointed to by items
90 // Note that the items array is simply taken over, setting *items to NULL.
91 // Use RsSmartPtr types instead of Rs types directly to keep accurate ref counting for types which need it
92 template< typename ElemType,
93 typename ElemPublicType,
94 typename EnumInterfaceType,
95 ElemPublicType (*GetPublicType)(ElemType)>
96 CordbEnumerator<ElemType,
99 GetPublicType>::CordbEnumerator(CordbProcess *pProcess,
102 CordbBase(pProcess, 0, enumCordbEnumerator),
104 m_countItems(countItems)
106 _ASSERTE(items != NULL);
112 template< typename ElemType,
113 typename ElemPublicType,
114 typename EnumInterfaceType,
115 ElemPublicType (*GetPublicType)(ElemType)>
116 CordbEnumerator<ElemType,
119 GetPublicType>::~CordbEnumerator()
121 // for now at least all of these enumerators should be in neuter lists and get neutered prior to destruction
122 _ASSERTE(IsNeutered());
125 // COM IUnknown::QueryInterface - provides ICorDebugEnum, IUnknown, and templated EnumInterfaceType
128 // riid - IID of the interface to query for
129 // ppInterface - on output set to a pointer to the desired interface
132 // S_OK for the supported interfaces and E_NOINTERFACE otherwise
133 template< typename ElemType,
134 typename ElemPublicType,
135 typename EnumInterfaceType,
136 ElemPublicType (*GetPublicType)(ElemType)>
137 HRESULT CordbEnumerator<ElemType,
140 GetPublicType>::QueryInterface(REFIID riid, VOID** ppInterface)
142 if(riid == __uuidof(ICorDebugEnum))
144 *ppInterface = static_cast<ICorDebugEnum*>(this);
148 else if(riid == __uuidof(IUnknown))
150 *ppInterface = static_cast<IUnknown*>(static_cast<CordbBase*>(this));
154 else if(riid == __uuidof(EnumInterfaceType))
156 *ppInterface = static_cast<EnumInterfaceType*>(this);
162 return E_NOINTERFACE;
166 // COM IUnknown::AddRef()
167 template< typename ElemType,
168 typename ElemPublicType,
169 typename EnumInterfaceType,
170 ElemPublicType (*GetPublicType)(ElemType)>
171 ULONG CordbEnumerator<ElemType,
174 GetPublicType>::AddRef()
179 // COM IUnknown::Release()
180 template< typename ElemType,
181 typename ElemPublicType,
182 typename EnumInterfaceType,
183 ElemPublicType (*GetPublicType)(ElemType)>
184 ULONG CordbEnumerator<ElemType,
187 GetPublicType>::Release()
189 return BaseRelease();
192 // ICorDebugEnum::Clone
193 // Makes a duplicate of the enumeration. The internal items are copied by value and there is no explicit reference
194 // between the new and old enumerations.
197 // ppEnum - on output filled with a duplicate enumeration
200 // S_OK if the clone was created succesfully, otherwise some appropriate failing HRESULT
201 template< typename ElemType,
202 typename ElemPublicType,
203 typename EnumInterfaceType,
204 ElemPublicType (*GetPublicType)(ElemType)>
205 HRESULT CordbEnumerator<ElemType,
208 GetPublicType>::Clone(ICorDebugEnum **ppEnum)
210 FAIL_IF_NEUTERED(this);
211 VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorDebugEnum **);
215 CordbEnumerator<ElemType, ElemPublicType, EnumInterfaceType, GetPublicType>* clone =
216 new CordbEnumerator<ElemType, ElemPublicType, EnumInterfaceType,GetPublicType>(
217 GetProcess(), m_items, m_countItems);
218 clone->QueryInterface(__uuidof(ICorDebugEnum), (void**)ppEnum);
226 // ICorDebugEnum::GetCount
227 // Gets the number of items in the the list that is being enumerated
230 // pcelt - on return the number of items being enumerated
233 // S_OK or failing HRESULTS for other error conditions
234 template< typename ElemType,
235 typename ElemPublicType,
236 typename EnumInterfaceType,
237 ElemPublicType (*GetPublicType)(ElemType)>
238 HRESULT CordbEnumerator<ElemType,
241 GetPublicType>::GetCount(ULONG *pcelt)
243 FAIL_IF_NEUTERED(this);
244 VALIDATE_POINTER_TO_OBJECT(pcelt, ULONG *);
246 *pcelt = m_countItems;
250 // ICorDebugEnum::Reset
251 // Restarts the enumeration at the beginning of the list
254 // S_OK or failing HRESULTS for other error conditions
255 template< typename ElemType,
256 typename ElemPublicType,
257 typename EnumInterfaceType,
258 ElemPublicType (*GetPublicType)(ElemType)>
259 HRESULT CordbEnumerator<ElemType,
262 GetPublicType>::Reset()
264 FAIL_IF_NEUTERED(this);
270 // ICorDebugEnum::Skip
271 // Skips over celt items in the enumeration, if celt is greater than the number of remaining items then all
272 // remaining items are skipped.
275 // celt - number of items to be skipped
278 // S_OK or failing HRESULTS for other error conditions
279 template< typename ElemType,
280 typename ElemPublicType,
281 typename EnumInterfaceType,
282 ElemPublicType (*GetPublicType)(ElemType)>
283 HRESULT CordbEnumerator<ElemType,
286 GetPublicType>::Skip(ULONG celt)
288 FAIL_IF_NEUTERED(this);
291 if(m_nextIndex > m_countItems)
293 m_nextIndex = m_countItems;
298 // EnumInterfaceType::Next
299 // Attempts to enumerate the next celt items by copying them in the items array. If fewer than celt
300 // items remain all remaining items are enumerated. In either case pceltFetched indicates the number
301 // of items actually fetched.
304 // celt - the number of enumerated items requested
305 // items - an array of size celt where the enumerated items will be copied
306 // pceltFetched - on return, the actual number of items enumerated
309 // S_OK if all items could be enumerated, S_FALSE if not all the requested items were enumerated,
310 // failing HRESULTS for other error conditions
311 template< typename ElemType,
312 typename ElemPublicType,
313 typename EnumInterfaceType,
314 ElemPublicType (*GetPublicType)(ElemType)>
315 HRESULT CordbEnumerator<ElemType,
318 GetPublicType>::Next(ULONG celt,
319 ElemPublicType items[],
322 FAIL_IF_NEUTERED(this);
323 VALIDATE_POINTER_TO_OBJECT_ARRAY(items, ElemInterfaceType *,
325 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pceltFetched, ULONG *);
327 if ((pceltFetched == NULL) && (celt != 1))
333 for(countFetched = 0; countFetched < celt && m_nextIndex < m_countItems; countFetched++, m_nextIndex++)
335 items[countFetched] = GetPublicType(m_items[m_nextIndex]);
338 if(pceltFetched != NULL)
340 *pceltFetched = countFetched;
343 return countFetched == celt ? S_OK : S_FALSE;
347 // neuters the enumerator and deletes the contents (the contents are not explicitly neutered though)
348 template< typename ElemType,
349 typename ElemPublicType,
350 typename EnumInterfaceType,
351 ElemPublicType (*GetPublicType)(ElemType)>
352 VOID CordbEnumerator<ElemType,
355 GetPublicType>::Neuter()