6

我正在使用一个本机 C++ 应用程序,它有一个插件系统,它将LoadLibrary()/GetProcAddress()在 .dll 上调用函数。我想实现其中一个插件,并且在插件内部我想使用持久性框架将复杂的对象图保存/加载到磁盘。

似乎 Windows 上最受支持的 ORM 是 Entity Framework,这个页面说 Entity Framework Core 是最现代的风格。这个页面似乎说,为了使用 Entity Framework Core,你的数据模型必须用 C# 编写。

所以,听起来我必须从 C++ 调用 C#。幸运的是,Entity Framework Core 似乎支持通用 Windows 运行时,它应该使语言之间的调用变得容易。

该演示文稿似乎在说,从 C++ 与通用 Windows 运行时交互涉及创建 Windows 运行时组件,并且编译步骤可以从 Windows 运行时组件的.winmd文件中生成粘合代码。

因此,我可以制作一个包含两个项目的 Visual Studio 解决方案:一个外部“C++ Windows 桌面动态链接库”项目和一个内部“C# 通用 Windows 运行时组件”。

外部 C++ Windows 桌面动态链接库 内部 C# 通用 Windows 运行时组件

然后文档说“引用 Windows 运行时组件的 Windows 运行时元数据 (.winmd) 文件并构建。” 但是,当我在外部项目中添加引用时,尝试选择内部项目时出现错误,并且没有选项可以浏览以选择任意.winmd.

尝试添加对内部项目的引用时出错

即使我进入解决方案管理器并删除x86两个项目中的所有平台,也会出现此错误。

这是令人惊讶的,因为这篇 Windows 博客文章明确指出,本机代码应该能够通过添加对 的引用来调用 UWP 代码.winmd(尽管该文章使用的是较旧的 C++/CX 语法)。

如果我重新开始并使用“C++/WinRT Windows 运行时组件”而不是“C++ Windows 桌面动态链接库”项目,我仍然会遇到问题。

外部 C++/WinRT Windows 运行时组件

如果我这样做,我可以添加引用就好了。

成功参考

但是,当我尝试构建时,构建失败。

