The CDriveWalker class


You don’t have to go far to figure out that the CDriveWalker class is a little unusual. Take a look at the first few lines of code:

‘ Implement Basic-friendly version of IEnumVARIANT
Implements IVariantWalker
‘ Delegate to class that implements real IEnumVARIANT
Private vars As CEnumVariant
‘ Connect back to parent collection
Private connect As CDrives

We’re going to implement a nice, friendly Basic-style interface (IVariantWalker) that does all the stuff the For Each syntax expects us to do. But because the real IEnumVARIANT is so Basic-hostile that we can’t afford to deal with its horrors every time we want to write a collection, we’ll delegate to a CEnumVariant
ob­ject, which will actually implement IEnumVARIANT. When your client code hits a For Each block, Visual Basic will think CEnumVariant is an IEnumVARIANT (if you implement it, you are it) and will call its methods. Those methods will, in turn, through a process too horrible to describe, call the IVariantWalker
methods, which will iterate through the collection. Figure 4-4 on the following page tries to make sense of the whole iteration mess.



Figure 4-4. The whole iteration mess.


In real life, you can ignore most of the details; just implement IVariantWalker and delegate it to CEnumVariant. Here’s the internal data the CDriveWalker class uses to maintain its position and connections:

‘ Private state data
Private i As Long

Private Sub Class_Initialize()
‘ Initialize position in collection
i = 1
‘ Connect walker to CEnumVariant so it can call methods
Set vars = New CEnumVariant
vars.Attach Me
End Sub

CDriveWalker also needs methods and properties to receive a connection from the CDrives collection and to pass a connection back from the CEnumVariant object (vars) to the CDrives collection (which will pass it back to the client program).

‘ Receive connection from CDrives
Sub Attach(connectA As CDrives)
Set connect = connectA
End Sub

‘ Return IEnumVARIANT (indirectly) to client collection
Friend Property Get NewEnum() As IEnumVARIANT
Set NewEnum = vars
End Property

Finally, with all this paperwork out of the way, you can actually write the code to move to the next item, skip some items, and reset the iteration.

Private Function IVariantWalker_More(v As Variant) As Boolean
‘ Find the next drive and return it through reference
Do While i <= 26
‘ Check flags to see if next drive exists
If MBytes.RShiftDWord(connect.DriveFlags, i - 1) And 1 Then
Dim drive As CDrive
Set drive = New CDrive
drive.Root = i
Set v = drive
IVariantWalker_More = True
i = i + 1
Exit Function
End If
i = i + 1
Loop
End Function

Private Sub IVariantWalker_Skip(c As Long)
‘ Skip ahead in the iteration
i = i + c
End Sub

Private Sub IVariantWalker_Reset()
‘ Reset the iteration
i = 1
End Sub

The More method (which would be named Next if Visual Basic allowed it) is the most important method and the only one called by For Each. Notice how it returns a Boolean indicating whether there are more items and also returns the next item through a reference parameter.


The Skip and Reset methods are not called by For Each, but they are called by the Locals window in the IDE. If it looks like a miracle that Visual Basic can display all the items in a collection before you’ve even iterated through them, well, it’s not—although it is remarkable. The Locals window is iterating, skipping, and resetting behind the scenes to display the parts of the collection you request. If you have enough patience and memory, you can verify that the Locals ­window actually has limits—it won’t display more than 256 items in a collection.


If all this sounds complicated, you ain’t seen nothin’ yet. And you don’t need to see nothin’. The Collection Wizard can write all the repetitive hack code, leaving you to worry only about how your collection works. We’ll take a look in a few pages.