I just discovered that I can create some .Net classes from VBA using the CreateObject method which can create COM classes. This is pretty cool but the created class is late bound so you don't get any intellisense etc. So what I hoped to do was write VBA wrapper classes and delegate all the method calls to an internal reference to the .Net object.
So this works well for an ArrayList object for everything but trying to reference the enumerator. There is a hack for VBA which allows you to create your own collections and use the For Each ... syntax to enumerate your collections. The following is an example:
Public Property Get NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
Attribute NewEnum.VB_MemberFlags = "40"
Set NewEnum = <<< pass a reference to the enumerator here.
End Property
Most implementations hold a reference to a VBA Collection object and pass the enumerator for the Collection object. However since I am holding a .Net ArrayList I'd like to pass that out. However I get "Invalid procedure call or argument" when I try.
My current attempt is this:
Public Function NewEnum() As IUnknown
Dim enumerator As Object
Set enumerator = internalList.GetEnumerator() <<<< Error occurs here.
Set NewEnum = enumerator
End Function
I'm pretty sure that its possible to make this work because it is possible to iterate the ArrayList collection directly without the wrapper. E.g.
Public Sub TestCreateArrayList()
Dim list As Object
Set list = CreateObject("System.Collections.ArrayList")
list.Add "an item."
list.Add "another item."
Dim Item As Variant
For Each Item In list
Debug.Print Item
Next
End Sub
I can live without the For Each functionality but it would be nice if I could get it to work especially when it seems like its almost there.
Edit: Its probably worth mentioning that instantiating an ArrayList and then calling GetEnumerator yields the same error even outside of a wrapper class.
Further edit: Note that trying to set a variable of type IUnknown to the result of the GetEnumerator method still gives the same error.
Public Sub TestCreateArrayList()
Dim list As Object
Set list = CreateObject("System.Collections.ArrayList")
Dim iterator As IUnknown
Set iterator = list.GetEnumerator() <<<< error occurs here.
End Sub
Final Edit: Thanks to @RegEdit's comments below I was able to get this to work and thought I'd add the code:
Private internalList As Object
Private Sub Class_Initialize()
' create a .Net Array list for the internal data store.
Set internalList = CreateObject("System.Collections.ArrayList")
End Sub
Private Sub Class_Terminate()
If Not internalList Is Nothing Then
On Error Resume Next
internalList.Dispose
Err.Clear
End If
End Sub
Public Function NewEnum() As IUnknown
Attribute NewEnum.VB_UserMemId = -4
Dim enumerator As IUnknown
Set enumerator = internalList.GetEnumerator(0, internalList.Count)
Set NewEnum = enumerator
End Function
' ... other wrapped methods elided