1>------ Build started: Project: InnerCSharp, Configuration: Debug x86 ------
1>  InnerCSharp -> C:\Users\lithe\source\repos\EntityFrameworkInsideC++\InnerCSharp\bin\x86\Debug\InnerCSharp.winmd
2>------ Build started: Project: OuterC++WinRT, Configuration: Debug Win32 ------
2>MIDLRT Processing C:\Users\lithe\source\repos\EntityFrameworkInsideC++\OuterC++WinRT\Class.idl
2>Class.idl
2>MIDLRT Processing C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\winrtbase.idl
2>winrtbase.idl
2>MIDLRT Processing C:\Program Files (x86)\Windows Kits\10\Include\10.0.17134.0\winrt\midlbase.idl
2>midlbase.idl
2>Processing WinMD c:\users\lithe\source\repos\entityframeworkinsidec++\innercsharp\bin\x86\debug\innercsharp.winmd
2>Processing WinMD c:\program files (x86)\windows kits\10\references\10.0.17134.0\windows.ai.machinelearning.preview.machinelearningpreviewcontract\1.0.0.0\windows.ai.machinelearning.preview.machinelearningpreviewcontract.winmd
... snip ...
2>Processing WinMD c:\program files (x86)\windows kits\10\references\10.0.17134.0\windows.ui.viewmanagement.viewmanagementviewscalingcontract\1.0.0.0\windows.ui.viewmanagement.viewmanagementviewscalingcontract.winmd
2>MDMERGE : error MDM2006: C:\Users\lithe\source\repos\EntityFrameworkInsideC++\InnerCSharp\bin\x86\Debug\InnerCSharp.winmd does not appear to be a valid Windows Runtime metadata file
2>MDMERGE : error MDM2005: Unable to open metadata file C:\Users\lithe\source\repos\EntityFrameworkInsideC++\InnerCSharp\bin\x86\Debug\InnerCSharp.winmd.
2>Microsoft(R) Metadata Merge Utility Version 10.0.45.
2>
2>
2>Creating output directory C:\Users\lithe\source\repos\EntityFrameworkInsideC++\Debug\OuterC++WinRT\Merged.
2>Load input metadata file C:\Users\lithe\source\repos\EntityFrameworkInsideC++\InnerCSharp\bin\x86\Debug\InnerCSharp.winmd.
2>Load input metadata file C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract\1.0.0.0\Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract.winmd.
... snip ...
2>Load input metadata file C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.UI.ViewManagement.ViewManagementViewScalingContract\1.0.0.0\Windows.UI.ViewManagement.ViewManagementViewScalingContract.winmd.
2>Processing input metadata file C:\Users\lithe\source\repos\EntityFrameworkInsideC++\Debug\OuterC++WinRT\Unmerged\Class.winmd.
2>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\VC\VCTargets\Microsoft.Cpp.CppWinRTEnabled.targets(244,9): error MSB3073: The command "mdmerge.exe -v -metadata_dir "C:\Users\lithe\source\repos\EntityFrameworkInsideC++\InnerCSharp\bin\x86\Debug\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract\1.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.ApplicationModel.Calls.CallsVoipContract\3.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.ApplicationModel.SocialInfo.SocialInfoContract\2.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.ApplicationModel.StartupTaskContract\3.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Devices.Custom.CustomDeviceContract\1.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Devices.DevicesLowLevelContract\3.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Devices.Printers.PrintersContract\1.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract\3.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Devices.SmartCards.SmartCardEmulatorContract\5.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Foundation.FoundationContract\3.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Foundation.UniversalApiContract\6.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Gaming.XboxLive.StorageApiContract\1.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Graphics.Printing3D.Printing3DContract\4.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Networking.Connectivity.WwanContract\2.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Services.Store.StoreContract\3.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.Services.TargetedContent.TargetedContentContract\1.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.System.Profile.ProfileHardwareTokenContract\1.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.System.Profile.ProfileSharedModeContract\2.0.0.0\." -metadata_dir "C:\Program Files (x86)\Windows Kits\10\References\10.0.17134.0\Windows.UI.ViewManagement.ViewManagementViewScalingContract\1.0.0.0\." -o "C:\Users\lithe\source\repos\EntityFrameworkInsideC++\Debug\OuterC++WinRT\Merged" -i "C:\Users\lithe\source\repos\EntityFrameworkInsideC++\Debug\OuterC++WinRT\Unmerged" -partial" exited with code 2.
2>Done building project "OuterC++WinRT.vcxproj" -- FAILED.
========== Build: 1 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

但是,我可以按照前面演示文稿中的步骤成功引用 Win2D,无论是在 C++/WinRT Windows 运行时项目(无需任何额外配置)和 ComponentC++ Windows 桌面动态链接库项目(并运行 cppwinrt 命令 -此答案中描述的线工具)。但是,这对我没有帮助——我不想引用 NuGet 包;我正在尝试在同一解决方案中引用不同的项目。

所以,毕竟,问题是:如何使用通用 Windows 运行时从 C++ 代码调用 C# 代码?

4

1 回答 1

2

您不能从 Windows 桌面应用程序调用 Windows 运行时组件。此功能为通用 Windows 平台 (UWP) 应用程序保留。Windows 运行时类型通过使用RoGetActivationFactory函数来访问/实例化/调用,并且该函数只接受类名,而不是类名和类所在的 DLL。这意味着系统必须能够定位类是。对于系统 API,这很容易——它们在 Windows 注册表中进行了硬编码。对于 Windows 运行时组件中的自定义类,它依赖于 AppX 清单来告知哪些类在哪些 DLL 中。不幸的是,对于桌面应用程序,您没有 AppX 清单,因此您无法调用自定义类。

还有其他(更好的)方法可以从您的桌面应用程序调用托管代码。

一种选择是在构建 DLL 时使用/clr标志。这将创建一个可以直接调用 C# 代码的 DLL。

另一种选择是在您的进程中手动托管 CLR 并以这种方式调用代码

我的回答假设您的应用程序以 Windows 桌面而不是 UWP 为目标,因为您的第一个 DLL 以桌面为目标。如果不是这种情况,Windows 运行时组件可能是一个解决方案,但为这种设置设置构建管道并不是很简单。您看到的错误来自 C++/winrt 编译器,它尝试将 .winmd 文件转换为头文件。我不知道它为什么会失败,但是您应该能够通过使用常规的 Windows 运行时组件模板(而不是 C++/winrt 模板)来禁用它。

于 2018-09-21T22:19:30.307 回答