Skip to content

Commit 24a375f

Browse files
committed
Merged main into live
2 parents f2945d5 + 719d780 commit 24a375f

27 files changed

+534
-1
lines changed

hub/apps/winui/winui3/desktop-winui3-app-with-basic-interop.md

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Build a C# .NET app with WinUI 3 and Win32 interop
33
description: Build a C# .NET application with WinUI 3 and basic Win32 interop capabilities using the Platform Invocation Services, or PInvoke.
4-
ms.date: 03/04/2025
4+
ms.date: 03/05/2025
55
ms.topic: article
66
keywords: windows 11, windows 10, uwp, COM, win32, winui, interop
77
ms.localizationpriority: high
@@ -56,6 +56,10 @@ The following code shows the MainWindow.xaml file from the initial template app,
5656

5757
:::code language="xml" source="samples/WinUI-3-basic-win32-interop/WinUI-3-basic-win32-interop/WinUI-3-basic-win32-interop.csproj" highlight="39":::
5858

59+
1. Add a text file to your project, and name it `NativeMethods.txt`. The contents of this file inform the C#/Win32 P/Invoke Source Generator the functions and types for which you want P/Invoke source code generated. In other words, which functions and types you'll be calling and using in your C# code.
60+
61+
:::code language="csharp" source="samples/WinUI-3-basic-win32-interop/WinUI-3-basic-win32-interop/NativeMethods.txt":::
62+
5963
### Code
6064

