In COM, collections are objects that contain a logical grouping of items and support a means of navigating these contained items. Although collections can contain simple types, the most common examples are collections of COM objects exposed through application Automation object models. Object models came into vogue as an application extensibility mechanism. By exposing a hierarchy of an application's objects and collections through dispatch interfaces, you can write macros to automate certain tasks. In this chapter, we'll look at the kinds of collections you might find in such an object model.
In 1994, Charlie Kindel described the "Six Commandments of OLE Automation Collections" (see the MSDN article "Implementing OLE Automation Collections" in the online help), which are the foundation of collections in Microsoft Office products (and many other products). Collections are a vital part of the object model in many applications and services. For example, a Microsoft ActiveX Data Object (ADO) recordset has a Fields collection, which is a grouping of Field objects, as shown in Figure 15-1.
Figure 15-1. Fields collection in ADO.
The properties and methods of a collection object vary depending on the privileges granted to a user of the collection. A collection object usually exposes methods to add, remove, delete, and retrieve items from the collection. The ability to iterate over the items in the collection is inherent to collections. Kindel's article outlines recommended standards for these properties and methods of a collection object. Table 15-1 shows these properties and methods.
Table 15-1. Standard Properties and Methods of a Collection Object.
|Add method||Adds the indicated item to the collection||Yes|
|Count property||Returns the number of items in the collection||No|
|Item method||Returns the indicated item in the collection; returns VT_EMPTY if the item doesn't exist||No|
|_NewEnum property||Returns an object that supports IEnumVARIANT (This method isn't visible to users.)||No|
|Remove method||Removes the specified item from the collection||Yes|
Although the properties and methods shown in Table 15-1 are fairly standard, in reality the signatures and names for collection properties and methods vary widely across applications. The Item method is usually given the predefined dispatch ID DISPID_VALUE, which makes the Item method the default member of the collection. The default member is implied when using an object in Microsoft Visual Basic unless another member is specified.
A collection is enumerated using a COM-defined iteration contract, which has a couple of distinct advantages over other enumeration possibilities:
Flow control is supported by the Next method, which allows the caller to pull as many items from the enumerator as it wants in a single call. For/Each is a Visual Basic loop statement that makes it simple for Visual Basic users to obtain an enumerator object and manipulate the object using its IEnumVARIANT interface.
Imagine a COM object that represents a data acquisition and control board supporting both analog input and analog output. The board could be modeled with a top-level object named AnalogBoard that contains two collections: Inputs and Outputs. The Inputs collection contains Input objects, and the Outputs collection contains Output objects. Input and Output objects support the Value property to read and write the device I/O. A Visual Basic client can read the data from each of the analog Input objects in sequence using a For/Each loop, like this:
Dim Board1 As New COLLECTIONSERVERLib.AnalogBoard Private Sub Form_Load() Dim AnalogInColl As COLLECTIONSERVERLib.Inputs Set AnalogInColl = Board1.Inputs Dim AnalogIn As COLLECTIONSERVERLib.Input Debug.Print "**** Analog Input Values ****" For Each AnalogIn In AnalogInColl Debug.Print AnalogIn.Value Next End Sub
The _NewEnum property returns such an enumerator object to the client. _NewEnum also has a predefined dispatch ID: DISPID_NEWENUM. The terms enumerator and iterator are used interchangeably throughout this chapter.
In the rest of the chapter, we'll look at the ATL classes that help build the collection objects just described and the enumerator objects for those collections.