Полное руководство: подключение C++/WinRT к приложениям C# WinUI3
Узнайте, как правильно подключать компоненты времени выполнения C++/WinRT к приложениям C# WinUI3 без предупреждений. Полное руководство со ссылками на проекты и устранением неполадок.
Как подключить компонент времени выполнения C++/WinRT к приложению C# на WinUI3
Я потратил много времени, пытаясь заставить это работать, но ничего не получилось. Прямая ссылка на файл .winmd из .NET 5+ невозможна, и я не хочу использовать старые версии .NET. Я также пробовал добавлять компонент среды выполнения Windows сам в качестве ссылки на проект, но после повторного открытия решения Visual Studio отображала значок предупреждения на этой ссылке.
Я тестировал это с каждым возможным типом компонента среды выполнения Windows — компонент среды выполнения Windows (WinUI 3), компонент среды выполнения Windows (C++/WinRT) — но значок предупреждения сохранялся во всех случаях. Я ищу правильное решение (желательно без хаков или обходных путей).
Подключение компонента C++/WinRT к приложению C# WinUI3
Подключение компонента C++/WinRT к приложению C# WinUI3 требует понимания системы проекции Windows Runtime и правильной настройки проекта. Решение включает в себя ссылку на компонент через выходные данные сборки, а не прямое добавление файлов .winmd, а также обеспечение совместимости версий Windows SDK в обоих проектах с использованием правильного метода добавления ссылки.
Содержание
- Понимание архитектуры компонента WinRT
- Создание компонента C++/WinRT
- Настройка проекта C# WinUI3
- Правильная настройка ссылки на проект
- Устранение распространенных проблем
- Расширенные шаблоны реализации
Понимание архитектуры компонента WinRT
Компоненты Windows Runtime (WinRT) служат мостом между различными языками программирования в экосистеме Windows. При создании компонента C++/WinRT генерируются файлы метаданных (.winmd), содержащие информацию о типах, используемых потребляющими языками, такими как C#. Система проекции Windows Runtime автоматически обрабатывает преобразование между типами C++ и их соответствующими представлениями в C#.
Ключевая концепция архитектуры, которую необходимо понять, заключается в том, что компоненты WinRT не ссылаются напрямую на сборки .NET. Вместо этого они компилируются в метаданные Windows Runtime, которые проецируются в потребляющий язык. Это означает, что вы не можете просто добавить файл .winmd в качестве ссылки в проект .NET 5+, поскольку механизм ссылок изменился.
Важно: Файл .winmd содержит определения типов, но фактическая реализация находится в DLL C#. Проекту C# нужны и метаданные, и реализация для корректной работы.
Создание компонента C++/WinRT
Начните с создания правильного проекта компонента C++/WinRT в Visual Studio:
-
Создайте новый проект
- Выберите “Компонент среды выполнения Windows (C++/WinRT)” из шаблонов C++
- Назовите ваш компонент (например, “MyCppComponent”)
- Выберите расположение и нажмите “Создать”
-
Реализуйте классы компонента
cpp// MyComponent.h #pragma once #include "MyComponent.g.h" namespace winrt::MyComponent::implementation { struct MyComponent : MyComponentT<MyComponent> { MyComponent() = default; int32_t AddNumbers(int32_t a, int32_t b); hstring GetString(); }; } namespace winrt::MyComponent::factory_implementation { struct MyComponent : MyComponentT<MyComponent, implementation::MyComponent> { }; } -
Реализуйте методы
cpp// MyComponent.cpp #include "pch.h" #include "MyComponent.h" #include "MyComponent.g.cpp" namespace winrt::MyComponent::implementation { int32_t MyComponent::AddNumbers(int32_t a, int32_t b) { return a + b; } hstring MyComponent::GetString() { return L"Hello from C++ WinRT!"; } } -
Обновите файл проекта
Убедитесь, что ваш .vcxproj файл содержит необходимые ссылки на Windows SDK:xml<PropertyGroup> <TargetPlatformVersion>10.0.22621.0</TargetPlatformVersion> <WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion> </PropertyGroup>
Настройка проекта C# WinUI3
Для вашего проекта C# WinUI3 выполните следующие шаги:
-
Создайте новый проект WinUI3
- Выберите шаблон “Пустое приложение, упакованное (WinUI 3 для настольных ПК)”
- Укажите целевую платформу .NET 6, .NET 7 или .NET 8 (избегайте .NET Framework для WinUI3)
-
Настройте свойства проекта
- Убедитесь, что целевая платформа .NET 6/7/8
- Установите целевую платформу x64 или x86 (совпадающую с вашим компонентом C++)
- Проверьте совместимость версии Windows SDK с вашим компонентом C++
-
Добавьте необходимые ссылки на пакеты
xml<ItemGroup> <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.230829000" /> <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.755" /> </ItemGroup>
Правильная настройка ссылки на проект
Здесь большинство разработчиков сталкиваются с проблемами. Вот правильный подход:
Метод 1: Ссылка на проект (Рекомендуется)
-
Сначала соберите компонент C++
- Щелкните правой кнопкой мыши по проекту C++ → Сборка
- Убедитесь, что сборка прошла успешно
-
Правильно добавьте ссылку на проект
- Щелкните правой кнопкой мыши по вашему проекту C# → Добавить → Ссылка на проект
- Выберите проект компонента C++ WinRT
- Не устанавливайте флажок “Копировать локально” для ссылки
-
Проверьте ссылку
- Ссылка должна отображаться без значков предупреждений
- Теперь вы должны иметь возможность использовать классы C++ в коде C#
// MainPage.xaml.cs
using MyComponent;
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
var component = new MyComponent();
int result = component.AddNumbers(5, 3);
ResultText.Text = $"Результат: {result}";
string message = component.GetString();
MessageText.Text = message;
}
}
Метод 2: Ручная настройка ссылки (Когда ссылка на проект не работает)
Если ссылки на проект продолжают показывать предупреждения, вы можете настроить ссылку вручную:
-
Найдите сгенерированные файлы
- После сборки проекта C++ посмотрите в папке
x64\Debug(или вашей папке конфигурации сборки) - Вы должны найти
MyComponent.winmdиMyComponent.dll
- После сборки проекта C++ посмотрите в папке
-
Скопируйте файлы в проект C#
- Создайте папку
Runtimeв вашем проекте C# - Скопируйте оба файла (
.winmdи.dll) в эту папку - Установите для файла .dll параметр “Копировать в выходной каталог” в “Копировать, если новее”
- Создайте папку
-
Добавьте ссылку вручную
- Щелкните правой кнопкой мыши по проекту C# → Добавить → Ссылка
- Перейдите к файлу
.winmdи выберите его
Устранение распространенных проблем
Значок предупреждения на ссылке на проект
Если вы видите значок предупреждения на ссылке на проект:
Возможные причины:
- Несовместимые версии Windows SDK между проектами
- Несовпадающие целевые платформы (x86 против x64)
- Отсутствующие инструменты сборки Windows SDK
- Поврежденный кэш проекта
Решения:
-
Очистите и пересоберите все проекты
- Сборка → Очистить решение
- Сборка → Пересобрать решение
-
Проверьте версии SDK
xml<!-- Проект C++ --> <TargetPlatformVersion>10.0.22621.0</TargetPlatformVersion> <!-- Проект C# --> <WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion> -
Проверьте архитектуру сборки
- Оба проекта должны целиться на одну и ту же платформу (рекомендуется x64)
- Проверьте “Диспетчер конфигураций” → Активная платформа решения
Проблемы со ссылками в .NET 5+
Поскольку .NET 5+ изменил работу со ссылками, вы можете столкнуться с:
- Отсутствующий файл .winmd: Убедитесь, что проект C++ успешно собран
- Проблемы разрешения путей: Используйте ссылки на проекты вместо файловых ссылок
- Совместимость SDK: Используйте совпадающие версии Windows SDK
<!-- В файле .csproj убедитесь, что эти свойства установлены -->
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<UseWinUI>true</UseWinUI>
</PropertyGroup>
Проблемы с разрешением типов
Если вы не можете разрешить типы из компонента C++:
-
Добавьте директивы using
csharpusing MyComponent; -
Проверьте имена пространств имен
- Убедитесь, что пространство имен совпадает с именем вашего проекта C++
- Проверьте правильность регистра имен классов
-
Пересоберите решение
- Иногда Visual Studio требуется полная пересборка для обновления кэша типов
Расширенные шаблоны реализации
Реализация асинхронного шаблона
Для асинхронных операций в вашем компоненте C++:
// Асинхронная операция в C++
IAsync<int32_t> LongOperationAsync()
{
co_await winrt::resume_after(std::chrono::seconds(2));
co_return 42;
}
// Использование в C#
private async void OnAsyncClick(object sender, RoutedEventArgs e)
{
var component = new MyComponent();
int result = await component.LongOperationAsyncAsync();
ResultText.Text = $"Асинхронный результат: {result}";
}
Обработка событий
Реализуйте события в C++ и используйте их в C#:
// Компонент C++ с событиями
struct MyComponent : MyComponentT<MyComponent>
{
MyComponent() = default;
winrt::event_token ValueChanged(winrt::Windows::Foundation::TypedEventHandler<MyComponent, int32_t> const& handler)
{
return m_valueChanged.add(handler);
}
void ValueChanged(winrt::event_token const& token)
{
m_valueChanged.remove(token);
}
void SetValue(int32_t value)
{
m_value = value;
m_valueChanged(*this, value);
}
private:
winrt::event<winrt::Windows::Foundation::TypedEventHandler<MyComponent, int32_t>> m_valueChanged;
int32_t m_value{0};
};
// Использование событий в C#
var component = new MyComponent();
component.ValueChanged += (sender, value) =>
{
Debug.WriteLine($"Значение изменено на: {value}");
};
component.SetValue(100);
Внедрение зависимостей
Для более сложных приложений рассмотрите внедрение зависимостей:
// В запуске C#
services.AddSingleton<MyComponent>();
// В конструкторе страницы
public MainPage(MyComponent component)
{
this.InitializeComponent();
this.component = component;
}
Заключение
Подключение компонентов C++/WinRT к приложениям C# WinUI3 требует тщательного внимания к настройке проекта и пониманию системы проекции Windows Runtime. Ключевые выводы:
- Используйте ссылки на проекты вместо прямых ссылок на файлы .winmd для проектов .NET 5+
- Обеспечивайте совместимость между версиями Windows SDK и целевыми платформами
- Сначала соберите компонент C++ перед добавлением ссылок в проект C#
- Очищайте и пересобирайте все решение при возникновении проблем со ссылками
- Избегайте ручного копирования файлов как основного решения - используйте правильные ссылки на проекты
Правильное решение включает создание компонента C++/WinRT с правильным типом проекта, настройку вашего проекта C# WinUI3 с совместимыми версиями SDK и использование диалога “Добавить ссылку на проект” вместо ручного добавления файлов .winmd. Этот подход устраняет значки предупреждений и обеспечивает правильное разрешение типов между двумя языками.
Для сложных сценариев рассмотрите реализацию асинхронных шаблонов, обработки событий и внедрения зависимостей для создания надежных, поддерживаемых приложений, использующих преимущества как C++, так и C#.
Источники
- Документация Microsoft - Создание компонента среды выполнения Windows на C++/WinRT
- Документация Microsoft - Использование компонентов среды выполнения Windows в C#
- Документация Microsoft - Шаблоны проектов WinUI 3
- Документация Microsoft - Справочник по среде выполнения Windows
- GitHub - Примеры Windows App SDK