A frequent programming task is that of iterating through a sequence of items. The COM interfaces are no exception: there are places in several interfaces described in this specification where a client of some object needs to iterate through a sequence of items controlled by the object. COM supports such enumeration through the use of ``enumerator objects.'' Enumerators cleanly separate the caller's desire to loop over a set of objects from the callee's knowledge of how to accomplish that function.
[Footnote 61]
Enumerators are just a concept; there is no actual interface called
IEnumerator or IEnum or the like.
This is due to the fact that the function
signatures in an enumerator interface must include the type of the things
that the enumerator enumerates.
As a consequence, separate interfaces exist
for each kind of thing that can be enumerated.
However, the difference in
the type being enumerated is the
only
difference between
each of these interfaces; they are all used in fundamentally the same way.
In other words, they are ``generic'' over the element type.
This document
describes the semantics of enumerators using a generic interface
IEnum()
and the C++ parameterized type syntax where
ELT_T
, which stands for ``ELemenT Type'',
[Footnote 61]
is representative of the type involved in the enumeration:
[ object, uuid(<IID_IEnum <ELT_T>>), // IID_IEnum<ELT_T> pointer_default(unique) ] interface IEnum<ELT_T> : IUnknown { HRESULT Next( [in] ULONG celt, [out] IUnknown **rgelt, [out] ULONG *pceltFetched ); HRESULT Skip( [in] ULONG celt ); HRESULT Reset( void ); HRESULT Clone( [out] IEnum<ELT_T>**ppenum ); }
A typical use of an enumerator is the following.
//Somewhere there's a type called ``String'' typedef char * String; //Interface defined using template syntax typedef IEnum<char *> IEnumString; ... interface IStringManager { virtual IEnumString* EnumStrings(void) = 0; }; ... void SomeFunc(IStringManager * pStringMan) { char * psz; IEnumString * penum; penum=pStringMan->EnumStrings(); while (S_OK==penum->Next(1, &psz, NULL)) { //Do something with the string in psz and free it } penum->Release(); return; }
- Attempt to get the next
celt
items in the enumeration
sequence.
IEnum::Next()
HRESULT IEnum::Next(
ULONG celt,
ELT_T* rgelt,
ULONG* pceltFetched
);
Attempt to get the next
celt
items in the
enumeration sequence, and return them through the array pointed to by
rgelt.
If fewer than the requested number of elements remain
in the sequence, then just return the remaining ones; the actual number of
elements returned is passed through *pceltFetched
(unless
it is
NULL
).
If the requested
celt
elements are in fact returned, then return
S_OK
; otherwise
return
S_FALSE
.
An error condition other than simply ``not
that many elements left'' will return an
SCODE
which is
a failure code rather than one of these two success values.
The number of elements that are to be returned.
An array of size at least celt in which the next elements are to be returned. [Footnote 62]
May be
NULL
if
celt
is
one.
If non-NULL
, then this is set with
the number of elements actually returned in
rgelt.
S_OK
Success. On exit all the celt elements requested are valid and returned in rgelt.
S_FALSE
Success.
On exit only the first *pceltFetched
entries
of
rgelt
are valid.
The contents of the remaining
entries
in the
rgelt
array are indeterminate.
E_UNEXPECTED
An unknown error occurred. On exit no entries in the rgelt array are valid; they are all in an indeterminate state.
- Attempt to skip over the next
celt
elements in
the enumeration sequence.
IEnum::Skip()
HRESULT IEnum::Skip(
ULONG celt
);
Attempt to skip over the next
celt
elements
in the enumeration
sequence.
Return
S_OK
if this was accomplished, or
S_FALSE
if the end of the sequence was reached first.
The number of elements that are to be skipped.
S_OK
Success. The requested number of elements were skipped.
S_FALSE
Success. Some skipping was done, but the end of the sequence was hit before the requested number of elements could be skipped.
E_UNEXPECTED
An unknown error occurred.
- Reset the enumeration sequence back to the beginning.
IEnum::Reset()
HRESULT IEnum::Reset(
void
);
Reset the enumeration sequence back to the beginning.
Note that there is no intrinsic guarantee that exactly the same set of objects will be enumerated the second time as was enumerated the first. Though clearly very desirable, whether this is the case or not is dependent on the collection being enumerated; some collections will simply find it too expensive to maintain this condition. Consider enumerating the files in a directory, for example, while concurrent users may be making changes.
S_OK
Success. The enumeration was reset to its beginning.
E_UNEXPECTED
An unknown error occurred.
- Return another enumerator which contains exactly the same enumeration state
as this one.
IEnum::Clone()
HRESULT IEnum::Clone(
IEnum<ELT_T>** ppenum
);
Return another enumerator which contains exactly the same enumeration state as this one. Using this function, a client can remember a particular point in the enumeration sequence, then return to it at a later time. Notice that the enumerator returned is of the same actual interface as the one which is being cloned.
Caveats similar to the ones found in
IEnum::Reset()
regarding
enumerating the same sequence twice apply here as well.
The place in which to return the clone enumerator.
S_OK
Success. The enumeration was reset to its beginning.
E_UNEXPECTED
An unknown error occurred.