|
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