Создание приложения C# .NET с использованием WinUI 3 и возможностей взаимодействия Win32
В этой статье показано, как создать базовое приложение C# .NET с возможностями взаимодействия WinUI 3 и Win32 с помощью служб вызова платформы (PInvoke).
Необходимые компоненты
- Настройте среду разработки, как описано в статье Установка инструментов для Windows App SDK.
- Проверьте конфигурацию, выполнив действия, описанные в статье Создание первого проекта WinUI 3.
Базовое управляемое приложение C#/.NET
В этом примере мы укажем расположение и размер окна приложения, преобразуем и масштабируем его для соответствующего DPI, отключим кнопки "Свернуть" и "Развернуть" окна, наконец, выполним запрос к текущему процессу, чтобы отобразить список модулей, загруженных в текущем процессе.
Мы создадим пример приложения на основе исходного шаблона приложения (см. раздел Предварительные требования). Также см. статью Шаблоны WinUI 3 в Visual Studio.
Файл MainWindow.xaml
С помощью WinUI 3 можно создавать экземпляры класса Window в разметке XAML.
Класс Window XAML был расширен для поддержки окон рабочего стола, преобразуя его в абстракцию всех низкоуровневых реализаций окон, которые используются моделями UWP и классическими приложениями. В частности, CoreWindow для UWP и дескрипторы окон (или объекты HWND) для Win32.
В следующем примере кода показан файл MainWindow.xaml из исходного приложения-шаблона, в котором класс Window используется в качестве корневого элемента для приложения.
<Window
x:Class="WinUI_3_basic_win32_interop.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WinUI_3_basic_win32_interop"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="myButton" Click="myButton_Click">Click Me</Button>
</StackPanel>
</Window>
Настройка
Для вызова API-интерфейсов Win32, предоставленных в библиотеке User32.dll, добавьте PInvoke.User32 пакет NuGet с открытым кодом в проект Visual Studio (в меню Visual Studio выберите Инструменты -> Диспетчер пакетов NuGet -> Управление пакетами NuGet для решения... и найдите "Pinvoke.User32"). Дополнительные сведения см. в статье Вызов собственных функций из управляемого кода.
Диспетчер пакетов NuGet с выбранным PInvoke.User32.Убедитесь, что установка прошла успешно, проверив папку Packages в проекте VS.
Пакеты Обозревателя решений с PInvoke.User32.Затем дважды щелкните файл проекта приложения (или щелкните правой кнопкой мыши и выберите "Изменить файл проекта"), чтобы открыть файл в текстовом редакторе и убедиться, что файл проекта теперь содержит NuGet
PackageReference
для PInvoke.User32.<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>net6.0-windows10.0.19041.0</TargetFramework> <TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion> <RootNamespace>WinUI_3_basic_win32_interop</RootNamespace> <ApplicationManifest>app.manifest</ApplicationManifest> <Platforms>x86;x64;arm64</Platforms> <RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers> <UseWinUI>true</UseWinUI> </PropertyGroup> <ItemGroup> <PackageReference Include="Microsoft.ProjectReunion" Version="0.8.1" /> <PackageReference Include="Microsoft.ProjectReunion.Foundation" Version="0.8.1" /> <PackageReference Include="Microsoft.ProjectReunion.WinUI" Version="0.8.1" /> <PackageReference Include="PInvoke.User32" Version="0.7.104" /> <Manifest Include="$(ApplicationManifest)" /> </ItemGroup> </Project>
Код
В файле кода программной части
App.xaml.cs
мы получаем дескриптор для Window с помощью метода COM-взаимодействия WinRT WindowNative.GetWindowHandle (см. статью Получение дескриптора окна (HWND)).Этот метод вызывается из обработчика приложения OnLaunched, как показано ниже:
/// <summary> /// Invoked when the application is launched normally by the end user. Other entry points /// will be used such as when the application is launched to open a specific file. /// </summary> /// <param name="args">Details about the launch request and process.</param> protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) { m_window = new MainWindow(); var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(m_window); SetWindowDetails(hwnd, 800, 600); m_window.Activate(); }
Затем вызовем метод
SetWindowDetails
, передав дескриптор окна и предпочтительные измерения. Не забудьте добавить директивуusing static PInvoke.User32;
.В этом методе мы выполняем следующие действия:
- Вызываем GetDpiForWindow, чтобы получить значение точек на дюйм (DPI) для окна (в Win32 используются фактические пиксели, а в WinUI 3 — эффективные пиксели). Это значение точек на дюйм используется для вычисления коэффициента масштабирования и применения его к ширине и высоте, указанным для окна.
- Затем вызываем SetWindowPos, чтобы указать нужное расположение окна.
- Наконец, вызываем SetWindowLong для отключения кнопок Свернуть и Развернуть.
private static void SetWindowDetails(IntPtr hwnd, int width, int height) { var dpi = GetDpiForWindow(hwnd); float scalingFactor = (float)dpi / 96; width = (int)(width * scalingFactor); height = (int)(height * scalingFactor); _ = SetWindowPos(hwnd, SpecialWindowHandles.HWND_TOP, 0, 0, width, height, SetWindowPosFlags.SWP_NOMOVE); _ = SetWindowLong(hwnd, WindowLongIndexFlags.GWL_STYLE, (SetWindowLongFlags)(GetWindowLong(hwnd, WindowLongIndexFlags.GWL_STYLE) & ~(int)SetWindowLongFlags.WS_MINIMIZEBOX & ~(int)SetWindowLongFlags.WS_MAXIMIZEBOX)); }
В файле MainWindow.xaml мы используем ContentDialog с ScrollViewer для вывода списка всех модулей, загруженных для текущего процесса.
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"> <Button x:Name="myButton" Click="myButton_Click">Display loaded modules</Button> <ContentDialog x:Name="contentDialog" CloseButtonText="Close"> <ScrollViewer> <TextBlock x:Name="cdTextBlock" TextWrapping="Wrap" /> </ScrollViewer> </ContentDialog> </StackPanel>
Затем замените обработчик событий
MyButton_Click
следующим кодом.Здесь мы получаем ссылку на текущий процесс, вызвав GetCurrentProcess. Затем выполним итерацию по коллекции модулей и добавим имя файла каждого объекта ProcessModule в отображаемую строку.
private async void myButton_Click(object sender, RoutedEventArgs e) { myButton.Content = "Clicked"; var description = new System.Text.StringBuilder(); var process = System.Diagnostics.Process.GetCurrentProcess(); foreach (System.Diagnostics.ProcessModule module in process.Modules) { description.AppendLine(module.FileName); } cdTextBlock.Text = description.ToString(); await contentDialog.ShowAsync(); }
Скомпилируйте и запустите приложение.
После появления окна нажмите кнопку Display loaded modules (Отобразить загруженные модули).
Базовое приложение Win32 взаимодействия, описанное в этой статье.
Итоги
В этом статье мы рассмотрели доступ к базовой реализации окна, в данном случае Win32 и HWND, а также использование API-интерфейсов Win32 вместе с API-интерфейсами WinRT. Благодаря этому при создании классических приложений WinUI 3 мы можем использовать часть имеющегося кода классического приложения.
Более обширный пример см. в образце коллекции AppWindow в репозитории GitHub Примеры использования пакета SDK для приложений Windows.
См. также
Windows developer
Обратная связь
https://aka.ms/ContentUserFeedback.
Ожидается в ближайшее время: в течение 2024 года мы постепенно откажемся от GitHub Issues как механизма обратной связи для контента и заменим его новой системой обратной связи. Дополнительные сведения см. в разделеОтправить и просмотреть отзыв по