Objective Toolkit : Chapter 30 Introduction to Objective Toolkit for ATL : COM Collection Classes
COM Collection Classes
The COM collection classes are used as base classes for a collection object to create an Automation compatible COM collection object. These classes appear in the object models of Microsoft Office applications, such as Word and Excel. For example, Excel exposes a Worksheets collection object, which you can use to Add, Remove, or retrieve a contained Worksheet object. You can easily create your own collection of objects using the OTL Collection Wizard. OTL examines the IDL for the project to create a list of the possible object types the collection can contain. An object type can be a custom or dual interface name, or generic IDispatch pointer. The generated collection object also supports the _NewEnum() method that Visual Basic clients expect when using For/Each enumeration syntax.
The wizard is a modified simple ATL Object Wizard that creates an ATL object that inherits from one of the OTL collection implementation classes. Select a base class that suits your internal collection implementation, which is based on your performance and indexing criteria:
CComCollection—A custom linked list implementation that does not have Standard Template Library (STL) dependencies. This class supports object retrieval by string key or by index.
CComCollectionOnSTLMap—Implemented on an STL map container, this class is a specialized case of the more general CComCollectionOnSTLAssoc, which takes any STL associative container, such as the map<> class, as a template argument. This class supports object retrieval by string key or by index.
CComCollectionOnSTLAssoc—The only base class not specifically supported by the collection wizard, this class requires a complete STL associative container type specification as a template parameter. The collection type must support value pairs with a _bstr_t (or other BSTR compatible type with a < operator) as the first value and the object interface pointer type as the second value. CComCollectionOnSTLMap is a predefined derivation for the common use case of an STL map.
CComCollectionOnSTL—For retrieval by numeric index only, this class is a thin wrapper for the ATL ICollectionOnSTLImpl class, using ATL's CComEnumOnSTL as the enumeration mechanism. This class is suitable for STL sequence containers, such as vector and list, which access items by numeric index, not string key. All CComCollectionOnSTL methods and data members are inherited from the ATL class ICollectionOnSTLImpl (atlcom.h), which currently supports the Item, Count, and _NewEnum COM collection members. This class requires an STL sequence container type specification as a template parameter, as the following code section from the Cars sample illustrates:
 
#include <vector>
#include <OtlComCollectionSTL.h>
#include "carobj.h"
 
class ATL_NO_VTABLE CCarsDual :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CCarsDual, &CLSID_CarsDual>,
public CComCollectionOnSTL<ICarObj,
std::vector<ICarObj*>, IDispatchImpl<ICarsDual, &IID_ICarsDual, &LIBID_CARCOLLECTIONLib> >
{
The wizard creates a fully functional collection object. If you need to populate the collection before exposing the object to clients, override FinalConstruct(), and use the Add() method of your new collection object to build the collection. The Add() method is implemented by the OTL collection base class, which is the class from which your object derives, so it is not listed in your collection objects header file.
The exception to this population rule is CComCollectionOnSTL, which does not support the Add() method because it’s derived from ATL’s ICollectionOnSTLImpl class. In this case, you can populate the collection by directly accessing the underlying STL container. The container is always available in the m_coll data member. The following code is a CComCollectionOnSTL-derived collection object populating itself with predefined objects:
 
HRESULT FinalConstruct()
{
CComObject<CCarObj>* pCar;
ICarObj* pICar = NULL;
for(int i = 0; i < NUMOBJECTS; i++)
{
CComObject<CCarObj>::CreateInstance(&pCar);
if(SUCCEEDED(pCar->QueryInterface(IID_ICarObj, (void**)&pICar)))
{
pICar->put_ID(i+1);
AddItem(pICar);
pICar->Release();
}
}
return S_OK;
}
 
void AddItem(ICarObj* pICar)
{
ATLASSERT(pICar);
pICar->AddRef();
m_coll.push_back(pICar);
}