我想编写一个 WPF 应用程序,但尽可能在现代框架上构建它,包括 .NET 6 甚至更高版本。
我有一些想要调用的 C++ 代码,并且我喜欢将 WinRT 作为组件模型,而不是低级别的 P/Invoke。
我已经成功使用 CsWinRT 将我的 C++ 代码集成到 WinUI3 应用程序中。现在我尝试对我的 WPF 应用程序执行相同的操作。我的尝试可以在https://github.com/mmarczell-graphisoft/winrtbug
看到只要我的 WPF C# 代码中没有 using 指令,也没有任何使用这些定义的代码,C# 投影文件就会在 obj\Debug 下生成 et6.0-windows\生成的文件\CsWinRT。然而,一旦我输入 using 指令并重建,这个文件就不再存在了。
我做错了什么?
我找到了一些关于类似用例的文档,但它们已有一些年头了,似乎并不直接适用。
最初不支持在非打包应用程序中使用 WinRT 组件。 https://github.com/microsoft/cppwinrt/issues/256
然后在2019年宣布了“免注册WinRT”: https://blogs.windows.com/windowsdeveloper/2019/04/30/enhancing-non-packaged-desktop-apps-using-windows-runtime-components/
带有示例代码: https://github.com/microsoft/RegFree_WinRT
但是,在 .NET 5 中,直接引用 .winmd 的功能已从 .NET 中删除并提取到 CsWinRT 包中: https://github.com/microsoft/CsWinRT
这就是我未能正确配置的原因。该文档指出,直接项目引用是不可能的,而应使用两阶段构建过程,第一阶段将库打包为 NuGet 包,顶级应用程序引用它。 https://learn.microsoft.com/en-us/windows/apps/develop/platform/csharp-winrt/net-projection-from-cppwinrt-component
然而,GitHub 讨论中的 MS 员工一再暗示这实际上是不必要的,因为 CsWinRT 通过直接引用项目来支持更简单的工作流程,例如 https://github.com/microsoft/CsWinRT/discussions/1072#discussioncomment-8497693 和 https://github.com/microsoft/CsWinRT/issues/1289#issuecomment-1481878399
我也将此问题作为 GitHub 问题提交: https://github.com/microsoft/CsWinRT/issues/1543
这里指出的许多文章都是旧的(也称为几年,但对于 .NET Core 来说几年已经很老了),并且使用最近的框架,有些事情比以前更容易,但很难找到解决方案。
因此,从本(官方)教程开始从 C++/WinRT 组件生成 C# 投影,作为 .NET 应用程序的 NuGet 进行分发,可在此处作为示例代码C#/WinRT 投影示例。首先要做的是更新所有软件包,尤其是 CsWinRT,它已经完全过时了(截至今天的当前版本是
2.0.7
)。
然后,由于这个较新的 CsWinRT,您甚至不需要像示例中所解释的那样使用中间 Nuget 项目,因为这个新的 CsWinRT 会从组件的 .winmd 文件中动态为我们生成一些 .cs 文件(元数据)。
只需构建 SimpleMathComponent C++/WinRT 项目,现在您可以使用 .NET 8 和 x64(调试或发布)在带有 .csproj 的控制台应用程序中引用它
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<Nullable>enable</Nullable>
<PlatformTarget>x64</PlatformTarget>
<Platforms>x64</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.7" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SimpleMathComponent\SimpleMathComponent.vcxproj" />
</ItemGroup>
<PropertyGroup>
<CsWinRTIncludes>
SimpleMathComponent;
</CsWinRTIncludes>
</PropertyGroup>
我们可以在
obj
目录下看到.cs投影自动生成的文件:
现在,对于 WPF 项目,相同的项目布局不起作用。由于某种原因,CsWinRT 没有选择
SimpleMathComponent
组件来生成代码(我能看到的唯一真正区别是 OutputType
、Exe
与 WinExe
)并且未生成 SimpleMathComponent.cs,这会导致编译错误。对我来说看起来像是一个错误。
一个可能的解决方法是直接向 CsWinRT 提供它需要的输入,如下所示;
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<Nullable>enable</Nullable>
<PlatformTarget>x64</PlatformTarget>
<Platforms>x64</Platforms>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWinRT" Version="2.0.7" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\SimpleMathComponent\SimpleMathComponent.vcxproj" />
</ItemGroup>
<PropertyGroup>
<CsWinRTParams>
-target net6.0
-input 10.0.19041.0
-input "$(BuildOutDir)SimpleMathComponent\bin\SimpleMathComponent\SimpleMathComponent.winmd"
-output "$(IntermediateOutputPath)\net8.0-windows10.0.19041.0\Generated Files\CsWinRT"
-exclude Windows
-exclude Microsoft
-include SimpleMathComponent
</CsWinRTParams>
</PropertyGroup>
</Project>
显然它不如控制台应用程序版本实用(并且在改变.NET版本、SDK版本等时需要进行调整)。