Используйте компонент C++/WinRT (но на самом деле любой компонент WinRT) в WPF .NET 6

Я хотел бы написать приложение 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

Вы сделали все, что указано здесь: Learn.microsoft.com/en-us/windows/apps/develop/platform/… (для этого нужен промежуточный пакет nuget и т. д.)

Simon Mourier 12.04.2024 18:33

@SimonMourier - я знаю эту документацию, но она оказалась вводящей в заблуждение, потому что даже в моем репозитории примеров, например, с проектом WinUI, она работает, напрямую ссылаясь на проект C++/WinRT, без всего танца nuget. Весь путь, как я зашел так далеко, а также советы, которые я получил от сотрудников MS, можно увидеть здесь: github.com/microsoft/CsWinRT/discussions/1072

marczellm 13.04.2024 22:36

В вопросе должно быть то, что вы знаете или не знаете. Почему вы не хотите использовать документированный способ, который работает?

Simon Mourier 15.04.2024 09:21

@SimonMourier По двум причинам: 1. Сотрудники MS неоднократно предлагали не использовать его (см. мои правки) 2. Опыт разработчиков. Это кошмар — разрабатывать серверную часть C++ и интерфейс пользовательского интерфейса в одном приложении, если каждое изменение внутренней части требует новой упаковки NuGet, изменения кода версии; и отладка также становится намного более громоздкой.

marczellm 16.04.2024 10:34

Это именно то «странно!» что меня интересует. Но я посмотрю на ваш пастбин

marczellm 17.04.2024 10:57

Это не такая же странность, как ваша проблема (и она отлично работает в консольном приложении)

Simon Mourier 17.04.2024 13:53

Обходной путь в вашем Pastebin сработал. Спасибо! Если вы опубликуете это в качестве ответа здесь, я приму это.

marczellm 17.04.2024 16:58
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
8
212
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Многие упомянутые здесь статьи устарели (то есть несколько лет, но для .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 и т. д.).

Другие вопросы по теме