Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом разделе мы рассмотрим, как создать базовое приложение C# .NET с возможностями взаимодействия WinUI и Win32, используя службы вызова платформы (PInvoke).
Prerequisites
Базовое управляемое приложение C#/.NET
В этом примере мы укажем расположение и размер окна приложения, преобразуем и масштабируем его для соответствующего DPI, отключим кнопки сворачивания и развёртывания окна, а затем запросим текущий процесс, чтобы отобразить список модулей, загруженных в текущий процесс.
Мы собираемся создать пример приложения из исходного приложения-шаблона (см. предварительные требования). См. также шаблоны WinUI в Visual Studio.
Файл MainWindow.xaml
С помощью WinUI можно создавать экземпляры класса Window в разметке XAML.
Класс окна 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>
Configuration
Чтобы вызвать API Win32, экспортированные из
User32.dll, можно использовать C#/Win32 P/Invoke Source Generator в Visual Studio project. Щелкните Tools>NuGet Package Manager>Manage NuGet Packages for Solution... и (на вкладке Browse) найдите Microsoft.Windows.CsWin32. Дополнительные сведения см. в разделе Вызов Нативных Функций из Управляемого Кода.При необходимости можно подтвердить, что установка выполнена успешно, убедив, что Microsoft.Windows.CsWin32 указан в узле Dependencies>Packages в Solution Explorer.
Кроме того, можно дважды щелкнуть файл project приложения (или щелкнуть правой кнопкой мыши и выбрать файл Edit project), чтобы открыть файл в текстовом редакторе и подтвердить, что файл project теперь содержит файл NuGet
PackageReferenceдля Microsoft.Windows.CsWin32.<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>WinExe</OutputType> <TargetFramework>net8.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>win-x86;win-x64;win-arm64</RuntimeIdentifiers> <PublishProfile>win-$(Platform).pubxml</PublishProfile> <UseWinUI>true</UseWinUI> <EnableMsixTooling>true</EnableMsixTooling> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <Content Include="Assets\SplashScreen.scale-200.png" /> <Content Include="Assets\LockScreenLogo.scale-200.png" /> <Content Include="Assets\Square150x150Logo.scale-200.png" /> <Content Include="Assets\Square44x44Logo.scale-200.png" /> <Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" /> <Content Include="Assets\StoreLogo.png" /> <Content Include="Assets\Wide310x150Logo.scale-200.png" /> </ItemGroup> <ItemGroup> <Manifest Include="$(ApplicationManifest)" /> </ItemGroup> <!-- Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging Tools extension to be activated for this project even if the Windows App SDK Nuget package has not yet been restored. --> <ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'"> <ProjectCapability Include="Msix" /> </ItemGroup> <ItemGroup> <PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.183"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> </PackageReference> <PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.1742" /> <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.6.250205002" /> </ItemGroup> <!-- Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution Explorer "Package and Publish" context menu entry to be enabled for this project even if the Windows App SDK Nuget package has not yet been restored. --> <PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'"> <HasPackageAndPublishMenu>true</HasPackageAndPublishMenu> </PropertyGroup> <!-- Publish Properties --> <PropertyGroup> <PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun> <PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun> <PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed> <PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed> </PropertyGroup> </Project>Добавьте текстовый файл в project и назовите его
NativeMethods.txt. Содержимое этого файла информирует генератор исходного кода C#/Win32 P/Invoke о функциях и типах, для которых вы хотите сгенерировать исходный код P/Invoke. Другими словами, какие функции и типы будут вызываться и использовать в коде C#.GetDpiForWindow GetWindowLong SetWindowPos SetWindowLong HWND_TOP WINDOW_STYLE
Code
В файле кода программной части мы получаем дескриптор
App.xaml.csс помощью метода взаимодействия WindowNative.GetWindowHandle WinRT COM (см. Получение дескриптора окна (HWND)).Этот метод вызывается из обработчика OnLaunched приложения, как показано ниже:
/// <summary> /// Invoked when the application is launched. /// </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, передав идентификатор окна и предпочитаемые размеры.В этом методе:
- Мы вызываем GetDpiForWindow , чтобы получить значения точек на дюйм (dpi) для окна (Win32 использует физические пиксели, а WinUI использует эффективные пиксели). Это значение dpi используется для вычисления коэффициента масштабирования и применения его к ширине и высоте, указанной для окна.
- Затем мы вызываем SetWindowPos , чтобы указать требуемое расположение окна.
- Наконец, мы вызываем SetWindowLong , чтобы отключить кнопки "Свернуть " и "Развернуть ".
private static void SetWindowDetails(IntPtr hwnd, int width, int height) { var dpi = Windows.Win32.PInvoke.GetDpiForWindow((Windows.Win32.Foundation.HWND)hwnd); float scalingFactor = (float)dpi / 96; width = (int)(width * scalingFactor); height = (int)(height * scalingFactor); _ = Windows.Win32.PInvoke.SetWindowPos((Windows.Win32.Foundation.HWND)hwnd, Windows.Win32.Foundation.HWND.HWND_TOP, 0, 0, width, height, Windows.Win32.UI.WindowsAndMessaging.SET_WINDOW_POS_FLAGS.SWP_NOMOVE); var nIndex = Windows.Win32.PInvoke.GetWindowLong((Windows.Win32.Foundation.HWND)hwnd, Windows.Win32.UI.WindowsAndMessaging.WINDOW_LONG_PTR_INDEX.GWL_STYLE) & ~(int)Windows.Win32.UI.WindowsAndMessaging.WINDOW_STYLE.WS_MINIMIZEBOX & ~(int)Windows.Win32.UI.WindowsAndMessaging.WINDOW_STYLE.WS_MAXIMIZEBOX; _ = Windows.Win32.PInvoke.SetWindowLong((Windows.Win32.Foundation.HWND)hwnd, Windows.Win32.UI.WindowsAndMessaging.WINDOW_LONG_PTR_INDEX.GWL_STYLE, nIndex); }В файле 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(); }Скомпилируйте и запустите приложение.
После появления окна нажмите кнопку "Отображать загруженные модули".
Базовое приложение взаимодействия Win32, описанное в этом разделе.
Summary
В этом разделе мы рассмотрели доступ к базовой реализации окна (в данном случае Win32 и HWND) и использованию API Win32 вместе с API WinRT. В этом разделе показано, как использовать существующий код настольного приложения при создании новых настольных приложений WinUI.
Более подробный пример см. в примере коллекции AppWindow в репозитории Windows App SDK Samples GitHub.
Пример настройки строки заголовка окна
В этом втором примере показано, как настроить заголовок окна и его содержимое. Прежде чем следовать вместе с ним, ознакомьтесь со следующими разделами:
Создание проекта
- В Visual Studio создайте новый проект C# или C++/WinRT из шаблона проекта WinUI Blank App (Packaged).
Configuration
Опять же, обратитесь к пакету NuGet Microsoft.Windows.CsWin32 так же, как и в первом примере.
Добавьте текстовый файл
NativeMethods.txtв проект.LoadImage SendMessage SetWindowText WM_SETICON
MainWindow.xaml
Note
Если вам нужен файл значка, чтобы использовать в этом пошаговом руководстве, можно скачать этот файл из примера приложения WirelessHostednetwork. Поместите этот файл в папку Assets и добавьте его в project в качестве содержимого. Затем вы сможете ссылаться на файл с помощью URL-адреса Assets/computer.ico.
В противном случае вы можете использовать файл значка, который у вас уже есть, и изменить две ссылки на него в приведенных ниже списках кода.
- В приведенном ниже списке кода вы увидите, что в
MainWindow.xamlсписке мы добавили две кнопки и указали обработчики щелчков для каждого. В обработчике события Click для первой кнопки (basicButton_Click) мы задали значок и текст на панели заголовка. Во втором (customButton_Click) мы демонстрируем более значительную настройку, заменив заголовок содержимым StackPanel с именем customTitleBarPanel.
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="window_titlebar.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:window_titlebar"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Basic WinUI 3 Window title bar sample">
<Grid x:Name="rootElement" RowDefinitions="100, *, 100, *">
<StackPanel x:Name="customTitleBarPanel" Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Top" Visibility="Collapsed">
<Image Source="Images/windowIcon.gif" />
<TextBlock VerticalAlignment="Center" Text="Full customization of title bar"/>
</StackPanel>
<StackPanel x:Name="buttonPanel" Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Name="basicButton" Click="basicButton_Click" Margin="25">Set the Window title and icon</Button>
<Button x:Name="customButton" Click="customButton_Click" Margin="25">Customize the window title bar</Button>
</StackPanel>
</Grid>
</Window>
MainWindow.xaml.cs/cpp
- В приведенном ниже фрагменте кода для обработчика basicButton_Click мы сворачиваем панель customTitleBarPanelStackPanel, чтобы скрыть настраиваемую строку заголовка, и задаем свойству ExtendsContentIntoTitleBar значение
false. - Затем мы вызываем IWindowNative::get_WindowHandle (для C#, используя вспомогательный метод GetWindowHandle), чтобы получить дескриптор окна (HWND) главного окна.
- Затем мы зададим значок приложения (для C#, используя пакет NuGet PInvoke.User32 ), вызвав функции LoadImage и SendMessage .
- Наконец, мы вызываем SetWindowText для обновления строки заголовка.
private void basicButton_Click(object sender, RoutedEventArgs e)
{
// Ensure the custom title bar content is not displayed.
customTitleBarPanel.Visibility = Visibility.Collapsed;
// Disable custom title bar content.
ExtendsContentIntoTitleBar = false;
//Get the Window's HWND
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
var hIcon = Windows.Win32.PInvoke.LoadImage(
null,
"Images/windowIcon.ico",
Windows.Win32.UI.WindowsAndMessaging.GDI_IMAGE_TYPE.IMAGE_ICON,
20, 20,
Windows.Win32.UI.WindowsAndMessaging.IMAGE_FLAGS.LR_LOADFROMFILE);
Windows.Win32.PInvoke.SendMessage(
(Windows.Win32.Foundation.HWND)hwnd,
Windows.Win32.PInvoke.WM_SETICON,
(Windows.Win32.Foundation.WPARAM)0,
(Windows.Win32.Foundation.LPARAM)hIcon.DangerousGetHandle());
Windows.Win32.PInvoke.SetWindowText((Windows.Win32.Foundation.HWND)hwnd, "Basic customization of title bar");
}
// pch.h
...
#include <microsoft.ui.xaml.window.h>
...
// MainWindow.xaml.h
...
void basicButton_Click(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args);
...
// MainWindow.xaml.cpp
void MainWindow::basicButton_Click(IInspectable const&, RoutedEventArgs const&)
{
// Ensure the that custom title bar content is not displayed.
customTitleBarPanel().Visibility(Visibility::Collapsed);
// Disable custom title bar content.
ExtendsContentIntoTitleBar(false);
// Get the window's HWND
auto windowNative{ this->m_inner.as<::IWindowNative>() };
HWND hWnd{ 0 };
windowNative->get_WindowHandle(&hWnd);
HICON icon{ reinterpret_cast<HICON>(::LoadImage(nullptr, L"Assets/computer.ico", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE)) };
::SendMessage(hWnd, WM_SETICON, 0, (LPARAM)icon);
this->Title(L"Basic customization of title bar");
}
- В обработчике customButton_Click мы устанавливаем видимость customTitleBarPanelStackPanel в Visible.
- Затем мы устанавливаем свойству ExtendsContentIntoTitleBar значение
true, и вызываем SetTitleBar, чтобы отображать панель с пользовательским заголовкомStackPanel в качестве нашей настраиваемой строки заголовков.
private void customButton_Click(object sender, RoutedEventArgs e)
{
customTitleBarPanel.Visibility = Visibility.Visible;
// Enable custom title bar content.
ExtendsContentIntoTitleBar = true;
// Set the content of the custom title bar.
SetTitleBar(customTitleBarPanel);
}
// MainWindow.xaml.h
...
void customButton_Click(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args);
...
// MainWindow.xaml.cpp
void MainWindow::customButton_Click(IInspectable const&, RoutedEventArgs const&)
{
customTitleBarPanel().Visibility(Visibility::Visible);
// Enable custom title bar content.
ExtendsContentIntoTitleBar(true);
// Set the content of the custom title bar.
SetTitleBar(customTitleBarPanel());
}
App.xaml
-
App.xamlВ файле сразу после<!-- Other app resources here -->комментария мы добавили настраиваемые цветные кисти для заголовка окна, как показано ниже.
<?xml version="1.0" encoding="utf-8"?>
<Application
x:Class="window_titlebar.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:window_titlebar">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->
<SolidColorBrush x:Key="WindowCaptionBackground">Green</SolidColorBrush>
<SolidColorBrush x:Key="WindowCaptionBackgroundDisabled">LightGreen</SolidColorBrush>
<SolidColorBrush x:Key="WindowCaptionForeground">Red</SolidColorBrush>
<SolidColorBrush x:Key="WindowCaptionForegroundDisabled">Pink</SolidColorBrush>
</ResourceDictionary>
</Application.Resources>
</Application>
Если вы следовали этим шагам в своем приложении, вы можете теперь собрать свой проект и запустить приложение. Вы увидите окно приложения, аналогичное следующему (с значком пользовательского приложения):
Приложение-шаблон.
Ниже приведена базовая настраиваемая строка заголовка:
Шаблон приложения со значком пользовательского приложения.Ниже приведена полностью настраиваемая строка заголовка:
Приложение-шаблон с настраиваемой строкой заголовка.
См. также
Windows developer