|
3 | 3 | // See the LICENSE file in the project root for more information.
|
4 | 4 |
|
5 | 5 | using Microsoft.Win32;
|
6 |
| -using System; |
7 |
| -using System.Collections.Generic; |
8 |
| -using System.Linq; |
| 6 | +using System.Runtime.CompilerServices; |
9 | 7 | using System.Runtime.InteropServices;
|
10 |
| -using System.Text; |
11 |
| -using System.Threading.Tasks; |
12 | 8 | using Windows.Win32;
|
| 9 | +using Windows.Win32.Foundation; |
| 10 | +using Windows.Win32.UI.WindowsAndMessaging; |
13 | 11 |
|
14 | 12 | namespace CommunityToolkit.WinUI.HelpersRns;
|
15 | 13 |
|
16 | 14 | #if WINAPPSDK
|
17 |
| - |
18 | 15 | internal class ThemeListenerHelperWindow
|
19 | 16 | {
|
20 | 17 | public delegate void ThemeChangedHandler(ApplicationTheme theme);
|
21 | 18 |
|
22 | 19 | public static ThemeListenerHelperWindow Instance = new();
|
23 |
| - private static string s_className = "ThemeListenerHelperWindow"; |
24 |
| - private IntPtr m_hwnd; |
| 20 | + |
25 | 21 | 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() |
29 | 28 | {
|
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) |
31 | 39 | {
|
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) |
40 | 43 | {
|
41 |
| - Debug.WriteLine(new Win32Exception(Marshal.GetLastWin32Error()).Message); |
| 44 | + Marshal.ThrowExceptionForHR(Marshal.GetLastPInvokeError()); |
42 | 45 | }
|
43 | 46 | }
|
44 |
| - |
45 | 47 | }
|
46 | 48 |
|
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() |
48 | 50 | {
|
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) |
50 | 53 | {
|
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()); |
62 | 55 | }
|
63 |
| - return PInvoke.DefWindowProc(hWnd, msg, wParam, lParam); |
| 56 | + return hwnd; |
64 | 57 | }
|
65 | 58 |
|
66 |
| - unsafe private static IntPtr createWindow() |
| 59 | + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)])] |
| 60 | + private static LRESULT WndProc(HWND hWnd, uint msg, WPARAM wParam, LPARAM lParam) |
67 | 61 | {
|
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) |
79 | 63 | {
|
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 | + } |
81 | 74 | }
|
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); |
90 | 77 | }
|
91 | 78 | }
|
92 | 79 | #endif
|
0 commit comments