为什么不能通过.NET中的COM使用.NET COM库?

时间:2013-02-21 23:32:41

标签: .net com

现在,我知道如果库是在.NET中,通过COM访问它有点没有意义,但是,我有点困惑,因为如果我要求别人写一个库并通过它公开它COM,那个人应该可以用任何语言自由地这样做。

对我来说,写入COM库的语言并不重要,为什么重要?

作为参考,这是在从.NET库生成的.tlb文件上使用tlbimp时会发生的情况:

C:\dev>tlbimp test.tlb
Microsoft (R) .NET Framework Type Library to Assembly Converter 4.0.30319.1
Copyright (C) Microsoft Corporation.  All rights reserved.

TlbImp : error TI1029 : Type library 'test' was exported from
a CLR assembly and cannot be re-imported as a CLR assembly.

此外,我的测试COM库使用IUnknown,仅支持早期绑定的COM互操作。

2 个答案:

答案 0 :(得分:13)

tlbimp只是问题的开始。

每个COM可见的.NET对象都实现IManagedObject。每次尝试通过COM接口调用对象时,.NET都会为IManagedObject执行QueryInterface,如果成功,则会直接打开并直接访问该对象。以这种方式消除互操作调用被认为是性能优化。

这是基于COM的互操作方案中的一个严重问题,其中多个组件可能以.NET语言实现。如果每个.NET组件都实现了自己的tlbimp生成的COM接口版本,那么它们将无法使用该接口相互通信。尽管每个tlbimp的接口副本都具有相同的COM GUID,但.NET认为它们是单独的接口。 "正确"这个问题的解决方案是在主互操作程序集中定义COM接口,并让每个.NET实现的组件使用相同的接口副本,但是如果组件开发人员之间没有协调那么漂亮不太可能发生。

这个问题曾经由http://blogs.msdn.com/b/jmstall/archive/2009/07/09/icustomqueryinterface-and-clr-v4.aspx的Microsoft开发人员以及.NET 4的解决方案突出显示,但它基于预发布版本,并且在最终版本中不起作用。我不知道微软已经承认了其他任何地方。

一种解决方案是放弃.NET-to-.NET场景中的界面并改为使用反射。这可能在许多情况下有效,但当然不是很有效。可能最好的解决方案是使用非托管代码来聚合每个托管组件,并拒绝对IManagedObject的QueryInterface的尝试。这类似于上面博客条目中描述的内容,但并不依赖于那些不再像该博客中描述的那样工作的.NET功能。

.NET互操作行为是IMO,非常糟糕,并且明显违反了COM规则(相同的IID ==相同的界面,并且不应该关心实现对象的语言)。但是.NET从一开始就表现得如此,开发人员对这种行为所引发的反馈意见没有改变.NET团队中任何人的想法。

答案 1 :(得分:4)

Tlbimp可以从类型库中看到它是从.NET程序集生成的。它只是在你正在尝试做什么。这没有意义,如果你想使用.NET程序集,那么只需添加对它的引用。

您可以使用后期绑定的COM欺骗机器,最容易使用C#中的 dynamic 关键字。这仍然不会欺骗CLR,它可以看到它与托管程序集交互并且实际上不会创建COM可调用包装器。您通常这样做是为了编写测试程序来测试COM服务器。这意味着您的测试实际上并未测试COM服务器在实践中的使用方式。非常基本的东西,如将变体转换为对象和返回只是根本不会被测试。当您在生产中使用组件时,可能会给您带来非常不愉快的意外。