I'm working with a native C++ app which has a plugin system where it will LoadLibrary()
/GetProcAddress()
on a .dll to call functions. I'd like to implement one of these plugins, and inside the plugin I'd like to use a persistence framework to save/load a complicated object graph to disk.
It seems like the most-supported ORM on Windows is Entity Framework, and this page says that Entity Framework Core is the most modern flavor. This page seems to say that, in order to use Entity Framework Core, your data model has to be written in C#.
So, it sounds like I'll have to call C# from C++. Luckily, it seems like Entity Framework Core supports the Universal Windows Runtime, which is supposed to make calling between languages easy.
This presentation seems to say that interacting with the Universal Windows Runtime from C++ involves creating a Windows Runtime Component, and a compilation step can generate glue code from the Windows Runtime Component's .winmd
file.
So, I can make a Visual Studio solution that includes two projects: An outer "C++ Windows Desktop Dynamic-Link Library" project, and an inner "C# Universal Windows Runtime Component."
The docs then say to "reference the Windows Runtime component's Windows Runtime metadata (.winmd) file, and build." However, when I add a reference in the outer project, I get an error when I try to select the inner project, and there is no option to browse to select an arbitrary .winmd
.
This error occurs even if I go into the Solution Manager and delete all the platforms except x86
in both projects.
This is surprising because this Windows Blog post explicitly says that native code is supposed to be able to call UWP code by adding a reference to the .winmd
(though the post uses the older C++/CX syntax).
If I start over and use a "C++/WinRT Windows Runtime Component" instead of the "C++ Windows Desktop Dynamic-Link Library" project, I still have problems.
If I do this, I can add the reference just fine.
However, when I try to build, I get a build failure.
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 ==========
I can, however, follow the steps in the earlier presentation to successfully reference Win2D, both in the C++/WinRT Windows Runtime project (without any additional configuration) and in the ComponentC++ Windows Desktop Dynamic-Link Library project (and running the cppwinrt command-line tool as described in this answer). However, that doesn't help me - I'm not trying to reference a NuGet package; I'm trying to reference a different project in the same solution.
So, after all that, the question is: How can I use the Universal Windows Runtime to call C# code from C++ code?