为什么 VBA 的 VarType 函数说这个 COM 对象是一个字符串? (对象是 .NET System.Object class 的 COM 版本的实例。)这是一个错误吗?
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?
问题总结
当我使用 VBA 的 VarType
function, passing it an instance of the Object
class available in a mscorlib.dll library reference (a .NET 库引用时,returned 的值是 8
。
根据 VBA 文档 here,这意味着该对象是一个字符串。这看起来很可笑。
我的问题是为什么 VarType
函数 return 从 .NET 库 VBA参考?这是一个错误吗?
背景资料
我怀疑 VBA 的 VarType
函数是在说某个 COM 对象是一个字符串,这可能就是我在使用 DispCallFunc
函数时遇到问题的原因在某些 COM 对象的某些方法上。 COM 对象是 .NET 对象的 COM 版本,可通过 .NET 框架获得。
我正在使用 mscorlib.dll VBA 引用来获取这些对象的早期绑定功能。该参考指的是 .NET 框架的 4.0.30319 版。在我的电脑上,引用的类型库存储在:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb.
当对象方法指定参数或 return 值的类型为 System.Object
时,DispCallFunc
似乎对我不起作用。无论如何,这是一个单独的问题,是这个问题专门针对的问题的间接问题。
在撰写本文时,我是 运行 Excel 的最新版本(版本 1903,内部版本 11425.20202)。我的操作系统是 Windows 8.1.
当我将 VarType
函数与 mscorlib.dll 库中的其他 class 实例一起使用时,我有时会得到 9
的 return 值 & 13
(VbVarType.vbObject
& VbVarType.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))
到 return 9
、13
或其他一些适当的整数。相反,它 returned 8
似乎根本不合适(8
代表字符串。)
我认为部分问题是 VBA 在某些情况下计算表达式(也许有人可以添加更多关于 when/why 这种情况的信息)。因此,当您调用 VarType(o)
时,o
变量实际上被转换为字符串表示形式,并且采用了类型。
例如,如果您写 Debug.Print o
,输出将是 System.Object
。如果您在不同的具体对象上写 Debug.Print x
,系统可能会抛出错误。
尝试以下语法:
Debug.Print VarType(o.GetType)
在我的例子中,returns 值 13。
查看 object.cs
的 reference source,我没有看到任何 [DispId]
属性,但假设第一个成员被 [DispId(0)]
编组,这将使ToString
方法 COM 类型的 默认成员 .
这是我对 Debug.Print o
输出 System.Object
的唯一解释,而不是像通常没有默认成员那样出现错误 438。
所以问题不在于 .NET/COM 互操作,而在于处理从具有默认成员的对象中获取元数据:您将遇到与任何 COM 对象完全相同的问题具有 String
个默认成员:
?VarType(Application), VarType(Application.Name)
8 8
我想不出让 VarType
使用这些的方法。另一方面,TypeOf...Is
检查工作正常:
?TypeOf Application Is Object
True
因此:
Debug.Print TypeOf o Is Object ' True
例如,如果您使用 OleView 打开 typeLib C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb
,并导航至 _Object
界面(不是第一个 _Object 界面,调度界面,而是第二个界面),您会看到这个:
因此,.NET 方法 Object.ToString()
向 COM/Automation 客户端声明为
[id(00000000), propget, custom(54FC8F55-38DE-4703-9C4E-250351302B1C, 1)]
HRESULT ToString([out, retval] BSTR* pRetVal);
这意味着 COM 客户端会将此 "syntactic sugar"(VB/VBA/VBScript/JScript/.NET 等)理解为 属性 (propget + out + retval) named ToString
that returns a String (BSTR).
现在,id(0)
表示它是默认属性,因为0代表DISPID_VALUE,一个特殊的众所周知的id。
最后,VB/VBA VarType's documentation 指出:
If an object has a default property, VarType(object) returns the type
of the object's default property.
(我总是发现一个非常奇怪的设计决定...)
问题总结
当我使用 VBA 的 VarType
function, passing it an instance of the Object
class available in a mscorlib.dll library reference (a .NET 库引用时,returned 的值是 8
。
根据 VBA 文档 here,这意味着该对象是一个字符串。这看起来很可笑。
我的问题是为什么 VarType
函数 return 从 .NET 库 VBA参考?这是一个错误吗?
背景资料
我怀疑 VBA 的 VarType
函数是在说某个 COM 对象是一个字符串,这可能就是我在使用 DispCallFunc
函数时遇到问题的原因在某些 COM 对象的某些方法上。 COM 对象是 .NET 对象的 COM 版本,可通过 .NET 框架获得。
我正在使用 mscorlib.dll VBA 引用来获取这些对象的早期绑定功能。该参考指的是 .NET 框架的 4.0.30319 版。在我的电脑上,引用的类型库存储在:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb.
当对象方法指定参数或 return 值的类型为 System.Object
时,DispCallFunc
似乎对我不起作用。无论如何,这是一个单独的问题,是这个问题专门针对的问题的间接问题。
在撰写本文时,我是 运行 Excel 的最新版本(版本 1903,内部版本 11425.20202)。我的操作系统是 Windows 8.1.
当我将 VarType
函数与 mscorlib.dll 库中的其他 class 实例一起使用时,我有时会得到 9
的 return 值 & 13
(VbVarType.vbObject
& VbVarType.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))
到 return 9
、13
或其他一些适当的整数。相反,它 returned 8
似乎根本不合适(8
代表字符串。)
我认为部分问题是 VBA 在某些情况下计算表达式(也许有人可以添加更多关于 when/why 这种情况的信息)。因此,当您调用 VarType(o)
时,o
变量实际上被转换为字符串表示形式,并且采用了类型。
例如,如果您写 Debug.Print o
,输出将是 System.Object
。如果您在不同的具体对象上写 Debug.Print x
,系统可能会抛出错误。
尝试以下语法:
Debug.Print VarType(o.GetType)
在我的例子中,returns 值 13。
查看 object.cs
的 reference source,我没有看到任何 [DispId]
属性,但假设第一个成员被 [DispId(0)]
编组,这将使ToString
方法 COM 类型的 默认成员 .
这是我对 Debug.Print o
输出 System.Object
的唯一解释,而不是像通常没有默认成员那样出现错误 438。
所以问题不在于 .NET/COM 互操作,而在于处理从具有默认成员的对象中获取元数据:您将遇到与任何 COM 对象完全相同的问题具有 String
个默认成员:
?VarType(Application), VarType(Application.Name)
8 8
我想不出让 VarType
使用这些的方法。另一方面,TypeOf...Is
检查工作正常:
?TypeOf Application Is Object
True
因此:
Debug.Print TypeOf o Is Object ' True
例如,如果您使用 OleView 打开 typeLib C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.tlb
,并导航至 _Object
界面(不是第一个 _Object 界面,调度界面,而是第二个界面),您会看到这个:
因此,.NET 方法 Object.ToString()
向 COM/Automation 客户端声明为
[id(00000000), propget, custom(54FC8F55-38DE-4703-9C4E-250351302B1C, 1)]
HRESULT ToString([out, retval] BSTR* pRetVal);
这意味着 COM 客户端会将此 "syntactic sugar"(VB/VBA/VBScript/JScript/.NET 等)理解为 属性 (propget + out + retval) named ToString
that returns a String (BSTR).
现在,id(0)
表示它是默认属性,因为0代表DISPID_VALUE,一个特殊的众所周知的id。
最后,VB/VBA VarType's documentation 指出:
If an object has a default property, VarType(object) returns the type of the object's default property.
(我总是发现一个非常奇怪的设计决定...)