为什么在使用COM时,TypeName()从.GetType和TypeOf返回不同的结果? [英] Why does TypeName() return different results from .GetType and TypeOf when working with COM?

查看:389
本文介绍了为什么在使用COM时,TypeName()从.GetType和TypeOf返回不同的结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我觉得我将从理解这些函数的工作方式的差异中受益匪浅,以便我更好地理解何时使用每个函数。

I feel like I would benefit greatly from understanding the differences in how these functions work so that I could better understand when to use each one.

我遇到了一个非常困难的时期使用两个不同的互操作(Excel和EPDM),它们都大量使用弱类型的参数。我一直遇到问题使用返回的对象,并将它们转换为正确的类型(根据文档)。浪费了很多时间后,我发现使用 TypeName GetType TypeOf操作符与COM对象可以产生不同的结果,在不同的情况下每个可以更多或者比下一个更不可靠。

I'm having a very difficult time working with two different interops (Excel, and EPDM) which have both made extensive use of weak typed parameters. I keep running into problems using returned objects and casting them to the proper type (per the documentation). After wasting a ton of time, I've found that using TypeName, GetType, and a TypeOf operator with COM objects can yield different results, and in different circumstances each one can be more or less reliable than the next.

现在,在大多数情况下, TypeName()似乎是确定COM对象类型最可靠的。然而,避免其他两个功能完全看起来很容易我,除此之外,我遇到一个有趣的问题其中我似乎不能把一个对象转换为 TypeName()报告的类型。在对该问题的评论中提出了一个有趣的概念,实现 IDispatch 的对象实际上可能返回 接口typename,差异。

Now, in most cases TypeName() seems to be the most reliable for determining type with COM objects. However, avoiding the other two functions entirely seems quite cargo cultish to me, and besides that today I ran into an interesting problem where I can't seem to cast an object to the type reported by TypeName(). An interesting notion was brought up in the comments on that problem that objects which implement IDispatch may actually return the dispatched interface typename, which could partially explain the differences.

我真的想更好地了解这些函数是如何工作的,但我通过 .NET ReferenceSource ,所以我提供一个赏金这个问题,希望有人能解释这些不同的函数如何工作,在什么上下文中使用。

I'd really like to better understand how these functions actually work, but I get kind of lost running through the .NET ReferenceSource, so I'm offering a bounty on this question in hopes someone can explain how these different functions work and in what context each should be used.

以下是使用Excel互操作的代码摘录。

Here is a code excerpt from working with the Excel interop.

Dim DocProps As Object 
DocProps = WeeklyReports.CustomDocumentProperties 'WeeklyReports is a Workbook object
Debug.Print(DocProps Is Nothing)
Debug.Print(TypeName(DocProps))
Debug.Print(TypeOf (DocProps) Is DocumentProperties)
Debug.Print(DocProps.GetType.ToString)

输出为:


False

DocumentProperties

False

系统.__ ComObject

False
DocumentProperties
False
System.__ComObject


推荐答案

这是一个长的故事,有点怀疑,英语会削减它。它需要了解COM的工作原理以及它如何集成到Office产品中。

It is a long story and a bit doubtful that English is going to cut it. It does require understanding how COM works and how it was integrated into the Office products.

在突破速度下,COM非常重要的是

At breakneck speed, COM is very heavily an interface-based programming paradigm at its core. Interfaces are easy, classes are hard. Something you see back in the .NET design as well, a class can derive from only one single base class but can implement any number of interfaces. To make language interop work smoothly, it is important to take as few dependencies on language implementation details as possible.

有很多COM不做,你会用于任何现代语言。它不支持异常,只有错误代码。没有泛型的概念。没有反思。不支持方法重载。不支持实现继承,类的概念被完全隐藏。它只显示为一个数字,CLSID,一个标识类类型的guid。使用在COM组件中实现的工厂函数创建类的对象。 COM组件保留该对象的所有权。客户端代码然后只使用接口进行调用以使用方法和获取或设置属性。 CoCreateInstance()是执行此操作的主要运行时支持功能。

