Wednesday, May 6, 2026

VBA.NET, no such thing

 Another day, another lovely point of friction on the managed/native border. I was trying to instantiate and call the .NET class System.Security.Cryptography.HMACSHA256 from an Excel macro.

Visual Basic for Applications (VBA) is a perfectly capable COM/Automation client, and the class in question is exposed to COM. Its ProgID is System.Security.Cryptography.HMACSHA265, and the object instantiates without a hitch. Now, the method that I initially wanted - ComputeHash - is overloaded, there are several flavors with different parameter sets. The classic COM (pre-IInspectable) identifies dispinterface methods by names, no support for overloading. VBA would let you disambiguate with a numeric postfix, instead of ComputeHash you'd have ComputeHash , ComputeHash_2, etc. But which postfix corresponds to which overload?

The method name mangling is documented, but the signature/postfix correspondence is not explained. The doc says: "x starts at 2 and increments for each overloaded form of the method", but doesn't say anything about the order of overloads. I have a strong suspicion it follows the physical order of member records in the class metadata, which is the same order as Type.GetMethods() return, but no hard evidence to that effect.

Type library to the rescue, I thought. A typelib would contain mangled method names and their parameter sets, or so I thought. The class/dispinterface in question declares a typelib, statically even, it's mscorlib.tlb under the .NET framework 4 directory. Surprise - if the typelib is to be believed, the dispinterface _HMACSHA256 has no methods. Zero, none, bupkis. No properties, either. Neither does _HashAlgorithm, where the method is declared. I even reexported the typelib using tlbexp - same contents.

Oh well, thought I, so static typelib is no good, let's go with dynamic. Write a C++ client, get IDispatch, get ITypeInfo and list the methods. Another surprise - only 7 functions in the interface, 3 IUnknown ones and 4 IDispatch ones. Another dead end.

OK, so the type info is no good. But IDispatch can work without providing a typeinfo, right? The results were surprising:

  • Calling IDispatch.GetIDsOfNames on ComputeHash returns a DISPID, 0x6002000d
  • Calling ITypeInfo.GetIDsOfNames on the same name returns DISP_E_UNKNOWNNAME
  • Calling ITypeInfo.GetNames with 0x6002000d as the DISPID  returns TYPE_E_ELEMENTNOTFOUND

It's almost as if the implementation of IDispatch is logically within .NET, and inspects the CLR types as it should, and the implementation of ITypeInfo that it returns is somehow elsewhere and is not .NET aware.

At the end of the day, I made the VBA code work with nonoverloaded methods, but the underlying issue remains. Something funny is going on with reflecting the type info of that datatype to the COM world.

No comments:

Post a Comment