Skip to content

Commit 70c489e

Browse files
authored
Merge pull request #1 from Lightczx/feat/winui3-themelistener
#445
2 parents f7628c0 + 9ad6992 commit 70c489e

File tree

3 files changed

+54
-58
lines changed

3 files changed

+54
-58
lines changed

components/Helpers/src/MultiTarget.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
-->
77
<MultiTarget>uwp;wasdk;wpf;wasm;linuxgtk;macos;ios;android;</MultiTarget>
88
</PropertyGroup>
9-
</Project>
9+
</Project>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"$schema": "https://aka.ms/CsWin32.schema.json",
3+
"allowMarshaling": false,
4+
"comInterop": {
5+
"preserveSigMethods": [
6+
"*"
7+
]
8+
}
9+
}

components/Helpers/src/ThemeListenerHelperWindow.cs

Lines changed: 44 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,90 +3,77 @@
33
// See the LICENSE file in the project root for more information.
44

55
using Microsoft.Win32;
6-
using System;
7-
using System.Collections.Generic;
8-
using System.Linq;
6+
using System.Runtime.CompilerServices;
97
using System.Runtime.InteropServices;
10-
using System.Text;
11-
using System.Threading.Tasks;
128
using Windows.Win32;
9+
using Windows.Win32.Foundation;
10+
using Windows.Win32.UI.WindowsAndMessaging;
1311

1412
namespace CommunityToolkit.WinUI.HelpersRns;
1513

1614
#if WINAPPSDK
17-
1815
internal class ThemeListenerHelperWindow
1916
{
2017
public delegate void ThemeChangedHandler(ApplicationTheme theme);
2118

2219
public static ThemeListenerHelperWindow Instance = new();
23-
private static string s_className = "ThemeListenerHelperWindow";
24-
private IntPtr m_hwnd;
20+
2521
public event ThemeChangedHandler? ThemeChanged;
26-
delegate Windows.Win32.Foundation.LRESULT WndProc(Windows.Win32.Foundation.HWND hWnd, uint msg, Windows.Win32.Foundation.WPARAM wParam, Windows.Win32.Foundation.LPARAM lParam);
27-
private WndProc m_wnd_proc_delegate;
28-
private void registerClass()
22+
23+
private static string s_className = "ThemeListenerHelperWindow";
24+
25+
private HWND m_hwnd;
26+
27+
private ThemeListenerHelperWindow()
2928
{
30-
unsafe
29+
s_className = "ThemeListenerHelperWindow";
30+
RegisterClass();
31+
m_hwnd = CreateWindow();
32+
}
33+
34+
private static unsafe void RegisterClass()
35+
{
36+
WNDCLASSEXW wcx = default;
37+
wcx.cbSize = (uint)sizeof(WNDCLASSEXW);
38+
fixed (char* pClassName = s_className)
3139
{
32-
var wcx = new Windows.Win32.UI.WindowsAndMessaging.WNDCLASSEXW();
33-
wcx.cbSize = (uint)Marshal.SizeOf(wcx);
34-
fixed (char* pClassName = s_className)
35-
{
36-
wcx.lpszClassName = new Windows.Win32.Foundation.PCWSTR(pClassName);
37-
}
38-
wcx.lpfnWndProc = wndProc;
39-
if (PInvoke.RegisterClassEx(in wcx) == 0)
40+
wcx.lpszClassName = pClassName;
41+
wcx.lpfnWndProc = &WndProc;
42+
if (PInvoke.RegisterClassEx(in wcx) is 0)
4043
{
41-
Debug.WriteLine(new Win32Exception(Marshal.GetLastWin32Error()).Message);
44+
Marshal.ThrowExceptionForHR(Marshal.GetLastPInvokeError());
4245
}
4346
}
44-
4547
}
4648

47-
static Windows.Win32.Foundation.LRESULT wndProc(Windows.Win32.Foundation.HWND hWnd, uint msg, Windows.Win32.Foundation.WPARAM wParam, Windows.Win32.Foundation.LPARAM lParam)
49+
private static unsafe HWND CreateWindow()
4850
{
49-
switch (msg)
51+
HWND hwnd = PInvoke.CreateWindowEx(0, s_className, string.Empty, 0, 0, 0, 0, 0, default, null, null, null);
52+
if (hwnd == HWND.Null)
5053
{
51-
case PInvoke.WM_SETTINGCHANGE:
52-
var value = Registry.GetValue(
53-
"""HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize""",
54-
"AppsUseLightTheme",
55-
true
56-
);
57-
if (value != null)
58-
{
59-
Instance.ThemeChanged?.Invoke((int)value == 1 ? ApplicationTheme.Light : ApplicationTheme.Dark);
60-
}
61-
break;
54+
Marshal.ThrowExceptionForHR(Marshal.GetLastPInvokeError());
6255
}
63-
return PInvoke.DefWindowProc(hWnd, msg, wParam, lParam);
56+
return hwnd;
6457
}
6558

66-
unsafe private static IntPtr createWindow()
59+
[UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])]
60+
private static LRESULT WndProc(HWND hWnd, uint msg, WPARAM wParam, LPARAM lParam)
6761
{
68-
var hwnd = PInvoke.CreateWindowEx(
69-
0,
70-
s_className,
71-
"",
72-
0,
73-
0, 0, 0, 0,
74-
new Windows.Win32.Foundation.HWND(),
75-
null,
76-
null,
77-
null);
78-
if (hwnd == IntPtr.Zero)
62+
if (msg is PInvoke.WM_SETTINGCHANGE)
7963
{
80-
Debug.WriteLine(new Win32Exception(Marshal.GetLastWin32Error()).Message);
64+
// REG_DWORD
65+
object? value = Registry.GetValue(
66+
@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize",
67+
"AppsUseLightTheme",
68+
true);
69+
70+
if (value is int dword)
71+
{
72+
Instance.ThemeChanged?.Invoke(dword is 1 ? ApplicationTheme.Light : ApplicationTheme.Dark);
73+
}
8174
}
82-
return hwnd;
83-
}
84-
private ThemeListenerHelperWindow()
85-
{
86-
m_wnd_proc_delegate = wndProc;
87-
s_className = "ThemeListenerHelperWindow";
88-
registerClass();
89-
m_hwnd = createWindow();
75+
76+
return PInvoke.DefWindowProc(hWnd, msg, wParam, lParam);
9077
}
9178
}
9279
#endif

0 commit comments

Comments
 (0)