There is a lot that COM does not do that you'd be used to in any modern language. It does not support exceptions, only error codes. No notion of generics at all. No Reflection. No support for method overloads. No support for implementation inheritance whatsoever, the notion of a class is completely hidden. It only appears as a number, the CLSID, a guid that identifies a class type. With a factory function implemented in the COM component that creates an object of the class. The COM component retains ownership of that object. The client code then only ever uses interfaces to make calls to use methods and get or set properties. CoCreateInstance() is the primary runtime support function that does this.

这进一步削减到一个名为OLE自动化的子集,您在与Office互操作时使用的风味。它严格限制类型的类型,你可以使用的属性和方法参数用规定的方法来处理像字符串和数组这样的困难。它会添加一些功能,它支持通过IDispatch接口的后期绑定,对脚本语言很重要。和VARIANT,一种可以存储任意类型的值或对象引用的数据类型。并支持类型库,COM服务器实现的接口的机器可读描述。 .NET元数据是完全类似的。

This was further whittled down to a subset called OLE Automation, the flavor that you use when you interop with Office. It strictly limits the kind of types you can use for properties and method arguments with prescribed ways to deal with the difficult ones like strings and arrays. It does add some capabilities, it supports late binding through the IDispatch interface, important to scripting languages. And VARIANTs, a data type that can store a value or object reference of an arbitrary type. And supports type libraries, a machine-readable description of the interfaces implemented by the COM server. .NET metadata is the exact analogue.

这个问题很重要,它限制了一个类可以实现的接口数量 。对于不支持接口概念的语言(例如VBA,JavaScript和VBScript等脚本语言以及早期的Visual Basic版本)非常重要。

And important to this question, it limit the number of interfaces that a class can implement to just one. Important to languages that don't support the notion of interfaces at all, like VBA, scripting languages like Javascript and VBScript and early Visual Basic versions. The Office interop object model was very much designed with these limitations in mind.

因此,从使用这种语言的程序员的角度来看,Office程序自动化的Office程序,它完全不可见他的语言运行时实际上使用接口。他在程序中看到和使用的所有标识符都是类名,而不是接口名。 DocumentProperties 实际上是 接口名称是您在对象浏览器中可以看到的。只需在搜索框中键入名称,它就会正确地注释右下方面板中的public interface DocumentProperties / Microsoft.Office.Core成员。

So from the point of view from a programmer that uses such a language to automate an Office program, it is completely invisible that his language runtime is actually using interfaces. All he ever sees and uses in his program are identifiers that look like class names, not interface names. That DocumentProperties is actually an interface name is something you can see in Object Browser. Just type the name in the search box, it properly annotates "public interface DocumentProperties / Member of Microsoft.Office.Core" in the lower-right panel.

一个特定的细节的Office对象模型在这里很重要,许多属性和方法返回类型是VARIANT。可以存储任意值或对象引用的OLE自动化类型,当使用.NET时,它将映射到System.Object。 Workbook.CustomDocumentProperties 属性是这样。即使该属性被记录为实际返回一个DocumentProperties接口引用。他们可能这样做离开肘房间到某天返回另一种界面。 自定义文档属性非常必要。

One specific detail of the Office object model matters a great deal here, many properties and method return types are VARIANTs. A OLE Automation type that can store an arbitrary value or object reference, it is mapped to System.Object when you use .NET. The Workbook.CustomDocumentProperties property is like that. Even though the property is documented to actually return a DocumentProperties interface reference. They probably did this to leave elbow room to some day return another kind of interface. Fairly necessary for "custom document properties".

属性是一个VARIANT在支持动态类型的语言中并不重要,他们采取步骤。然而在强类型语言中它是相当痛苦的。而且对于支持自动完成的编程编辑器(如VS的IntelliSense)非常不友好。通常 是将变量声明为预期的接口类型:

