英文原文:
C# and Visual Basic on the WinRT API
(作者:Jonathan Allen 译者:侯伯薇)
尽管我们可以使用 .NET 语言来调用 Win32 API,但那样做会很困难。所以在过去的两年间微软一直在构建替代的方案,它就是实现了跨语言支持的 Windows 运行时,即 WinRT。我们可以在 C++ 和 .NET 中创建 WinRT 组件,并且可由二者以及 JavaScript 使用。
尽管 COM 在表面上是一种基于 OOP 的框架,但它与 .NET 之间有很大的区别。在 WinRT 出现之前,COM 是基于接口而不是基于类的。这意味着其中缺少很多 .NET 开发者认为应该有的内容,像构造函数以及静态方法等。C++组件扩展解决了这个问题。
WinRT 形式的 COM 使用的元数据格式和通用语言运行时(Common Language Runtime)相同。这些信息存储在表示结构的 WINMD 文件中,尽管没有实现,但在所有公有类中都会有。FXCop 被用于检验这些文件所暴露的 API 是否遵循 .NET Framework 的设计指南。
.NET 在最开始时就有“API 设计委员会(API Design Board)”。受此启发,Windows 运行时也会建立 API 设计委员会来对其进行管理。很多最初的成员都在 .NET 委员会中,并且很多指南都直接来自于 .NET 基本类库所遵循的原则。
Windows 运行时会返回 HRESULT,而不会抛出异常。对于众所周知的 HRESULT 值来说,会抛出相应的异常,而对于其他值就只能抛出 COMException。
WinRT 的 IAsyncOperation 接口现在使用新的 async/await 关键字,就像 .NET 的 Task 对象一样。
所有 Windows 运行时的集合接口都被映射到 .NET 框架的等价物上。在 .NET 4.5中添加了 IReadOnlyList 和 IReadOnlyDictionary,用来负责处理 WinRT 中的只读集合。
WinRT 和 .NET API 在两个地方无法匹配。WinRT 的 stream 无法直接与 .NET 的 IO.Stream 类兼容,但是可以调用名为 AsStream 的扩展方法来进行转换。WinRT 还拥有名为 IBuffer 的接口,这在 .NET 中也无法简单地实现。在此也有一个扩展方法来进行 IBuffer 和比特数组之间的转换。
我们可以使用 C# 和 VB 来创建新的 Windows 运行时程序库,过程非常简单。为了把类暴露为 Windows 运行时组件,我们只需要把项目类型设置为“WINMD 文件”,并确保遵循以下规则:
- API 签名只使用 Windows 运行时的类型
- 结构体只能拥有公有的数据字段
- 只允许对 XAML 控件使用继承,其它类型都必须使用 sealed 关键字。
- 只支持内建的泛型
编译这些库之后,我们就可以在 C++ 和 JavaScript 中调用它们,就像从 .NET 中调用一样简单。
警告
由于 WinRT 是基于 COM 构建的,所以你同样会有引用计数和 mark-and-sweep 垃圾回收器之间无法融合的问题。对于实现了析构函数释放非内存资源的对象来说,这是最常见的问题。我们可以考虑调用“Marshal.FinalReleaseComObject”来解决问题,但是那本身也存在问题。
COM 风格的 marshaling 需要在 .NET 和本地组件之间调用。尽管这通常是无关紧要的,但是如果 API 非常不正式,那么就会出现问题。
内建的 WinRT 库(而不是 XAML)是在 Metro 运行时环境之外提供的。然而,第三方的 WinRT 库并非如此。这是 WinRT 中激活框架(activation framework)的限制,而不是 .NET 的问题。