WinRT:这可能是Windows上最出色的原生ABI和远程调用方案,难道不是吗?

摘要:前言 Windows 自从很久以来就有一个叫做 COM 的 Native ABI。这是一套面向对象的 ABI,在此之上 Windows 基于 COM ABI 暴露了各种各样的 API,例如 Management API、Shell API
前言 Windows 自从很久以来就有一个叫做 COM 的 Native ABI。这是一套面向对象的 ABI,在此之上 Windows 基于 COM ABI 暴露了各种各样的 API,例如 Management API、Shell API 和 DirectX API 就是典型。COM 自然不仅局限于进程内调用,跨进程的 RPC 调用也是不在话下。但无论如何,COM 用起来都很不顺手。 不过自从 Windows 8 以来,Windows 引入了全新的 WinRT,一下子让 Windows 的 Native ABI 变得方便快捷。 WinRT 的前身:COM 不少人可能对 COM 并没有什么概念,那首先我们来简单说一下 COM 是什么。 例如当你需要提供一些算术的 API 时,你可以定义下面这样一个 interface: [[uuid(dc58f02e-ceaa-46dc-8fb8-2a1348412421)]] interface ICalc { HResult Add(int x, int y, int* result); } 这个 interface 提供了加法的 API,加法 API 传入两个参数,通过指针输出一个参数作为返回值,而 API 自身返回是否执行成功。为了让这个 interface 能够被唯一识别,我们用 GUID(uuid) 给他提供一个 ID。 所有的 COM interface 都自动派生自 IUnknown,其中包含两个用于管理生命周期的引用计数函数 AddRef 和 Release,以及一个用于查询接口的函数 QueryInterface。 当我们拿到一个 object 的时候,如果我们想要调用 ICalc 上的方法,很自然我们会想到要把这个 object 先转换到 ICalc 再调用: object x = ...; int result; ((ICalc)x).Add(1, 2, &result); 但这样并不安全:你怎么知道这个 object 实现了 ICalc? 于是这里 QueryInterface 就派上用场了,调用它用 GUID 查询接口,成功后会返回给你查询的接口在这个 object 上对应方法表的入口点(等价于强制转换为 ICalc 之后的 object),然后你就能在这个 object 上调用它实现的 ICalc 里的方法了: object x = ...; ICalc calcEntry; if (x.QueryInterface(guid, &calcEntry) == S_OK) { int result; calcEntry.Add(1, 2, &result); } 这个时候假设我们 A 包含这个接口的实现,而 B 需要在不知道 A 的实现的情况下调用加法,只需要 A 实现这个 ICalc 的接口并且注册好,那么 B 只需要调用 QueryInterface 就能把 A 传过来的 object 变成 ICalc 然后调用了。 更进一步,我们的 A 有个类型实现了 IClassFactory,里面有个函数 CreateInstance 用来根据 GUID 来创建 object,这样我们在 B 里可以首先从 A 拿到 IClassFactory 的 object,然后直接用 ICalc 的 GUID 来调用它,就能创建一个对应 object 返回给我们来用了。 Windows 贴心的提供了一个系统 API CoGetClassObject,就是用来完成从获取 IClassFactory 到创建对象整个流程的,我们在 B 里简单调用 CoGetClassObject 这个函数,就能做到凭空产生我们想要的 object。 而 A 只需要把自己的 IClassFactory 注册到进程内(如果 A 和 B 在同一个进程里的话)或者系统里(如果 A 是一个独立进程的话)就可以了,这样系统就能知道从哪里去获取这个 IClassFactory。只不过进程内的情况是通过调用 A 暴露的 DllGetClassObject 函数,而不是 CoGetClassObject。 如此一来,无论 A 在哪里(进程内或者进程外),只要注册了,B 就能直接用 GUID 创建一个 ICalc 拿来用,进程内调用和进程间调用的差异被 COM 彻底抹除了。 为了沟通 A 和 B,我们用一个叫做 idl 的语言描述接口,编译后会生成一个 tlb 文件来描述类型信息,这个类型信息就能让系统知道你都定义了哪些东西。
阅读全文