#com-interface #intercom #object #class

nightly app intercom-utils

查看 'intercom'

1个不稳定版本

使用旧Rust 2015

0.2.0 2017年12月10日

#15 in #com-interface

MIT许可证

185KB
4.5K SLoC

Intercom

用于在Rust中编写COM组件的工具

crates.io Build Status codecov

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一起使用时遇到可用性问题,请随意创建一个描述问题的issue。

跨平台考虑

尽管COM传统上是Windows技术,但Intercom旨在提供一种平台独立的方式来在Rust和其他语言之间执行方法调用。这为Intercom提供了两个指导原则:

  1. 存在一组Intercom API/约定子集,允许用户编写可在任何平台上编译和使用的Intercom组件。
  2. 在具有自己的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 入口点以及 CoClassClassFactory 的实现。
  • [com_interface(IID)] - 一个属性,它指定了一个 trait 或一个 impl 作为COM接口。该属性将定义接口的虚表结构。
  • [com_class(CLSID, Itfs...)] - 定义在 struct 上的一个属性。此属性实现了结构所需的 CoClass,这允许在对象上构造引用计数的 ComBox<T> 实例。

依赖关系

~3MB
~58K SLoC