4个版本 (破坏性更新)
0.4.0 | 2022年7月2日 |
---|---|
0.3.0 | 2019年10月1日 |
0.2.0 | 2017年12月10日 |
0.1.0 | 2017年11月5日 |
#465 in 过程宏
150KB
3.5K SLoC
Intercom
Rust编写COM组件的实用工具
Intercom允许用户在Rust中编写可重用的组件,这些组件与组件对象模型接口标准二进制兼容。这些组件可以用于支持静态COM组件的任何语言,包括C++、C#和VB.Net。
示例
Rust COM服务器
pub use intercom::*;
com_library! {
class Calculator
}
#[com_class(Calculator)]
struct Calculator {
value: i32
}
#[com_interface]
impl Calculator {
pub fn add(&mut self, value: i32) -> ComResult<i32> {
self.value += value;
Ok(self.value)
}
}
C# COM客户端
class Program
{
[STAThread]
static void Main( string[] args )
{
var calc = new Calculator.Interop.Calculator();
calc.Add( 10 );
var result = calc.Add( 100 );
Console.WriteLine( result );
}
}
其他crate
Intercom不是Rust第一次与COM接口互动。至少还有两个与COM支持相关的crate。
winapi-rs
包含了Microsoft Windows API的各种COM接口定义。winrt-rust
为Rust提供了对Windows Runtime (WinRT) API的支持。
理想情况下,这些crate可以很好地协同工作。如果您在使用这些crate与Intercom一起时遇到可用性问题,请自由地创建一个问题来描述该问题。
跨平台考虑因素
虽然COM传统上是Windows技术,但Intercom旨在提供一种平台无关的方式,以便在Rust和其他语言之间执行方法调用。这为Intercom提供了两个指导原则
- 存在Intercom API/约定的子集,允许用户编写可以在任何平台上编译和使用的Intercom组件。
- 在具有自己的COM API的平台,Intercom组件与平台API和预期兼容。
在实践中,这意味着例如在Windows上,Intercom将使用SysAllocString
分配字符串。这允许Intercom组件与Windows技术(如.Net COM互操作)一起使用。
但是,平台无关子集将需要使用IIntercomAllocator
分配和释放字符串。
技术细节
背景
COM(组件对象模型)是基于虚拟表(也称为调度表)的使用。有一个导出的符号,即 DllGetClassObject
,客户端(使用COM模块的代码片段)使用它来获取初始的 IClassFactory 接口。一旦客户端拥有 IClassFactory 接口,其余的方法调用就可以通过COM接口来完成。
每个COM接口都由一个包含虚拟表和服务器(实现接口的库)所需任何数据的对象表示。当客户端尝试在接口上调用方法时,它将使用虚拟表来解决正确的方法地址,并使用Pascal调用约定(在大多数C++编译器中为 __stdcall
,在Rust中为 "stdcall"
)进行调用。
实现
Intercom库是在Rust的过程宏属性之上构建的。目前有四个属性可用
com_library!(LIBID, Classes...)
- 这是一个必需的属性,它实现了导出的DllGetClassObject
入口点以及ClassFactory
的CoClass
。[com_interface(IID)]
- 这是一个属性,它指定了一个trait
或一个impl
作为COM接口。该属性会导致为接口定义一个虚拟表结构。[com_class(CLSID, Itfs...)]
- 这是在一个struct
上定义的属性。这个属性实现了所需的CoClass
,允许在对象上构建引用计数的ComBox<T>
实例。
依赖项
~2.5MB
~55K SLoC