调用您的第一个 COM API
COM API 的独特之处在于它们通过接口暴露功能。接口只是一组虚拟函数指针,它们被组织在一个被称为 vtable(或虚拟函数表)的结构中。Rust 不像 C++ 那样直接支持这种结构,但 windows crate 提供了必要的代码生成,使其变得可能且无缝。COM API 通常会通过传统的 C 风格函数调用开始其生命周期,以便获取 COM 接口。之后,您可以通过该接口调用其他方法。
有些基于 COM 的 API 可能非常复杂,所以让我们从一个非常简单的例子开始。CreateUri
函数在 MSDN 上有官方文档,它返回表示解析给定 URI 结果的 IUri
接口。Rust windows crate 的文档 指出它位于 Win32::System::Com
模块中,因此我们可以相应地配置我们的 windows
crate 依赖项
[dependencies.windows]
version = "0.52"
features = [
"Win32_System_Com",
]
我们可以使用 use
声明,使这个 API 更易于访问。windows
crate 的 core
模块还提供了一些辅助函数,使 COM 接口的使用更加容易,所以我们也将它包含进来
#![allow(unused)] fn main() { use windows::{core::*, Win32::System::Com::*}; }
对于这个例子,我将只使用一个简单的 main
函数和一个大的 unsafe
块,因为这里几乎所有东西都是 unsafe
。为什么会这样?因为 windows
crate 允许你调用外部函数,而这些函数通常被认为是 unsafe
的。
fn main() -> Result<()> { unsafe { Ok(()) } }
这里唯一“有趣”的地方是使用了 windows::core
模块中的 Result
类型,它提供了 Windows 错误处理,以简化后续的 API 调用。有了这些,我们就可以如下调用 CreateUri
函数
#![allow(unused)] fn main() { let uri = CreateUri(w!("http://kennykerr.ca"), Uri_CREATE_CANONICALIZE, 0)?; }
这里有很多事情发生。第一个参数实际上是一个 PCWSTR
,它表示许多 Windows API 使用的以 null 结尾的宽字符串。windows
crate 提供了方便的 w!
宏,用于创建有效的以 null 结尾的宽字符串作为编译时常量。第二个参数只是官方文档指定的默认标志。第三个参数是保留的,因此应该为零。
生成的 IUri
对象有各种方法,我们现在可以使用它们来检查 URI。官方文档 描述了各种接口方法,Rust 文档 简要介绍了它们的各种签名,以便您可以快速了解如何在 Rust 中调用它们。对于这个例子,我们只调用其中的两个来打印 URI 的域和 HTTP 端口号
#![allow(unused)] fn main() { let domain = uri.GetDomain()?; let port = uri.GetPort()?; println!("{domain} ({port})"); }
在底层,这些方法将通过 COM 接口调用虚拟函数,并进入 API 提供的实现。它们还提供了一系列错误和签名转换,使其在 Rust 中使用起来非常自然。就是这样,运行示例应该会打印出类似这样的内容
kennykerr.ca (80)
这是完整的示例供参考。