COM是如何实现语言互操作的



我理解COM如何实现编译器无关的C++代码,因为它通过小心使用C++语言的哪些功能来定义ABI。这只是C++代码以一种非常聪明的方式与C++代码对话。然而,我仍然不明白它如何允许与C#或Javascript进行语言互操作。

边界在哪里?我现在唯一的解释是,语言编译器本身必须对COM有特殊的支持,这样它才能生成正确的汇编代码,以便在调用者/被调用者之间进行准确的通信。

既然您已经用WinRT标记了您的问题,我想您是在专门询问WinRT语言投影是如何实现这一点的。在这种情况下,所有语言都必须有某种方法将其自然语言构造映射到WinRT定义的COM ABI。该ABI源自ECMA335标准中编码的元数据,并且应用特殊规则将抽象元数据转换为具体ABI。实现这一点自然有不同的方法。CLR本身已更新为支持C#中的WinRT。Visual C++编译器(遗憾地)更新了语言扩展,以通过C++/CX支持WinRT。C++/WinRT方法的不同之处在于,它只需要一个标准的C++编译器,并且所有关于WinRT的知识都是通过一个标准C++头库提供的。其他语言可能会采取不同的方法,但最终他们必须就元数据中表达的类型转换为对象的方式达成一致,并在基于COM.的ABI上调用虚拟函数

虽然这个过程目前还没有很好的文档记录,但C++/WinRT是唯一的开源语言投影之一,因此对于那些需要了解WinRT如何在后台工作的人来说,它是一个有用的参考实现。

https://github.com/microsoft/cppwinrt

"类型库"支持不同语言之间COM组件的互操作。

https://learn.microsoft.com/en-us/windows/desktop/midl/com-dcom-and-type-libraries

类型库(.tlb)是一个二进制文件,用于存储COM或DCOM对象的属性和方法的形式可在运行时访问其他应用程序。使用类型库应用程序或浏览器可以确定对象的接口支持和调用对象的接口方法。这种情况可能发生即使对象和客户端应用程序是用不同的语言编写的编程语言。COM/DCOM运行时环境也可以使用一种类型库,以及类型中描述的接口的跨机封送图书馆。

语言互操作的另一种方法(例如C++将对象投影到Javascript)是COM对象可以实现IDispatch。

当然,这不是魔法。

COM为语言互操作设置规则。这只是一份合同,有一些有用的工具。每种想要支持COM的语言都必须找到自己遵守规则的方法。它们都必须以某种方式提供自己的兼容机制。

在C++的情况下,正如您所提到的,这些规则似乎是免费的,但请注意,有一点需要注意:语言标准没有指定类和虚拟函数的布局和机制。COM模仿的方法是一种非常常见的虚拟调用("VTable")实现,COM遵循Microsoft编译器使用的确切布局。但是,在具有虚拟函数的类与COM布局不兼容的情况下,可以使用完全有效的C++编译器。只是没有人这么做,至少在Windows编译器中没有。因此,即使在C++中,编译器也会有一些"中间相遇"。

在C语言中,你必须手工完成整个过程。其他语言可能允许您做同样的事情(当然是汇编程序)。

为了帮助编译后的语言交换有关特定约定的信息,COM提供了类型库和读取它们的机制。想要利用它们的编译器或语言还必须"在中间相遇"并学习如何处理它们(例如,Microsoft C++#import指令;VB6库菜单)。

并不是每种语言都能支持COM中所能做的一切,因为在某种程度上(在更模糊的功能中),在该语言中实现支持的投资回报是无法实现的。每种语言都有自己的局限性。在COM中可以做很多VB6不能做的事情(阅读IDL规范)

因为在类似脚本的语言中遵循COM规则介于不切实际和不可能之间,COM提供了一种更高级的方法(Automation),它更适合动态语言,即使更受限制。但是,想要为Automation提供客户端支持的语言实现者必须实现对IDispatch接口的理解、激活机制以及对其语言适当设施的翻译。想要为创建COM服务器提供支持的脚本语言必须更加努力地实现有效的COM IDispatch实现和代表用户脚本的独立主机引擎。即使是VBScript一开始也无法做到这一点,直到微软在Windows脚本主机上添加了.SCR支持。再次"在中间相遇"。

如果一种语言想要同时支持纯COM和Automation,它们需要加倍努力;对其中一方的支持不会自动给予你对另一方的支撑。

对于像C#这样的.NET语言,大部分工作都是在.NET运行时内为本机COM和Automation完成的,它提供了与COM交互所需的COM可调用包装器(CCW)和运行时可调用包装程序(RCW)的实现,以及处理COM的引用计数方法和.NET的GC方法之间的冲突。Microsoft在一个地方完成了所有的工作,因此单个.NET语言设计者不必这样做。

因此,是的,语言实现者必须额外工作,为该语言提供对COM的特殊支持:遵循二进制布局规则,在需要时实现翻译层,和/或可能提供读取类型库的工具。

语言互操作要求双方(调用者和被调用者)在某个地方"在中间相遇"。COM只是一种规范,它为设计师提供了一个中间地带,"一个所有人都可以见面的地方"。

最新更新