C#/WinRT

C#/WinRT 是一个进行 NuGet 打包的工具包,为 C# 语言提供 Windows 运行时 (WinRT) 投影支持。 投影程序集是一个互操作程序集,它以自然而熟悉的方式为目标语言启用编程 WinRT API。 C#/WinRT 投影隐藏了 C# 与 WinRT 接口之间的互操作的详细信息,并提供了从许多 WinRT 类型到相应的 .NET 等效项(例如字符串、URI、公用值类型和泛型集合)的映射。

C#/WinRT 目前支持通过使用 .NET 中的目标框架名字对象 (TFM) 来使用 WinRT API。 如果使用特定 Windows SDK 版本来指定 TFM,会添加对 C#/WinRT 生成的 Windows SDK 投影和运行时程序集的引用。

借助 C#/WinRT NuGet 包,可为 .NET 使用者创建引用你自己的 WinRT 互操作程序集。 C#/WinRT 最新版还包含在 C# 中创作 WinRT 类型的功能(现为预览版)。

有关更多信息,请参阅 C#/WinRT GitHub 存储库

采用 C#/WinRT 的动机

.NET(以前称为 .NET Core)是一个开源的跨平台运行时,可用于构建设备、云和 IoT 应用程序。

以前版本的 .NET Framework 和 .NET Core 都内置了 WinRT(一种特定于 Windows 的技术)知识。 为了支持 .NET 6+ 的可移植性和高效性目标,我们从 .NET 编译器和运行时中撤销了 WinRT 投影支持,将其移到了 C#/WinRT 工具包中(请参阅已从 .NET 中删除对 WinRT 的内置支持)。 C#/WinRT 的目标是通过旧版 C# 编译器和 .NET 运行时提供的内置 WinRT 支持来提供奇偶校验。 有关详细信息,请参阅 Windows 运行时类型的 .NET 映射

C#/WinRT 还支持 Windows 应用 SDK 中的组件,包括 WinUI 3。 Windows 应用 SDK 会从操作系统中移出本机 Microsoft UI 控件和其他本机组件。 这使得应用开发人员能够在 Windows 10 版本 1809 及更高版本上使用最新控件和组件。

最后,C#/WinRT 是一个通用工具包,用于支持在 C# 编译器或 .NET 运行时中无法使用内置 WinRT 支持的其他方案。

新变化

可在 Github 存储库中的发行说明页上找到最新的 C#/WinRT 版本。

使用情况

C#/WinRT NuGet 包可用于从 WinRT 组件生成 C# 投影(也称为互操作程序集)创作 C#/WinRT 组件。 有关 C#/WinRT 使用方案的更多详细信息,请参阅我们的存储库上的使用指南

生成和分发互操作程序集

WinRT API 是在 Windows 元数据 (WinMD) 文件中定义的。 C#/WinRT NuGet 包 (Microsoft.Windows.CsWinRT) 中包括 C#/WinRT 编译器 cswinrt.exe,可用它来处理 WinMD 文件并生成 .NET C# 代码。 C#/WinRT 将这些源文件编译为互操作程序集,这与 C++/WinRT 为 C++ 语言投影生成头文件的方式类似。 然后,可与实现程序集一起分发 C#/WinRT 互操作程序集供 .NET 应用程序引用(通常以 NuGet 包的形式分发)。

若要详细了解如何生成和分发互操作程序集,请参阅从 C++/WinRT 组件生成 C# 投影,并将其以 NuGet 的形式分发供 .NET 应用使用

引用互操作程序集

通常,C#/WinRT 互操作程序集由应用程序项目引用。 但是,中间互操作程序集也可能引用它们。 例如,WinUI 互操作程序集将引用 Windows SDK 互操作程序集。

如果分发没有官方互操作程序集的第三方 WinRT 组件,则应用程序项目可能会按照生成互操作程序集的过程来生成其自己的专用投影源。 不建议使用此方法,因为它可能会在一个进程内生成同一类型的冲突投影。 设计了遵循语义版本控制方案的 NuGet 打包来防止出现此情况。 最好使用正式的第三方互操作程序集。

对 WinRT 类型的嵌入式支持(预览版)

从 C#/WinRT 版本 1.4.1 开始,支持将 .NET 和 .NET Standard 2.0 的 Windows SDK 投影和运行时源嵌入到你的库或应用的输出中。 如果 Windows SDK 类型的使用是自包含的,则这非常有用。 嵌入式支持移除了对 WinRT.Runtime.dll 和 Microsoft.Windows.SDK.NET.dll 的依赖项,从而减少库或应用输出的大小。 它还使库开发人员可提供下层支持,并移除对多目标的需求。

