Visual Basic for Applications has a very nice object called
Collection. In VC++ there is no such object, which is a shame (in my opinion).
I searched MSDN and it turned out there is a sample called ATLCollections. This project has 2 collections. First is a collection of
BSTRs and second one is a
VARIANT collection which is using
CComBSTRs as keys. I wanted to use only
VARIANTs to be comparable with the scripting languages so neither one was an option.
Next step was to search the Web. I found one on www.widgetware.com written by Chris Brooks and another one by Chris Sells (www.sellsbrothers.com). Both were template-based and I did not want to use the templates. So I decided to write my own collection object.
According to MSDN a Collection object is an ordered set of items that can be referred to as a unit. The Collection object provides a convenient way to refer to a related group of items as a single object. The items, or members, in a collection need only be related by the fact that they exist in the collection. Members of a collection don't have to share the same data type.
Once a collection is created, members can be added using the
Add method and removed using the
Remove method. Specific members can be returned from the collection using the
Item method, while the entire collection can be iterated using the
For Each...Next statement.
It means that a collection is a COM object that has 3 properties and 2 methods:
_NewEnum, though in technical literature you may find that only
_NewEnum are necessary for the object to be called the collection.
My collection defines the interface
IXCollection implemented by the class
The IDL looks like this:
interface IXCollection : IDispatch
[id(1), helpstring("Adds a member to a collection")]
HRESULT Add([in] VARIANT vItem, [in, optional] VARIANT vKey);
[id(2), helpstring("Removes a member from a collection")]
HRESULT Remove([in] VARIANT vIndex);
[propget, id(3), helpstring("Returns the number of members in a collection")]
HRESULT Count([out, retval] long * plNumber);
[propget, id(DISPID_VALUE), helpstring("Returns a specific member of a
collection either by position or key")]
HRESULT Item([in] VARIANT vIndex, [out, retval] VARIANT * pvItem);
// 'restricted' IDL attribute is used to indicate that this property is
// not to be displayed to the user.
[propget, restricted, id(DISPID_NEWENUM), helpstring("Method _NewEnum")]
HRESULT _NewEnum([out, retval] IUnknown ** ppUnk);
Now lets talk a little about each method and property.
Adds items to the collection. You can add items to the collection using the optional vKey parameter. If key is used the individual item can be accessed using this key.
Removes items from the collection either by the index or by the key.
Returns the number of items in the collection.
Returns an individual item either by the index or by the key. If the index is a number it’s 1-based. This property is given the standard id
DISPID_VALUE to make it as the "default" property to simplify its use in Visual Basic and scripting languages.
Returns an enumerator object that contains collection items allowing the client sequential access. This property is assigned the standard id
DISPID is used by Visual Basic to implement its
For-Each syntax. The
_NewEnum property returns an enumerator object that supports standard
IEnumVARIANT interface. The
IEnumVARIANT interface is a collection of Variants. It allows clients to enumerate heterogeneous collections of objects and intrinsic types when the clients cannot or do not know the specific type(s) of elements in the collection.
For detailed coverage of the collections and enumerators I refer you to “ATL Internals” by B. Rector, C. Sells and “Professional ATL COM Programming” by R. Grimes.
The download file contains ShoppingCart project that implements the collection as well as a C++ test application.