Home » excel » excel – Using .NET HashTable Return Type in VBA

excel – Using .NET HashTable Return Type in VBA

Posted by: admin May 14, 2020 Leave a comment

Questions:

I have created a .NET library in VB.NET and there is a function that returns an object of HashTable.

I have been searching for how to access the elements in the HashTable object in Excel VBA but can’t find a solution. I am new to VBA so pardon me. I have searched but can’t find a way out.

For instance, after something like this, I don’t know how to access the data.

   Dim hashData As Object
   Set hashData = obj.getHashData

Please help

How to&Answers:
Dim hashData As Object
Set hashData = obj.getHashData

If getHashData is returning a HashTable, then hashData is a late-bound HashTable, and you can invoke its members, including its Item property:

Dim value As Variant
value = hashData.Item("key")

You’re not getting compile-time validation on the late-bound member calls against Object, so you need to be particularly careful for typos, because Option Explicit cannot save you when late binding is involved. Refer to the HashTable documentation linked above for what members you can invoke.

Adding a reference to mscorlib.tlb (you’ll find it under C:\Windows\Microsoft.NET\Framework\v4.0.30319, or reference the equivalent from \Framework64 if your Excel is 64-bit – bitness of the library needs to match the bitness of the host application) would normally allow for early binding, but while this library is COM-visible, it’s intended to be used from managed (.net) code, so you’re accessing these objects from interfaces – the concrete types don’t expose any members directly:

object browser showing no members for Hashtable class

Knowing that Hashtable implements the IDictionary interface, we can use early binding and get compile-time validation and IntelliSense if we declare hashData As IDictionary:

Dim hashData As mscorlib.IDictionary
Set hashData = New mscorlib.Hashtable
hashData.Add "foo", 42
Debug.Print hashData.Item("foo") 'prints 42

Note that the Item property is exposed as the default member:

members of IDictionary

This means you can have the Item member call implicit, exactly as you could do with any standard VBA collection object:

Dim hashData As mscorlib.IDictionary
Set hashData = New mscorlib.Hashtable
hashData.Add "foo", 42
Debug.Print hashData("foo") 'prints 42

Early-bound code is much easier to write, especially when you’re not familiar with the types involved. However if the project is referencing the 64-bit framework and your macros need to run on 32-bit Excel, you’ll want to stick to late binding to avoid binding issues.

Also note, iterating the Hashtable object with a For Each loop isn’t going to work, because of how enumerators work in VBA vs how they work in .NET; the Keys and Values collections are objects implementing the ICollection interface, so iterating them will be non-trivial as well: a For Each loop won’t work, and while you can set up a For i = 0 To hashData.Keys.Count - 1, you can’t get the item at index i from an ICollection.

But we know that ICollection inherits IEnumerable, and IEnumerable does work with For Each, so we can cast the Keys collection to IEnumerable, and iterate all keys and values like so:

Dim hashData As mscorlib.IDictionary
Set hashData = obj.getHashData

Dim hashKeys As mscorlib.IEnumerable
Set hashKeys = hashData.Keys

Dim k As Variant
For Each k In hashKeys
    Debug.Print k, hashData(k) 'outputs the key and its associated value
Next

The problem is that you can’t cast to IEnumerable with late-bound code or without a reference to mscorlib.tlb, and late binding somehow won’t see the GetEnumerator member, so this raises error 438:

Dim hashKeys As Object
Set hashKeys = hashData.Keys

Dim k As Variant
For Each k In hashKeys ' error 438, hashKeys isn't exposing the enumerator
    Debug.Print k, hashData(k) 
Next

Conclusion: if you need the VBA code to run on both 32 and 64 bit hosts, you’ll have to jump through hoops to get late-bound code to work. I would recommend working early-bound with the 64-bit framework if you’re on a 64-bit host, and distributing a separate copy of the macro that references the 32-bit framework for 32-bit hosts. A bit of a pain to distribute, but less painful than getting late bound code to work.