Delegating the iterator


There’s just one more step to make CDrivesO a real collection—a step so bizarre that I’m embarrassed to describe it. But I’m going to put the literary equivalent of a bag over my head and forge ahead.


If you write a collection in another language, you have to create a method named _NewEnum. When a programmer codes a For Each block using your collection class, Visual Basic calls the _NewEnum method to create a hidden iterator object that implements the IEnumVARIANT interface. This object is essentially an iterator like the ones we created earlier with the CListWalker class. For each time through the loop, the Next method of the iterator object gets the next item in the collection.


In order for you to get Visual Basic to use your collection with For Each, you have to give your collection a _NewEnum that will delegate its creation of the enumeration object to the internal Collection. This is easier said than done, and easier shown than explained:

‘ NewEnum must have the procedure ID -4 in Procedure Attributes dialog
Public Function NewEnum() As IEnumVARIANT
Set NewEnum = drives.[_NewEnum]
End Function

The first peculiarity about this method is that it’s named NewEnum rather than _NewEnum; this is because underscores are illegal as the first character of Visual Basic symbol names. The second peculiarity is that, legal or not, the Collection class has a _NewEnum method, and you’ll have to delegate whatever it does to your NewEnum property. One of the more obscure features of Visual Basic is that you can access illegal names by putting them in square brackets. The third peculiarity is that NewEnum returns an IEnumVARIANT type. This is the type of the iterator in the Collection class. (Some samples in other books use IUnknown as the return type, but it comes to the same thing.)


The last and most outstanding peculiarity is how you tell Visual Basic that your NewEnum method is really the _NewEnum method. It’s a simple recipe. You mix together eye of newt, toe of frog, wool of bat, and tongue of dog…. No, wait. That’s a different kind of magic. In this case, you assign a magic number to the procedure ID in the Dialog Box From Hell (DBFH). Figure 4-3 shows you how.



Figure 4-3. Assigning the magic ID to NewEnum.

As you might remember, the Procedure ID combo box in the DBFH has several entries, including (None), (Default), AboutBox, and a bunch of other irrelevant nonsense. But it doesn’t have an entry for NewEnum, _NewEnum, or any other name that matches what you want. Fortunately, the Procedure ID value is set with an ordinary combo box that allows you to either select one of the suggested entries or type in your own. That’s what you do: you type in the magic ID number, which is—drumroll please—negative four.

FLAME This magic works, even though it violates all standards of Basic decency. This is formula stuff. There’s no room for creativity. ­Computers are better than humans at following formulas. Visual Basic is supposed to make things easy. You ought to be able to simply click a check box to indicate that you want this class to be a collection. You could then select which internal Collection variable you wanted to delegate to (in the unlikely event there was more than one internal Collection). Visual Basic would automatically create the NewEnum property. It wouldn’t be as easy as inheritance, but at least it wouldn’t be an object of ridicule.