Как использовать среду выполнения Windows для реализации API C++ с использованием C#?
Я работаю с родным приложением C++, которое имеет систему плагинов, где оно будет LoadLibrary()
/GetProcAddress()
на.dll для вызова функций. Я хотел бы реализовать один из этих плагинов, и внутри плагина я хотел бы использовать постоянную среду для сохранения / загрузки графа сложных объектов на диск.
Похоже, что наиболее поддерживаемый ORM в Windows - это Entity Framework, и на этой странице сказано, что Entity Framework Core - самый современный вариант. Кажется, на этой странице написано, что для использования Entity Framework Core ваша модель данных должна быть написана на C#.
Похоже, мне придется вызывать C# из C++. К счастью, похоже, что Entity Framework Core поддерживает универсальную среду выполнения Windows, которая должна облегчать вызовы между языками.
Похоже, что в этой презентации говорится, что взаимодействие с универсальной средой выполнения Windows из C++ предполагает создание компонента среды выполнения Windows, а на этапе компиляции можно создать связующий код из компонента среды выполнения Windows. .winmd
файл.
Итак, я могу создать решение Visual Studio, которое включает в себя два проекта: внешний "C++ Windows Desktop Dynamic-Link Library" проект и внутренний "C# Universal Windows Runtime Component".
Затем в документах говорится "сослаться на файл метаданных среды выполнения Windows (.winmd) компонента среды выполнения Windows и выполнить сборку". Тем не менее, когда я добавляю ссылку во внешний проект, я получаю сообщение об ошибке при попытке выбрать внутренний проект, и нет возможности просмотреть произвольный выбор произвольного .winmd
,
Эта ошибка возникает, даже если я захожу в Solution Manager и удаляю все платформы, кроме x86
в обоих проектах.
Это удивительно, потому что в этом посте блога Windows явно сказано, что нативный код должен вызывать код UWP, добавив ссылку на .winmd
(хотя пост использует старый синтаксис C++/CX).
Если я начну заново и использую "C++/WinRT Windows Runtime Component" вместо "C++ Windows Desktop Dynamic-Link Library", у меня все еще будут проблемы.
Если я сделаю это, я могу добавить ссылку просто отлично.
Однако, когда я пытаюсь собрать, я получаю сбой сборки.
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 Runtime (без какой-либо дополнительной настройки), так и в проекте библиотеки динамических ссылок Windows Desktop для ComponentC++ (и запустив команду cppwinrt- инструмент линии, как описано в этом ответе). Однако это мне не помогает - я не пытаюсь ссылаться на пакет NuGet; Я пытаюсь сослаться на другой проект в том же решении.
Итак, после всего этого возникает вопрос: как я могу использовать универсальную среду выполнения Windows для вызова кода C# из кода C++?
1 ответ
Нельзя вызывать компоненты среды выполнения Windows из настольного приложения Windows. Эта функциональность зарезервирована для приложений универсальной платформы Windows (UWP). Доступ к типам среды выполнения Windows осуществляется / создается / вызывается с использованием функции RoGetActivationFactory, и эта функция принимает только имя класса, а не имя класса и библиотеку DLL, в которой находится класс. Это означает, что система должна быть в состоянии определить, где находится класс есть. Для системных API это легко - они жестко запрограммированы в реестре Windows. Для пользовательских классов в компонентах среды выполнения Windows он использует манифест AppX, указывающий, какие классы находятся в каких DLL. К сожалению, для настольных приложений у вас нет манифеста AppX, поэтому вы не можете вызывать пользовательские классы.
Существуют и другие (и лучшие) способы вызова управляемого кода из вашего настольного приложения.
Одним из вариантов является использование флага /clr при сборке вашей DLL. Это создаст DLL, которая может напрямую вызывать код C#.
Другим вариантом является размещение CLR в вашем процессе вручную и вызов кода таким образом.
Мой ответ предполагает, что ваше приложение предназначено для рабочего стола Windows, а не для UWP, так как ваш первый целевой компьютер для DLL. Если это не так, компонент среды выполнения Windows может быть решением, но настройка конвейера сборки для такого рода установки не очень тривиальна. Ошибки, которые вы видите, происходят из компилятора C++/winrt, и он пытается преобразовать файл.winmd в заголовочные файлы. Я не знаю, почему это терпит неудачу, но вы должны иметь возможность отключить, используя обычный шаблон Windows Runtime Component (вместо C++/winrt).