I am designing a COM wrapper for a C++ library using ATL. Currently I am a little bit confused about enumerators that are based on ATL collections. I already wrote several enumerators based on STL collections, but since there is no ICollectionOnATL
-interface (such as the ICollectionOnSTL
-interface), I am a little bit confused if my implementation is correct.
Here is how I am creating the enumerator at the moment:
STDMETHODIMP CCollectionOnATL::get_NewEnum(IEnumITEM** enumerator)
{
// IItem implements IUnknown.
typedef CInterfaceArray<IItem> Container;
typedef CComEnum<IEnumITEM, &IID_IEnumITEM, IItem*, _CopyInterface<IItem>> CComEnumITEM;
// Copy all elements to an array that can be enumerated.
Container items;
auto elements = m_coll.GetCount();
//items.SetCount(elements);
// See below for the definition of m_coll.
POSITION pos = m_coll.GetHeadPosition();
for (size_t element = 0; element < elements; element++)
{
auto current = m_coll.GetNext(pos);
// Automatically calls AddRef!
items.Add(current->m_value);
}
// Create an enumerator over the array.
// Using `new` is valid here (since enumerators do not implement FinalConstruct).
CComObject<CComEnumITEM>* pEnum = new CComObject<CComEnumITEM>();
pEnum->Init(&items[0], &items[elements - 1], nullptr, ATL::AtlFlagTakeOwnership);
// Return the enumerator.
return pEnum->QueryInterface(enumerator);
}
The member m_coll
is defined as CRBMap
:
CRBMap<ULONG, IItem*> m_coll;
There are some points with this implementation, where I am not really sure if I understood them correctly:
Iterating the
CRBMap
should give me an ordered list, where the lowest key is the first and the highest key is the last element. However, I am not sure if there's a "better" (in terms of simplicity) way to perform the iteration.Usage of
CInterfaceArray
to initialize the enumerator:pEnum->Init(&items[0], &items[elements - 1], nullptr, ATL::AtlFlagTakeOwnership);
Is the initialization correct? Especially I am wondering about the third parameter, that references an
IUnknown
-instance to keep alive for as long as the enumerator lives. Currently I am passingnullptr
, but I think the right value should be theitems
-array, which however does not implementIUnknown
.Regarding the enumerator initialization: Was my choose of
ATL::AtlFlagTakeOwnership
correct in here? I am not completely sure, because the actual ownership of the instances is taken bym_coll
.Since the size of the final array is known, I could initialize it (and therefor prevent relocations/copy-steps) using
items.SetCount(elements);
. However, the MSDN only states thatCInterfaceArray::Add
automatically callsAddRef
. There's no information aboutSetAt
oroperator[]
. Could I simply change the way I add items to the array toitems[element] = current->m_value;
without any change in the behaviour of reference counting?
Also if you have any suggestions on how I can further improve this code, please let me know!