That the property is a VARIANT doesn't matter that much in languages that support dynamic typing, they take them with stride. It is however pretty painful in a strongly typed language. And pretty unfriendly to programming editors that support auto-completion, like VS's IntelliSense. What you normally do is declare your variable to the expected interface type:

  Dim DocProps As DocumentProperties
  DocProps = CType(WeeklyReports.CustomDocumentProperties, Microsoft.Office.Core.DocumentProperties)

一切都亮起来。你不需要CType()转换,如果你喜欢编程VB.NET与选项严格关闭效果。

And now everything lights up. You don't need the CType() cast either if you favor programming VB.NET with Option Strict Off in effect. Which turns it into a programming language that supports dynamic typing well.

我们到达那里。只要将DocProps声明为 Object ,编译器就会知道接口的bean。也不是调试器,它没有帮助的变量声明,只能看到它是一个 __ System.ComObject 从运行时类型。所以它不是Nothing,很容易理解,属性getter没有失败,并且文档有属性。

We're getting there. As long as you declare DocProps as Object then the compiler knows beans about the interface. Nor does the debugger, it isn't helped by the variable declaration and can only see that it is a __System.ComObject from the runtime type. So it isn't Nothing, that's easy enough to understand, the property getter did not fail and the document has properties.

TypeName 函数使用IDispatch接口的一个特性,它在运行时公开类型信息。这发生在你的情况下工作,通常不会,函数首先调用 IDispatch :: GetTypeInfo()以获取ITypeInfo接口引用,然后调用 ITypeLib :: GetDocumentation()。这工作,你得到的接口名称回来。否则可以相当于在.NET中的反射,只是没有几乎同样强大。

The TypeName() function uses a feature of the IDispatch interface, it exposes type information at runtime. That happens to work in your case, it usually doesn't, the function first calls IDispatch::GetTypeInfo() to get an ITypeInfo interface reference, then calls ITypeLib::GetDocumentation(). That works, you get the interface name back. Otherwise pretty comparable to Reflection in .NET, just not nearly as powerful. Do not rely on it heavily, there are lots of COM components that don't implement this.

对你的问题至关重要, TypeOf(DocProps )是DocumentProperties 是一个失败的鲸鱼。当你尝试写我之前提出的代码时,你会发现的东西。你会得到一个讨厌的运行时异常System.InvalidCastException:

And crucial to your question, TypeOf (DocProps) Is DocumentProperties is a fail whale. Something you'll discover when you try to write the code I proposed earlier. You'll get a nasty runtime exception, System.InvalidCastException:


{无法投射类型为System .__ ComObject的COM对象接口类型Microsoft.Office.Core.DocumentProperties。此操作失败,因为COM组件上的QueryInterface调用与IID'{2DF8D04D-5BFA-101B-BDE5-00AA0044DE52}'的接口失败,原因是以下错误:No such接口支持(来自HRESULT的异常:0x80004002(E_NOINTERFACE))}

{"Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.Office.Core.DocumentProperties'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{2DF8D04D-5BFA-101B-BDE5-00AA0044DE52}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE))."}

换句话说,Excel文档向你说明。您获得的类似于 DocumentProperties的接口,它仍然具有此接口记录的成员,但不再与Microsoft.Office.Core.DocumentProperties相同。它可能曾经是,许多月前。隐藏在此知识库文章中的一个讨厌的细节:

In other words, the Excel documentation is lying to you. You get an interface back that resembles DocumentProperties, it still has the members that this interface documents, but is no longer identical to the Microsoft.Office.Core.DocumentProperties. It probably once was, many moons ago. A nasty little detail that's buried inside this KB article:


注意DocumentProperties和DocumentProperty接口是后绑定接口。要使用这些接口,必须像处理IDispatch接口一样对待它们。

Note The DocumentProperties and the DocumentProperty interfaces are late bound interfaces. To use these interfaces, you must treat them like you would an IDispatch interface.

这篇关于为什么在使用COM时,TypeName()从.GetType和TypeOf返回不同的结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