Why is VBA's VarType function saying this COM object is a string? (Object is instance of COM version of .NET's System.Object class.) Is it a bug?

萝らか妹 提交于 2019-12-01 06:03:58

If you open the typeLib C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb with OleView for example, and navigate to the _Object interface (not the first _Object one, the dispinterface, but the second one) you'll see this:

So, the .NET method Object.ToString() is declared to COM/Automation clients as

[id(00000000), propget, custom(54FC8F55-38DE-4703-9C4E-250351302B1C, 1)]
HRESULT ToString([out, retval] BSTR* pRetVal);

Which means it's seen to COM clients that understand this "syntactic sugar" (VB/VBA/VBScript/JScript/.NET, etc.) as a Property (propget + out + retval) named ToString that returns a String (BSTR).

Now, id(0) means it's the default property, because 0 represents DISPID_VALUE, a special well-known id.

And lastly, VB/VBA VarType's documentation states this:

If an object has a default property, VarType(object) returns the type of the object's default property.

(which I always found a pretty strange design decision...)

Looking at the reference source for object.cs, I'm not seeing any [DispId] attributes, but assuming the first member gets marshaled with [DispId(0)], that would make the ToString method the COM type's default member.

That's the only explanation I have for Debug.Print o outputting System.Object, rather than blowing up with error 438 as it normally would without a default member.

So the problem isn't so much with .NET/COM interop, rather it's about dealing with getting metadata out of an object that has a default member: you would have the exact same problem with any COM object that has a String default member:

?VarType(Application), VarType(Application.Name)
 8             8 

I can't think of a way off the top of my head to make VarType work with these. On the other hand, a TypeOf...Is check works fine:

?TypeOf Application Is Object
True

Hence:

Debug.Print TypeOf o Is Object ' True

I think a part of the problem is that VBA evaluates expressions in certain cases (maybe someone can add more information on when/why this happens). So, when you make the call to VarType(o), the o variable is actually being converted to a string representation, and the type is taken.

As an example, if you write Debug.Print o, the output will be System.Object. If you write Debug.Print x on a different, concrete object, the system will possibly throw an error.

Try the following syntax:

Debug.Print VarType(o.GetType)

In my case, that returns the value 13.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!