今天出现了一个有趣的问题。假设我有一个.NET对象,它实现了某个接口IMyInterface,并且也是COM Visible。
现在,我从ProgID加载类型并转换为强类型接口,如下所示:
IMyInterface objEarlyBound = null;
Type t = Type.GetTypeFromProgID("My.ProgId");
objLateBound = Activator.CreateInstance(t);
objEarlyBound= (IMyInterface)objLateBound;
objEarlyBound.Method();
如果我执行上面的代码,当objEarlyBound.Method()执行时,我是调用COM对象还是直接调用.NET对象?我怎么能以这种或那种方式证明这一点?
答案 0 :(得分:3)
RCW应该是(据我所知)特殊类型System .__ ComObject,但是你可能要做的就是调用Marshal.IsComObject,它会告诉你对象是否是运行时包装器。在快速测试中,COM通过该路由创建的对象最终成为直接管理对象并丢失COM包装器。
答案 1 :(得分:2)
你无论如何都无法证明这一点 - 这是一个故意隐瞒你的内部实施选择。
objEarlyBound
和objLateBound
必须具有相同的标识,即==
将返回true。因此,从它们中的每一个,您总是可以获得另一个,并且同样支持它们支持的任何其他接口,并且如果您将它们中的任何一个分配给object
。但这并不能证明什么。
如果您直接引用包含通过COM公开的类My.ProgId
的程序集,您可以说:
IMyInterface objEarlyBound = new MyClassExposedThroughCOM();
此时根本不需要CLR的COM支持。但是,然后您可以将该对象传递给某个外部COM库,此时CLR将创建一个CCW以与该对象关联。并且已经完成了一次,对于任何给定的CLR对象,它总是可以回到相同的CCW。
因此,为了将它与您的示例相关联,您可以在COM对象周围使用RCW,将其转换为接口,此时CLR可以(据我们所知)查询特殊的内部COM接口,如果找到,允许它获取内部CLR对象,从而完全绕过COM。如果它在任何时候需要回到CCW,它可以这样做,因为它必须能够在向另一个方向工作的任何时候这样做。
我尝试在手工实现的C ++ COM对象的QueryInterface函数中放置一个断点,以查看CLR查询的内容。基本上它会尝试很多东西,其中一些我无法立即识别出来,所以它很可能会“嗅探”一个CLR对象。这样做是有道理的,以避免疯狂的COM三明治情况,其中CLR引用指向RCW,RCW指向CCW,指向CLR对象。通过让CLR引用直接指向CLR对象,可以清楚地简化这一点。
实际上现在我考虑一下,它不需要查询就可以找到它:它有一个以前生成的CCW全局表,所以它可以在那里查找任何新的IUnknown
。 COM对象必须始终返回IUnknown
的完全相同的地址,以便它可用于对象标识比较。因此,CLR始终可以识别它正在实现的COM对象,并获取相应的CLR对象。
顺便说一下,所有这些讨论都假定COM对象正在进行中。如果它是在进程外,那么情况就完全不同了;每个进程都有自己的CLR实例,因此也可以使用进程间编组的COM实现。