Я хотел бы написать приложение WPF, но построить его на максимально современных платформах, включая, например, .NET 6 или, может быть, даже выше.
У меня есть код C++, который я хочу вызвать, и мне нравится WinRT как компонентная модель вместо низкоуровневого P/Invoke.
Мне уже удалось интегрировать свой код C++ в приложение WinUI3 с помощью CsWinRT. Теперь я пытаюсь сделать то же самое со своим приложением WPF. Мою попытку можно увидеть по адресу https://github.com/mmarczell-graphisoft/winrtbug
Пока у меня нет директивы using в моем коде C# WPF или кода, использующего эти определения, файл проекции C# создается в папке obj\Debug\net6.0-windows\Generated Files\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-comComponents/
с примером кода: 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-comComponent
Однако сотрудники MS в обсуждениях на GitHub неоднократно предполагают, что на самом деле в этом нет необходимости, поскольку 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
@SimonMourier - я знаю эту документацию, но она оказалась вводящей в заблуждение, потому что даже в моем репозитории примеров, например, с проектом WinUI, она работает, напрямую ссылаясь на проект C++/WinRT, без всего танца nuget. Весь путь, как я зашел так далеко, а также советы, которые я получил от сотрудников MS, можно увидеть здесь: github.com/microsoft/CsWinRT/discussions/1072
В вопросе должно быть то, что вы знаете или не знаете. Почему вы не хотите использовать документированный способ, который работает?
@SimonMourier По двум причинам: 1. Сотрудники MS неоднократно предлагали не использовать его (см. мои правки) 2. Опыт разработчиков. Это кошмар — разрабатывать серверную часть C++ и интерфейс пользовательского интерфейса в одном приложении, если каждое изменение внутренней части требует новой упаковки NuGet, изменения кода версии; и отладка также становится намного более громоздкой.
Эти статьи старые. С .NET 8 я могу заставить официальный образец (github.com/microsoft/CsWinRT/tree/master/src/Samples/… ) работать довольно легко без nuget и консольного приложения (на том же уровне, что и другие проекты). ). с CsWinRTIncludes. Однако тот же макет не работает с приложением WPF (странно!), но может работать, если вы принудительно используете командную строку CsWinRT. Проверьте оба csproj здесь Pastebin.com/raw/mnmFb3Mf (PS UseWPF в консольном приложении использовался только для тестирования)
Это именно то «странно!» что меня интересует. Но я посмотрю на ваш пастбин
Это не такая же странность, как ваша проблема (и она отлично работает в консольном приложении)
Обходной путь в вашем Pastebin сработал. Спасибо! Если вы опубликуете это в качестве ответа здесь, я приму это.
Многие упомянутые здесь статьи устарели (то есть несколько лет, но для .NET Core несколько лет — это целая вечность), а в последней версии Framework некоторые вещи стали проще, чем были, но найти решение сложно.
Итак, начнем с этого (официального) руководства Создайте проекцию C# из компонента C++/WinRT, распространите в виде NuGet для приложений .NET , который доступен в качестве примера кода здесь Пример проекции C#/WinRT. Первое, что нужно сделать, это обновить все пакеты, особенно CsWinRT, который полностью устарел (текущая версия на сегодняшний день — 2.0.7
).
И затем, благодаря этому новому CsWinRT, вам даже не нужно использовать промежуточный проект Nuget, как описано в примере, потому что этот новый CsWinRT генерирует для нас некоторый файл .cs на лету из файла .winmd компонента (метаданные ).
Просто создайте проект SimpleMathComponent C++/WinRT, и теперь вы можете ссылаться на него в консольном приложении с помощью .csproj, подобного этому, используя .NET 8 и x64 (отладка или выпуск).
<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>
Мы можем увидеть автоматически созданный файл проекции .cs в каталоге obj
:
Теперь с проектом WPF тот же макет проекта не работает. По какой-то причине компонент SimpleMathComponent
не подхватывается CsWinRT для генерации кода (единственная реальная разница, которую я вижу, это 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 и т. д.).
Вы сделали все, что указано здесь: Learn.microsoft.com/en-us/windows/apps/develop/platform/… (для этого нужен промежуточный пакет nuget и т. д.)