Как использовать среду выполнения Windows для реализации API C ++ с использованием C #? - PullRequest
0 голосов
/ 21 сентября 2018

Я работаю с собственным приложением C ++, в котором есть система плагинов, где он LoadLibrary() / GetProcAddress() на .dll вызывает функции.Я хотел бы реализовать один из этих плагинов, и внутри плагина я хотел бы использовать среду хранения для сохранения / загрузки графа сложных объектов на диск.

Кажется, что наиболее поддерживаемый ORM наWindows - это Entity Framework, и на этой странице говорится, что Entity Framework Core - самый современный вариант. Эта страница , кажется, говорит о том, что для использования Entity Framework Core ваша модель данных должна быть написана на C #.

Итак, похоже, мне придется вызывать C # изC ++.К счастью, похоже, что Entity Framework Core поддерживает универсальную среду выполнения Windows, которая должна облегчать вызовы между языками.

Эта презентация , кажется, говорит о взаимодействии суниверсальная среда выполнения Windows из C ++ включает создание компонента среды выполнения Windows, и на этапе компиляции можно сгенерировать связующий код из файла .winmd компонента среды выполнения Windows.

Итак, я могу создать решение Visual Studio, включающее два проекта.: Внешний проект «C ++ Windows Desktop Dynamic-Link Library» и внутренний «C # Universal Windows Runtime Component».

Outer C++ Windows Desktop Dynamic-Link Library Inner C# Universal Windows Runtime Component

docs затем говорят "сослаться на файл метаданных среды выполнения Windows (.winmd) компонента среды выполнения Windows и выполнить сборку".Однако, когда я добавляю ссылку во внешний проект, я получаю сообщение об ошибке, когда пытаюсь выбрать внутренний проект, и нет возможности просмотреть произвольный выбор .winmd.

Error when trying to add a reference to inner project

Эта ошибка возникает, даже если я захожу в Solution Manager и удаляю все платформы, кроме x86 в обоих проектах.

Это удивительно, потому что эта WindowsВ блоге прямо сказано, что нативный код должен вызывать код UWP, добавив ссылку на .winmd (хотя в посте используется более старый синтаксис C ++ / CX).

Если я начнуи используйте «C ++ / WinRT Windows Runtime Component» вместо «C ++ Windows Desktop Dynamic-Link Library», у меня все еще есть проблемы.

Outer C++/WinRT Windows Runtime Component

Если я это сделаю, я могу добавить ссылку просто отлично.

Successful Reference

Однако, когда я пытаюсь собрать, я получаю ошибку сборки.

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 (без какой-либо дополнительной настройки), так и в проекте ComponentC ++ Windows Desktop Dynamic-Link Library (и при запуске инструмента командной строки cppwinrt, как описано в этот ответ ).Однако это мне не помогает - я не пытаюсь ссылаться на пакет NuGet;Я пытаюсь сослаться на другой проект в том же решении.

Итак, после всего этого возникает вопрос: как я могу использовать универсальную среду выполнения Windows для вызова кода C # из кода C ++?

1 Ответ

0 голосов
/ 22 сентября 2018

Нельзя вызывать компоненты среды выполнения 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).

...