6165
1. In the `App.xaml.cs` code-behind file, we get a handle to the [**Window**](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window) by using the **WindowNative.GetWindowHandle** WinRT COM interop method (see [Retrieve a window handle (HWND)](../../develop/ui-input/retrieve-hwnd.md)).
@@ -95,6 +99,119 @@ In this topic we covered accessing the underlying window implementation (in this
9599

96100
For a more extensive sample, see the [AppWindow gallery sample](https://github.com/microsoft/WindowsAppSDK-Samples/tree/main/Samples/Windowing) in the [Windows App SDK Samples](https://github.com/microsoft/WindowsAppSDK-Samples) GitHub repo.
97101

102+
## An example to customize the window title bar
103+
104+
In this second example, we show how to customize the window's title bar and its content. Before following along with it, review these topics:
105+
106+
* [Install tools for the Windows App SDK](/windows/apps/windows-app-sdk/set-up-your-development-environment).
107+
* [Create your first WinUI 3 project](/windows/apps/winui/winui3/create-your-first-winui3-app).
108+
109+
### Create a new project
110+
111+
1. In Visual Studio, create a new C# or C++/WinRT project from the **Blank App, Packaged (WinUI 3 in Desktop)** project template.
112+
113+
### Configuration
114+
115+
1. Again, reference the *Microsoft.Windows.CsWin32* NuGet package just like we did in the first example.
116+
117+
1. Add a `NativeMethods.txt` text file to your project.
118+
119+
:::code language="csharp" source="samples/window-titlebar/window-titlebar/NativeMethods.txt":::
120+
121+
### MainWindow.xaml
122+
123+
> [!NOTE]
124+
> If you need an icon file to use with this walkthrough, then you can download the [`computer.ico` file](https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/netds/wlan/WirelessHostedNetwork/HostedNetwork/res/computer.ico) from the **WirelessHostednetwork** sample app. Place that file in your `Assets` folder, and add the file to your project as content. You'll then be able to refer to the file using the url `Assets/computer.ico`.
125+
>
126+
> Otherwise, feel free to use an icon file that you already have, and change the two references to it in the code listings below.
127+
128+
1. In the code listing below, you'll see that in `MainWindow.xaml` we've added two buttons, and specified **Click** handlers for each. In the **Click** handler for the first button (**basicButton_Click**), we set the title bar icon and text. In the second (**customButton_Click**), we demonstrate more significant customization by replacing the title bar with the content of the **StackPanel** named *customTitleBarPanel*.
129+
130+
:::code language="xaml" source="samples/window-titlebar/window-titlebar/MainWindow.xaml":::
131+
132+
### MainWindow.xaml.cs/cpp
133+
134+
1. In the code listing below for the **basicButton_Click** handler—in order to keep the custom title bar hidden—we collapse the *customTitleBarPanel* **StackPanel**, and we set the [ExtendsContentIntoTitleBar](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window.extendscontentintotitlebar) property to `false`.
135+
2. We then call **IWindowNative::get_WindowHandle** (for C#, using the interop helper method **GetWindowHandle**) to retrieve the window handle (**HWND**) of the main window.
136+
3. Next, we set the application icon (for C#, using the [PInvoke.User32](https://www.nuget.org/packages/PInvoke.User32/) NuGet package) by calling the [LoadImage](/windows/win32/api/winuser/nf-winuser-loadimagea) and [SendMessage](/windows/win32/api/winuser/nf-winuser-sendmessage) functions.
137+
4. Finally, we call [SetWindowText](/windows/win32/api/winuser/nf-winuser-setwindowtexta) to update the title bar string.
138+
139+
:::code language="csharp" source="samples/window-titlebar/window-titlebar/MainWindow.xaml.cs" id="basicButton_Click" highlight="3-7,8-9,12-23":::
140+
141+
```cppwinrt
142+
// pch.h
143+
...
144+
#include <microsoft.ui.xaml.window.h>
145+
...
146+
147+
// MainWindow.xaml.h
148+
...
149+
void basicButton_Click(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args);
150+
...
151+
152+
// MainWindow.xaml.cpp
153+
void MainWindow::basicButton_Click(IInspectable const&, RoutedEventArgs const&)
154+
{
155+
// Ensure the that custom title bar content is not displayed.
156+
customTitleBarPanel().Visibility(Visibility::Collapsed);
157+
158+
// Disable custom title bar content.
159+
ExtendsContentIntoTitleBar(false);
160+
161+
// Get the window's HWND
162+
auto windowNative{ this->m_inner.as<::IWindowNative>() };
163+
HWND hWnd{ 0 };
164+
windowNative->get_WindowHandle(&hWnd);
165+
166+
HICON icon{ reinterpret_cast<HICON>(::LoadImage(nullptr, L"Assets/computer.ico", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE)) };
167+
::SendMessage(hWnd, WM_SETICON, 0, (LPARAM)icon);
168+
169+
this->Title(L"Basic customization of title bar");
170+
}
171+
```
172+
173+
5. In the **customButton_Click** handler, we set the visibility of the *customTitleBarPanel* **StackPanel** to **Visible**.
174+
6. We then set the [ExtendsContentIntoTitleBar](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window.extendscontentintotitlebar) property to `true`, and call [SetTitleBar](/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window.settitlebar) to display the *customTitleBarPanel* **StackPanel** as our custom title bar.
175+
176+
:::code language="csharp" source="samples/window-titlebar/window-titlebar/MainWindow.xaml.cs" id="customButton_Click":::
177+
178+
```cppwinrt
179+
// MainWindow.xaml.h
180+
...
181+
void customButton_Click(Windows::Foundation::IInspectable const& sender, Microsoft::UI::Xaml::RoutedEventArgs const& args);
182+
...
183+
184+
// MainWindow.xaml.cpp
185+
void MainWindow::customButton_Click(IInspectable const&, RoutedEventArgs const&)
186+
{
187+
customTitleBarPanel().Visibility(Visibility::Visible);
188+
189+
// Enable custom title bar content.
190+
ExtendsContentIntoTitleBar(true);
191+
192+
// Set the content of the custom title bar.
193+
SetTitleBar(customTitleBarPanel());
194+
}
195+
```
196+
197+
### App.xaml
198+
199+
1. In the `App.xaml` file, immediately after the `<!-- Other app resources here -->` comment, we've added some custom-colored brushes for the title bar, as shown below.
200+
201+
:::code language="csharp" source="samples/window-titlebar/window-titlebar/App.xaml":::
202+
203+
1. If you've been following along with these steps in your own app, then you can build your project now, and run the app. You'll see an application window similar to the following (with the custom app icon):
204+
205+
:::image type="content" source="images/template-app-windowhandle.png" alt-text="Template app with no customization.":::<br/>*Template app.*
206+
207+
- Here's the basic custom title bar:
208+
209+
:::image type="content" source="images/template-app-windowhandle-basic-custom.png" alt-text="Template app with custom application icon.":::<br/>*Template app with custom application icon.*
210+
211+
- Here's the fully custom title bar:
212+
213+
:::image type="content" source="images/template-app-windowhandle-full-custom.png" alt-text="Template app with custom title bar.":::<br/>*Template app with custom title bar.*
214+
98215
## See also
99216

100217
- [Windows App SDK](../../windows-app-sdk/index.md)
Loading
Loading
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"profiles": {
3+
"WinUI-3-basic-win32-interop (Package)": {
4+
"commandName": "MsixPackage"
5+
},
6+
"WinUI-3-basic-win32-interop (Unpackaged)": {
7+
"commandName": "Project"
8+
}
9+
}
10+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.13.35825.156 d17.13
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "window-titlebar", "window-titlebar\window-titlebar.csproj", "{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|ARM64 = Debug|ARM64
11+
Debug|x64 = Debug|x64
12+
Debug|x86 = Debug|x86
13+
Release|ARM64 = Release|ARM64
14+
Release|x64 = Release|x64
15+
Release|x86 = Release|x86
16+
EndGlobalSection
17+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
18+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Debug|ARM64.ActiveCfg = Debug|ARM64
19+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Debug|ARM64.Build.0 = Debug|ARM64
20+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Debug|ARM64.Deploy.0 = Debug|ARM64
21+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Debug|x64.ActiveCfg = Debug|x64
22+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Debug|x64.Build.0 = Debug|x64
23+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Debug|x64.Deploy.0 = Debug|x64
24+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Debug|x86.ActiveCfg = Debug|x86
25+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Debug|x86.Build.0 = Debug|x86
26+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Debug|x86.Deploy.0 = Debug|x86
27+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Release|ARM64.ActiveCfg = Release|ARM64
28+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Release|ARM64.Build.0 = Release|ARM64
29+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Release|ARM64.Deploy.0 = Release|ARM64
30+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Release|x64.ActiveCfg = Release|x64
31+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Release|x64.Build.0 = Release|x64
32+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Release|x64.Deploy.0 = Release|x64
33+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Release|x86.ActiveCfg = Release|x86
34+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Release|x86.Build.0 = Release|x86
35+
{4B0C7FDC-6696-499B-B51F-583AF2FDDC9B}.Release|x86.Deploy.0 = Release|x86
36+
EndGlobalSection
37+
GlobalSection(SolutionProperties) = preSolution
38+
HideSolutionNode = FALSE
39+
EndGlobalSection
40+
GlobalSection(ExtensibilityGlobals) = postSolution
41+
SolutionGuid = {DDC50E4B-3A69-408E-A79C-A2C292E2FE6B}
42+
EndGlobalSection
43+
EndGlobal
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Application
3+
x:Class="window_titlebar.App"
4+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
5+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
6+
xmlns:local="using:window_titlebar">
7+
<Application.Resources>
8+
<ResourceDictionary>
9+
<ResourceDictionary.MergedDictionaries>
10+
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
11+
<!-- Other merged dictionaries here -->
12+
</ResourceDictionary.MergedDictionaries>
13+
<!-- Other app resources here -->
14+
<SolidColorBrush x:Key="WindowCaptionBackground">Green</SolidColorBrush>
15+
<SolidColorBrush x:Key="WindowCaptionBackgroundDisabled">LightGreen</SolidColorBrush>
16+
<SolidColorBrush x:Key="WindowCaptionForeground">Red</SolidColorBrush>
17+
<SolidColorBrush x:Key="WindowCaptionForegroundDisabled">Pink</SolidColorBrush>
18+
</ResourceDictionary>
19+
</Application.Resources>
20+
</Application>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Runtime.InteropServices.WindowsRuntime;
6+
using Windows.ApplicationModel;
7+
using Windows.ApplicationModel.Activation;
8+
using Windows.Foundation;
9+
using Windows.Foundation.Collections;
10+
using Microsoft.UI.Xaml;
11+
using Microsoft.UI.Xaml.Controls;
12+
using Microsoft.UI.Xaml.Controls.Primitives;
13+
using Microsoft.UI.Xaml.Data;
14+
using Microsoft.UI.Xaml.Input;
15+
using Microsoft.UI.Xaml.Media;
16+
using Microsoft.UI.Xaml.Navigation;
17+
using Microsoft.UI.Xaml.Shapes;
18+
19+
// To learn more about WinUI, the WinUI project structure,
20+
// and more about our project templates, see: http://aka.ms/winui-project-info.
21+
22+
namespace window_titlebar
23+
{
24+
/// <summary>
25+
/// Provides application-specific behavior to supplement the default Application class.
26+
/// </summary>
27+
public partial class App : Application
28+
{
29+
/// <summary>
30+
/// Initializes the singleton application object. This is the first line of authored code
31+
/// executed, and as such is the logical equivalent of main() or WinMain().
32+
/// </summary>
33+
public App()
34+
{
35+
this.InitializeComponent();
36+
}
37+
38+
/// <summary>
39+
/// Invoked when the application is launched.
40+
/// </summary>
41+
/// <param name="args">Details about the launch request and process.</param>
42+
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
43+
{
44+
m_window = new MainWindow();
45+
m_window.Activate();
46+
}
47+
48+
private Window? m_window;
49+
}
50+
}
Loading
Loading
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Window
3+
x:Class="window_titlebar.MainWindow"
4+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
5+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
6+
xmlns:local="using:window_titlebar"
7+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
8+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
9+
mc:Ignorable="d"
10+
Title="Basic WinUI 3 Window title bar sample">
11+
12+
<Grid x:Name="rootElement" RowDefinitions="100, *, 100, *">
13+
14+
<StackPanel x:Name="customTitleBarPanel" Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Stretch" VerticalAlignment="Top" Visibility="Collapsed">
15+
<Image Source="Images/windowIcon.gif" />
16+
<TextBlock VerticalAlignment="Center" Text="Full customization of title bar"/>
17+
</StackPanel>
18+
19+
<StackPanel x:Name="buttonPanel" Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center">
20+
<Button x:Name="basicButton" Click="basicButton_Click" Margin="25">Set the Window title and icon</Button>
21+
<Button x:Name="customButton" Click="customButton_Click" Margin="25">Customize the window title bar</Button>
22+
</StackPanel>
23+
24+
</Grid>
25+
</Window>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Runtime.InteropServices.WindowsRuntime;
6+
using Windows.Foundation;
7+
using Windows.Foundation.Collections;
8+
using Microsoft.UI.Xaml;
9+
using Microsoft.UI.Xaml.Controls;
10+
using Microsoft.UI.Xaml.Controls.Primitives;
11+
using Microsoft.UI.Xaml.Data;
12+
using Microsoft.UI.Xaml.Input;
13+
using Microsoft.UI.Xaml.Media;
14+
using Microsoft.UI.Xaml.Navigation;
15+
using System.Runtime.InteropServices;
16+
17+
// To learn more about WinUI, the WinUI project structure,
18+
// and more about our project templates, see: http://aka.ms/winui-project-info.
19+
20+
namespace window_titlebar
21+
{
22+
/// <summary>
23+
/// An empty window that can be used on its own or navigated to within a Frame.
24+
/// </summary>
25+
public sealed partial class MainWindow : Window
26+
{
27+
public MainWindow()
28+
{
29+
this.InitializeComponent();
30+
}
31+
32+
// <basicButton_Click>
33+
private void basicButton_Click(object sender, RoutedEventArgs e)
34+
{
35+
// Ensure the custom title bar content is not displayed.
36+
customTitleBarPanel.Visibility = Visibility.Collapsed;
37+
38+
// Disable custom title bar content.
39+
ExtendsContentIntoTitleBar = false;
40+
41+
//Get the Window's HWND
42+
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
43+
44+
var hIcon = Windows.Win32.PInvoke.LoadImage(
45+
null,
46+
"Images/windowIcon.ico",
47+
Windows.Win32.UI.WindowsAndMessaging.GDI_IMAGE_TYPE.IMAGE_ICON,
48+
20, 20,
49+
Windows.Win32.UI.WindowsAndMessaging.IMAGE_FLAGS.LR_LOADFROMFILE);
50+
51+
Windows.Win32.PInvoke.SendMessage(
52+
(Windows.Win32.Foundation.HWND)hwnd,
53+
Windows.Win32.PInvoke.WM_SETICON,
54+
(Windows.Win32.Foundation.WPARAM)0,
55+
(Windows.Win32.Foundation.LPARAM)hIcon.DangerousGetHandle());
56+
57+
Windows.Win32.PInvoke.SetWindowText((Windows.Win32.Foundation.HWND)hwnd, "Basic customization of title bar");
58+
}
59+
// </basicButton_Click>
60+
61+
// <customButton_Click>
62+
private void customButton_Click(object sender, RoutedEventArgs e)
63+
{
64+
customTitleBarPanel.Visibility = Visibility.Visible;
65+
66+
// Enable custom title bar content.
67+
ExtendsContentIntoTitleBar = true;
68+
// Set the content of the custom title bar.
69+
SetTitleBar(customTitleBarPanel);
70+
}
71+
// </customButton_Click>
72+
}
73+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
LoadImage
2+
SendMessage
3+
SetWindowText
4+
WM_SETICON

0 commit comments

Comments
 (0)