Skip to content

Commit

Permalink
Subclass WinUI Window to hook native win32 events (#1687)
Browse files Browse the repository at this point in the history
* Subclass WinUI Window to hook native win32 events

* Make native message id's consts public

* Make native message id consts internal
  • Loading branch information
Redth authored Jul 20, 2021
1 parent c359193 commit b80a399
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/Core/src/LifecycleEvents/Windows/WindowsLifecycle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 13 additions & 0 deletions src/Core/src/Platform/Windows/IWindowNative.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
}
47 changes: 46 additions & 1 deletion src/Core/src/Platform/Windows/MauiWinUIWindow.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
using Microsoft.Maui.LifecycleEvents;
using System;
using System.Runtime.InteropServices;
using Microsoft.Maui.LifecycleEvents;
using WinRT;

namespace Microsoft.Maui
{
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<WindowsLifecycle.OnNativeMessage>(m => m(this, args));
}

protected virtual void OnActivated(object sender, UI.Xaml.WindowActivatedEventArgs args)
Expand All @@ -25,5 +36,39 @@ protected virtual void OnVisibilityChanged(object sender, UI.Xaml.WindowVisibili
{
MauiWinUIApplication.Current.Services?.InvokeLifecycleEvents<WindowsLifecycle.OnVisibilityChanged>(del => del(this, args));
}

public event EventHandler<WindowsNativeMessageEventArgs> 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<IWindowNative>().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
}
}
20 changes: 20 additions & 0 deletions src/Core/src/Platform/Windows/WindowsNativeMessageEventArgs.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
}
10 changes: 10 additions & 0 deletions src/Core/src/Platform/Windows/WindowsNativeMessageIds.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Microsoft.Maui
{
internal 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;
}
}

0 comments on commit b80a399

Please sign in to comment.