C#/WinRT 是 NuGet 打包的工具包,它为 C# 语言提供Windows 运行时(WinRT)投影支持。 投影程序集是一个互作程序集,它使 WinRT API 能够以自然且熟悉的方式对目标语言进行编程。 C#/WinRT 投影隐藏了 C# 和 WinRT 接口之间的互操作的详细信息,并提供多种 WinRT 类型与 .NET 对应项的映射,例如字符串、URI、常见值类型和泛型集合。
C#/WinRT 当前通过 .NET 中使用 Target Framework 名字对象(TPM)来支持使用 WinRT API。 使用特定Windows SDK 版本设置 TFM 会添加对 C#/WinRT 生成的Windows SDK 投影和运行时程序集的引用。
使用 C#/WinRT NuGet 包可为.NET使用者创建和 reference自己的 WinRT 互操作程序集。 最新的 C#/WinRT 版本还支持在 C# 中 创作 WinRT 类型。
有关详细信息,请参阅 C#/WinRT GitHub 存储库。
C#/WinRT 的动机
.NET(以前称为.NET核心)是一种开源的跨平台运行时,可用于生成设备、云和 IoT 应用程序。
以前版本的 .NET Framework 和 .NET Core 对 WinRT 具有内置知识,这是一种特定于Windows的技术。 为了支持 .NET 6+ 的可移植性和效率目标,我们从 .NET 编译器和运行时中解除了 WinRT 投影支持,并将其移动到 C#/WinRT 工具包(请参阅 WinRT 的内置支持已从 .NET 中删除)。 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 的内置支持的其他方案。
新动态
可以在 release notes GitHub 页上找到最新的 C#/WinRT 版本。
使用情况
C#/WinRT NuGet 包可用于生成从 WinRT 组件到 C# 投影(也称为互操作程序集),以及在编写 C#/WinRT 组件。 有关 C#/WinRT 的使用方案的更多详细信息,请参阅存储库上的 usage 指南。
生成和分发互操作程序集
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 组件,则应用程序project可能遵循 生成互作程序集以生成其自己的专用投影源的过程。 不建议使用此方法,因为它可以在进程中生成同一类型的冲突投影。 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 运行时 组件增强非打包桌面应用),适用于 Windows 10 版本 1903 及更高版本。 本机 C++ 组件应通过项目属性或 文件将 Windows Desktop Compatible 属性设置为 .vcxproj,以便将 Microsoft.VCLibs.Desktop 二进制文件引用并转发给使用它们的应用程序。 否则,如果组件仅针对 UWP 应用,则使用该组件的应用需依赖 VCRT 转发器包。
如果Windows无法激活类型,C#/WinRT 还提供激活回退路径,如上文所述。 在这种情况下,C#/WinRT 会尝试根据完全限定的类型名称查找本机实现 DLL,逐渐删除元素。 例如,回退逻辑会尝试按顺序从以下模块激活 Contoso.Controls.Widget 类型:
- Contoso.Controls.Widget.dll
- Contoso.Controls.dll
- 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>net8.0-windows10.0.19041.0</TargetFramework>-
将对象强制转换为带有
ComImport属性的接口时,需要使用.As<>运算符,而非显式使用强制转换表达式。 例如:someObject.As<SomeComImportInterface>有关详细信息,请参阅 COM 互作指南。
System.Runtime.InteropServices.COMException:未注册的类(0x80040154(REGDB_E_CLASSNOTREG))
- 如果在从 C++/WinRT 组件使用 C#/WinRT 投影时看到此异常,请确保组件已将 Windows Desktop Compatible 属性设置为 True通过项目属性或通过
.vcxproj文件。
- 如果在从 C++/WinRT 组件使用 C#/WinRT 投影时看到此异常,请确保组件已将 Windows Desktop Compatible 属性设置为 True通过项目属性或通过
.NET SDK 版本控制错误
在使用较早版本的 .NET SDK 而不是其任何依赖项所使用版本生成的项目中,您可能会遇到以下错误或警告。
| 错误或警告消息 | 原因 |
|---|---|
| 警告 MSB3277:发现不同版本的 WinRT.Runtime 或 Microsoft.Windows.SDK.NET 之间存在无法解析的冲突。 | 引用在 API 界面上公开 Windows SDK 类型的库时,会出现此生成警告。 |
| 错误 CS1705:程序集“AssemblyName1”使用版本高于引用的程序集“AssemblyName2”的“TypeName” | 引用和使用库中公开Windows SDK 类型时,会发生此生成编译器错误。 |
| System.IO.FileLoadException | 在未公开Windows SDK 类型的库中调用某些 API 时,可能会出现此运行时错误。 |
若要修复这些错误,请将 .NET SDK 更新到最新版本。 这样做可确保应用程序使用的运行时和Windows SDK 程序集版本与所有依赖项兼容。 这些错误可能与.NET SDK 的早期维护/功能更新一起发生,因为运行时修复可能需要更新程序集版本。
已知问题
在C#/WinRT GitHub 存储库中记录了已知问题和重大变更。
如果遇到 C#/WinRT NuGet 包、cswinrt.exe 编译器或生成的投影源的任何功能问题,请通过 C#/WinRT 问题页提交问题。