为什么VBA的VarType函数说这个COM对象是一个字符串? (Object是.NET的System.Object类的COM版本的实例。)这是一个错误吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么VBA的VarType函数说这个COM对象是一个字符串? (Object是.NET的System.Object类的COM版本的实例。)这是一个错误吗?相关的知识,希望对你有一定的参考价值。

问题摘要

当我使用VBA的VarType函数时,将它传递给Object库引用(mscorlib.dll库引用)中可用的.NET类的实例,返回的值是8

根据VBA文档here,这意味着对象是一个字符串。这看起来很荒谬。

我的问题是为什么VarType函数从.NET库VBA引用返回此Object类的实例的字符串类型值?这是一个错误吗?

背景资料

我怀疑VBA的VarType函数说某个COM对象是一个字符串,这可能就是为什么我在某些COM对象的某些方法上使用DispCallFunc函数时遇到问题。 COM对象是.NET对象的COM版本,可通过.NET框架获得。

我正在使用mscorlib.dll VBA引用来获取这些对象的早期绑定功能。该引用指的是.NET框架的4.0.30319版。在我的计算机上,引用的类型库存储在:

T:ювиндовсюйцрософт.Нетюфрамеворкювч.0.30319мсорлиб.тлб。

看起来当对象方法指定参数或返回值是System.Object类型时,DispCallFunc无法为我工作。无论如何,这是一个单独的问题,对于这个问题所致的问题是间接的。


At the time of writing, I'm running the latest version of Excel (Version 1903, Build 11425.20202). My operating system is Windows 8.1.

当我使用VarType函数与mscorlib.dll库中的其他类的实例时,我有时会得到913VbVarType.vbObjectVbVarType.vbDataObject常量)的返回值,这似乎是正确的。

我在互联网上研究是否有其他人遇到过这个问题但却找不到任何东西。

可用于重现问题的代码

Dim o As mscorlib.Object
Set o = New mscorlib.Object
Debug.Print "TypeName(o) = " & TypeName(o) ' TypeName function seems to work correctly.
Debug.Print "o.Equals(o) = " & o.Equals(o) ' System.Object.Equals method is working.

Debug.Print "VarType(CVar(o)) = " & VarType(CVar(o)) ' IMPORTANT LINE
' VBA VarType function says o is string (type 8) but it isn't?!

Debug.Print "VbVarType.vbString = " & VbVarType.vbString

我期望VarType(CVar(o))返回913或其他一些适当的整数。相反,它返回了8,这似乎根本不合适(8代表字符串。)

答案

例如,如果用C:WindowsMicrosoft.NETFrameworkv4.0.30319mscorlib.tlb打开typeLib OleView,并导航到_Object接口(不是第一个_Object,接口,但第二个),你会看到:

enter image description here

因此,.NET方法Object.ToString()被声明为COM / Automation客户端

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

这意味着COM客户端将其理解为“语法糖”(VB / VBA / VBScript / JScript / .NET等)作为名为ToString且返回字符串(BSTR)的属性(propget + out + retval)。

现在,id(0)意味着它是默认属性,因为0代表DISPID_VALUE,一个特殊的知名id。

最后,VB / VBA VarType's documentation说:

如果对象具有默认属性,则VarType(object)返回对象的默认属性的类型。

(我总是发现一个非常奇怪的设计决定...)

另一答案

看看reference sourceobject.cs,我没有看到任何[DispId]属性,但假设第一个成员被[DispId(0)]编组,这将使ToString方法成为COM类型的默认成员。

这是我对Debug.Print o输出System.Object的唯一解释,而不是像通常没有默认成员那样炸出错误438。

因此问题不在于.NET / COM互操作,而在于处理从具有默认成员的对象中获取元数据:对于具有String默认成员的任何COM对象,您将遇到完全相同的问题:

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

我想不出有什么方法可以让VarType使用它们。另一方面,TypeOf...Is检查工作正常:

?TypeOf Application Is Object
True

因此:

Debug.Print TypeOf o Is Object ' True
另一答案

我认为问题的一部分是VBA在某些情况下评估表达式(也许有人可以添加更多关于何时/为何发生这种情况的信息)。因此,当您调用VarType(o)时,o变量实际上被转换为字符串表示形式,并且类型被采用。

例如,如果你写Debug.Print o,输出将是System.Object。如果在不同的具体对象上编写Debug.Print x,系统可能会抛出错误。

请尝试以下语法:

Debug.Print VarType(o.GetType)

在我的情况下,返回值13。

以上是关于为什么VBA的VarType函数说这个COM对象是一个字符串? (Object是.NET的System.Object类的COM版本的实例。)这是一个错误吗?的主要内容,如果未能解决你的问题,请参考以下文章

使用来自另一个模式的数据的 Oracle SQL 函数说表或视图不存在

Java 函数的参数说

理解Javascript的原型链

异步编程之Javascript Promises 规范介绍

excel函数 value是啥意思

后台获取离子配置