有关更多详细信息,请参阅我们的存储库上的“C#/WinRT 嵌入式”文档

WinRT 类型激活

C#/WinRT 支持激活由操作系统承载的 WinRT 类型以及第三方组件(例如 Win2D)。 桌面应用程序中对第三方组件的激活支持是通过注册免费 WinRT 激活(在 Windows 10 版本 1903 及更高版本中提供)(请参阅使用 Windows 运行时组件增强未打包的桌面应用)启用的。 本机 C++ 组件应通过项目属性或 .vcxproj 文件将“Windows 桌面兼容”属性设置为 True,以便引用和转发 Microsoft.VCLibs.Desktop 二进制文件来使用应用。 否则,如果组件仅面向 UWP 应用,需要 VCRT 转发器包才能使用应用。

如果 Windows 未能如上所述激活该类型,则可使用 C#/WinRT 提供的激活回退路径。 在这种情况下,C#/WinRT 会尝试根据完全限定的类型名称查找一个原生实现 DLL,并逐步删除各个元素。 例如,回退逻辑会尝试按顺序从以下模块激活 Contoso.Controls.Widget 类型:

  1. Contoso.Controls.Widget.dll
  2. Contoso.Controls.dll
  3. Contoso.dll

C#/WinRT 使用 LoadLibrary 备用搜索顺序查找一个实现 DLL。 依赖于此回退行为的应用应将该实现 DLL 与应用模块一起打包。

常见错误和疑难解答

  • 错误:“未提供或未检测到 Windows 元数据。”

    可以使用 <CsWinRTWindowsMetadata> 项目属性指定 Windows 元数据,例如:

    <CsWinRTWindowsMetadata>10.0.19041.0</CsWinRTWindowsMetadata>
    

    在 C#/WinRT 1.2.1 及更高版本中,此属性默认为 TargetPlatformVersion,它派生自 TargetFramework 属性中指定的 Windows SDK 版本。

  • 错误 CS0246:找不到类型或命名空间名称“Windows”(是否缺少 using 指令或程序集引用?)

    若要解决此错误,请编辑 <TargetFramework> 属性,使其面向特定的 Windows 版本,例如:

    <TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
    

    有关指定 <TargetFramework> 属性的更多详细信息,请参阅调用 Windows 运行时 API 上的文档。

  • System.InvalidCastException(转换到具有 ComImport 特性的接口时)

    将对象转换为具有 ComImport 特性的接口时,需要使用 .As<> 运算符,而不是使用显式的转换表达式。 例如:

    someObject.As<SomeComImportInterface>
    

    有关详细信息,请参阅 COM 互操作指南

  • System.Runtime.InteropServices.COMException:未注册类 (0x80040154 (REGDB_E_CLASSNOTREG))

    • 如果从 C++/WinRT 组件使用 C#/WinRT 投影时看到此异常,请确保该组件已通过项目属性或 .vcxproj 文件将“Windows 桌面兼容”属性设置为 True。

.NET SDK 版本控制错误

在使用版本低于其任何依赖项的 .NET SDK 构建的项目中,你可能会遇到以下错误或警告。

错误或警告消息 原因
警告 MSB3277:发现不同版本的 WinRT.Runtime 或 Microsoft.Windows.SDK.NET 之间存在无法解决的冲突。 引用在其 API 表面公开 Windows SDK 类型的库时,会出现此生成警告。
错误 CS1705:程序集“AssemblyName1”使用“TypeName”,后者的版本比引用的程序集“AssemblyName2”的版本高 引用和使用已在库中公开的 Windows SDK 类型时,会出现此生成编译器错误。
System.IO.FileLoadException 在不公开 Windows SDK 类型的库中调用某些 API 时,可能会出现此运行时错误。

要解决这些错误,请将 .NET SDK 更新到最新版本。 这样做将确保你的应用程序使用的运行时和 Windows SDK 程序集与所有依赖项兼容。 使用 .NET SDK 的早期服务/功能更新时可能会出现这些错误,原因是运行时修补程序可能要求程序集版本更新。

已知问题

已知问题和中断性变更记录在 C#/WinRT GitHub 存储库中。

如果在 C#/WinRT NuGet 程序包、cswinrt.exe 编译器或生成的投影源中遇到任何功能问题,请通过 C#/WinRT 问题页将问题提交给我们。

其他资源