10

在这个相关问题中,我注意到 Visual Studio 的调试器能够枚举System.__ComObject引用的属性,这是“当包装器类型不明确时使用的隐藏类型”——例如,当你从另一个获取它时获得的对象类型COM 对象,不要自己实例化它:

COM 对象调试视图

此外,如果您只是将 COM 对象的标识符写入即时窗口,它的属性和值也会被类似地转储:

COM 对象立即窗口

请注意,这与 VS2010 的“动态视图”是分开的,我相信它使用IDispatch和 COM 反射来枚举 COM 对象的属性,而不使用 PIA 和 .NET 反射。我正在使用的对象没有实现IDispatch(它们也没有为此实现IProvideClassInfo),因此,“动态视图”无法获取有关它们的任何信息:

动态视图

有趣的是,SharpDevelop的调试器无法列出System.__Comobjects 的成员(例如point.Envelope),只能列出强类型的 RCW(例如point)。

SharpDevelop 调试器

那么 Visual Studio 是如何做到的呢?

我相信在这种情况下,这是因为主互操作程序集存在这些对象支持的接口的定义,并且 Visual Studio 很可能使用反射来枚举支持的接口和属性。那准确吗?如果是这样,它是如何工作的?

首先,它如何访问 PIA?它只查看当前加载的 PIA 还是动态加载它们(如果是,如何加载)?它如何确定枚举属性的接口,其中可以有很多?它似乎只使用一个,不一定是第一个。从我正在使用的 API的文档IUnknown(ArcObjects)来看,这些对象的默认接口是,因此它也不仅仅是使用默认接口。

在屏幕截图的示例中,它枚举成员的接口是IEnvelope接口,它继承自IGeometry接口。VS2010怎么知道不枚举成员IGeometry,在我的测试中,如果你只枚举PIA中的所有接口类型,它首先出现?发生了一些非常聪明的事情,或者我错过了一些明显的事情?

我问的原因是,如果LINQPad 的开发人员知道 VS 是如何做到的,他似乎愿意实现相同的功能。因此,这里的一个好的答案可以大大有助于改进这个非常流行的工具。

4

1 回答 1

2

这是如何做到的:

  • 获取 COM 对象的IDispatch(替代可能的路径是IDispatchEx
  • 获取类型库的引用——IDispatch::GetTypeInfo
  • 加载类型库并枚举属性
  • 查询真实对象以获取已发现属性的值

其他增强选项适用:查询IPersist*接口系列或IProvideClassInfo获取对象类型库的引用并发现属性。

于 2013-02-10T13:49:15.660 回答