#com #macro #ffi #com-interface #windows

com_macros

COM宏crate

6个版本 (breaking)

0.6.0 2021年10月25日
0.5.0 2021年10月5日
0.4.0 2021年1月27日
0.3.0 2020年10月21日
0.1.0 2019年10月1日

#290Windows API

Download history 16863/week @ 2024-03-14 19603/week @ 2024-03-21 18834/week @ 2024-03-28 14321/week @ 2024-04-04 17250/week @ 2024-04-11 18996/week @ 2024-04-18 18469/week @ 2024-04-25 16920/week @ 2024-05-02 14321/week @ 2024-05-09 16229/week @ 2024-05-16 17977/week @ 2024-05-23 18826/week @ 2024-05-30 17990/week @ 2024-06-06 20510/week @ 2024-06-13 17456/week @ 2024-06-20 18072/week @ 2024-06-27

77,171 每月下载量
571 个crate中使用(通过 com

MIT 许可证

72KB
1.5K SLoC

COM

Build Status crates.io Docs.rs

Rust中与COM编程相关的所有事情的综合性商店。

此库向用户公开了各种宏、结构和函数,用于以惯用的方式产生和消费COM组件。

🚨 🚨 🚨 注意 此crate目前正在积极开发中,因为我们正在决定稳定API。 🚨 🚨 🚨

什么是COM?

COM 是一个平台无关的、分布式的、面向对象的系统,用于创建可以交互的二进制软件组件。

COM已经被WinRT 取代,WinRT基于COM提供更多关于二进制接口的保证。因此,如果您不确定是否需要使用COM,可能不应该使用。

用法

定义COM接口

要通过接口消费或产生COM组件,您首先需要生成该接口的Rust表示。`interfaces`宏是自动生成此Rust表示的主要工具。

com::interfaces! {
    #[uuid("00000000-0000-0000-C000-000000000046")]
    pub unsafe interface IUnknown {
        fn QueryInterface(
            &self,
            riid: *const IID,
            ppv: *mut *mut c_void
        ) -> HRESULT;
        fn AddRef(&self) -> u32;
        fn Release(&self) -> u32;
    }

    #[uuid("EFF8970E-C50F-45E0-9284-291CE5A6F771")]
    pub unsafe interface IAnimal: IUnknown {
        fn Eat(&self) -> HRESULT;
    }
}

简要说明:此操作会生成IUnknown和IAnimal的VTable布局以及正确的`Clone`和`Drop`实现。

消费COM组件

与COM组件的交互始终是通过接口指针(指向VTable的指针的指针)进行的。

use com::run_time::{create_instance, init_runtime};

// Initialises the COM library
init_runtime().expect("Failed to initialize COM Library");

// Get a COM instance's interface pointer, by specifying
// - The CLSID of the COM component
// - The interface of the COM component that you want
// create_instance returns an IAnimal interface in this case.
let mut cat = create_instance::<IAnimal>(&CLSID_CAT_CLASS).expect("Failed to get a cat");

// All IAnimal methods will be available.
// Because we are crossing an FFI boundary, all COM interfaces are marked as unsafe.
// It is the job of the programmer to ensure that invariants beyond what the COM library guarantees are upheld.
unsafe { cat.Eat(); }

有关用法和安全的更多信息,请参阅文档

产生COM组件

与消费相比,生成 COM 组件相对复杂,因为我们必须支持许多功能。在这里,我们将向您演示如何生成我们的一些示例之一,即 BritishShortHairCat

  1. 定义包含您想要的所有用户字段的类。
  • 指定类实现的每个接口。您必须列出接口的父接口(除非指定了 IUnknown,默认情况下没有父接口),例如:: MyInterface(MyParentInterface(MyGrandParentInterface)), MyOtherInterface
  1. 在类上实现必要的接口。
use com::class;

com::class! {
    pub class BritishShortHairCat: ICat(IAnimal), IDomesticAnimal(IAnimal) {
        num_owners: u32,
    }
    
    impl IDomesticAnimal for BritishShortHairCat {
        fn Train(&self) -> HRESULT {
            println!("Training...");
            NOERROR
        }
    }
    
    impl ICat for BritishShortHairCat {
        fn IgnoreHumans(&self) -> HRESULT {
            println!("Ignoring Humans...");
            NOERROR
        }
    }
    
    impl IAnimal for BritishShortHairCat {
        fn Eat(&self) -> HRESULT {
            println!("Eating...");
            NOERROR
        }
    }
}

有关用法和安全的更多信息,请参阅文档

安全性

尽管 COM 指定了方法调用 ABI 的细节,但它很少在保证这些方法调用的安全性方面发挥作用。因此,确保 COM API 的安全性以及编写这些 API 的安全包装器的工作留给了程序员。

您可以在安全性指南中了解更多关于此库提供哪些保证的信息。

现有 crates

有许多现有的 Rust crates 可以帮助与 COM 交互。根据您的用例,您可能会发现这些 crates 更适合您的需求。例如,我们有

  • Intercom,它专注于在 Rust 中编写跨平台 COM 组件的支持。
  • winapi-rs,它提供了一个简单的宏,允许您轻松消费 COM 接口。

构建

此库仅适用于 Windows,因此最简单的方法是在 Windows 机器上进行贡献。您可以像这样执行示例

cd examples\basic
cargo run --release

如果您在 Mac 或 Linux 机器上,您仍然应该能够通过在项目的根目录中运行以下命令来修改更改并确保它们可以编译

cargo check --target=x86_64-pc-windows-msvc

贡献

有关贡献的更多信息,请参阅贡献文档

行为准则

本项目已采用微软开源行为准则。您可以在行为准则文档中了解更多信息。

常见问题解答

是否有 IDL 支持?

作为基础,我们试图创建一个不依赖于 IDL 文件的库。然而,这是未来改进的计划之一。我们将有一个命令行工具,它将解析 IDL 到所需的宏。

是否有进程外 COM 支持?

目前,我们仅支持生成进程内 COM 组件。此外,COM 组件的生成只能是 DLL 格式。我们计划启用进程外 COM 生成以及生成 .EXE 格式。

依赖关系

~1.5MB
~35K SLoC