From 2272766692e3d0c02b11df41fcd590bda2941d2a Mon Sep 17 00:00:00 2001 From: Jonathan Dick Date: Thu, 15 Jul 2021 12:27:31 -0400 Subject: [PATCH 1/3] Subclass WinUI Window to hook native win32 events --- .../Windows/WindowsLifecycle.cs | 1 + .../src/Platform/Windows/IWindowNative.cs | 13 +++++ .../src/Platform/Windows/MauiWinUIWindow.cs | 47 ++++++++++++++++++- .../Windows/WindowsNativeMessageEventArgs.cs | 20 ++++++++ .../Windows/WindowsNativeMessageIds.cs | 10 ++++ 5 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/Core/src/Platform/Windows/IWindowNative.cs create mode 100644 src/Core/src/Platform/Windows/WindowsNativeMessageEventArgs.cs create mode 100644 src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs diff --git a/src/Core/src/LifecycleEvents/Windows/WindowsLifecycle.cs b/src/Core/src/LifecycleEvents/Windows/WindowsLifecycle.cs index dafe28714dfa..71f44e9e4260 100644 --- a/src/Core/src/LifecycleEvents/Windows/WindowsLifecycle.cs +++ b/src/Core/src/LifecycleEvents/Windows/WindowsLifecycle.cs @@ -7,6 +7,7 @@ public static class WindowsLifecycle public delegate void OnLaunched(UI.Xaml.Application application, UI.Xaml.LaunchActivatedEventArgs args); public delegate void OnLaunching(UI.Xaml.Application application, UI.Xaml.LaunchActivatedEventArgs args); public delegate void OnVisibilityChanged(UI.Xaml.Window window, UI.Xaml.WindowVisibilityChangedEventArgs args); + public delegate void OnNativeMessage(UI.Xaml.Window window, WindowsNativeMessageEventArgs args); // Internal events internal delegate void OnMauiContextCreated(IMauiContext mauiContext); diff --git a/src/Core/src/Platform/Windows/IWindowNative.cs b/src/Core/src/Platform/Windows/IWindowNative.cs new file mode 100644 index 000000000000..af8e9f1a5c1f --- /dev/null +++ b/src/Core/src/Platform/Windows/IWindowNative.cs @@ -0,0 +1,13 @@ +using System; +using System.Runtime.InteropServices; + +namespace Microsoft.Maui +{ + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("EECDBF0E-BAE9-4CB6-A68E-9598E1CB57BB")] + internal interface IWindowNative + { + IntPtr WindowHandle { get; } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/MauiWinUIWindow.cs b/src/Core/src/Platform/Windows/MauiWinUIWindow.cs index 67c8aecdf7b2..6b44dba1db86 100644 --- a/src/Core/src/Platform/Windows/MauiWinUIWindow.cs +++ b/src/Core/src/Platform/Windows/MauiWinUIWindow.cs @@ -1,4 +1,7 @@ -using Microsoft.Maui.LifecycleEvents; +using System; +using System.Runtime.InteropServices; +using Microsoft.Maui.LifecycleEvents; +using WinRT; namespace Microsoft.Maui { @@ -6,9 +9,17 @@ public class MauiWinUIWindow : UI.Xaml.Window { public MauiWinUIWindow() { + NativeMessage += OnNativeMessage; Activated += OnActivated; Closed += OnClosed; VisibilityChanged += OnVisibilityChanged; + + SubClassingWin32(); + } + + protected virtual void OnNativeMessage(object? sender, WindowsNativeMessageEventArgs args) + { + MauiWinUIApplication.Current.Services?.InvokeLifecycleEvents(m => m(this, args)); } protected virtual void OnActivated(object sender, UI.Xaml.WindowActivatedEventArgs args) @@ -25,5 +36,39 @@ protected virtual void OnVisibilityChanged(object sender, UI.Xaml.WindowVisibili { MauiWinUIApplication.Current.Services?.InvokeLifecycleEvents(del => del(this, args)); } + + public event EventHandler NativeMessage; + + #region Native Window + IntPtr _hwnd = IntPtr.Zero; + delegate IntPtr WinProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); + WinProc? newWndProc = null; + IntPtr oldWndProc = IntPtr.Zero; + + [DllImport("user32")] + static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, WinProc newProc); + [DllImport("user32.dll")] + static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); + + void SubClassingWin32() + { + //Get the Window's HWND + _hwnd = this.As().WindowHandle; + if (_hwnd == IntPtr.Zero) + throw new NullReferenceException("The Window Handle is null."); + + newWndProc = new WinProc(NewWindowProc); + oldWndProc = SetWindowLongPtr(_hwnd, /* GWL_WNDPROC */ -4, newWndProc); + } + + IntPtr NewWindowProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam) + { + var args = new WindowsNativeMessageEventArgs(hWnd, msg, wParam, lParam); + + NativeMessage?.Invoke(this, args); + + return CallWindowProc(oldWndProc, hWnd, msg, wParam, lParam); + } + #endregion } } \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/WindowsNativeMessageEventArgs.cs b/src/Core/src/Platform/Windows/WindowsNativeMessageEventArgs.cs new file mode 100644 index 000000000000..39aef1869b9b --- /dev/null +++ b/src/Core/src/Platform/Windows/WindowsNativeMessageEventArgs.cs @@ -0,0 +1,20 @@ +using System; + +namespace Microsoft.Maui +{ + public class WindowsNativeMessageEventArgs : EventArgs + { + public WindowsNativeMessageEventArgs(IntPtr hwnd, uint messageId, IntPtr wParam, IntPtr lParam) + { + Hwnd = hwnd; + MessageId = messageId; + WParam = wParam; + LParam = lParam; + } + + public IntPtr Hwnd { get; private set; } + public uint MessageId { get; private set; } + public IntPtr WParam { get; private set; } + public IntPtr LParam { get; private set; } + } +} \ No newline at end of file diff --git a/src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs b/src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs new file mode 100644 index 000000000000..dc88a0180395 --- /dev/null +++ b/src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs @@ -0,0 +1,10 @@ +namespace Microsoft.Maui +{ + static class WindowsNativeMessageIds + { + public const int WM_DPICHANGED = 0x02E0; + public const int WM_DISPLAYCHANGE = 0x007E; + public const int WM_SETTINGCHANGE = 0x001A; + public const int WM_THEMECHANGE = 0x031A; + } +} \ No newline at end of file From 662be6983c17f9ce9d42134191867d23bf1104eb Mon Sep 17 00:00:00 2001 From: Jonathan Dick Date: Thu, 15 Jul 2021 12:32:46 -0400 Subject: [PATCH 2/3] Make native message id's consts public --- src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs b/src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs index dc88a0180395..d14a28369720 100644 --- a/src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs +++ b/src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs @@ -1,6 +1,6 @@ namespace Microsoft.Maui { - static class WindowsNativeMessageIds + public static class WindowsNativeMessageIds { public const int WM_DPICHANGED = 0x02E0; public const int WM_DISPLAYCHANGE = 0x007E; From 0150b9ffdb507a63bf1505ae198e50d7acbf4f3e Mon Sep 17 00:00:00 2001 From: Jonathan Dick Date: Tue, 20 Jul 2021 16:16:04 -0400 Subject: [PATCH 3/3] Make native message id consts internal --- src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs b/src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs index d14a28369720..7cfed5168d3c 100644 --- a/src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs +++ b/src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs @@ -1,6 +1,6 @@ namespace Microsoft.Maui { - public static class WindowsNativeMessageIds + internal static class WindowsNativeMessageIds { public const int WM_DPICHANGED = 0x02E0; public const int WM_DISPLAYCHANGE = 0x007E;