I got a solution here on Stack Overflow for maintaining my windows aspect ratio when the user resizes and it works great. I'm trying to use the wndproc function from that to detect a WM_MOUSEMOVE message when inside the client area of my main window. Not sure why my modification does not catch WM_MOUSEMOVE events when I move the mouse around my window.
I added this to the wndproc function ...
const int WM_MOUSEMOVE = 0x0200;
if (msg == WM_MOUSEMOVE)
{
return null; // never reaches this
}
resulting MainWindow.xaml.cs ...
namespace MainWindowTest
{
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
///
public sealed partial class MainWindow : Window
{
private readonly WindowProcedureHook _hook;
public MainWindow()
{
this.InitializeComponent();
// hook the window procedure
_hook = new WindowProcedureHook(this, WndProc);
//ExtendsContentIntoTitleBar = true;
GetAppWindowAndPresenter();
_presenter.IsMaximizable = true;
_presenter.IsMinimizable = true;
_apw.Title = "Title";
//_apw.TitleBar.IconShowOptions = IconShowOptions.HideIconAndSystemMenu;
}
public void GetAppWindowAndPresenter()
{
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
WindowId myWndId = Win32Interop.GetWindowIdFromWindow(hWnd);
_apw = AppWindow.GetFromWindowId(myWndId);
_presenter = _apw.Presenter as OverlappedPresenter;
}
private AppWindow _apw;
private OverlappedPresenter _presenter;
private void Window_SizeChanged(object sender, WindowSizeChangedEventArgs args)
{
}
private IntPtr? WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam)
{
// handle the WM_SIZING message
const int WM_SIZING = 0x0214;
**const int WM_MOUSEMOVE = 0x0200;
if (msg == WM_MOUSEMOVE)
{
return null; // never reaches this breakpoint
}**
if (msg == WM_SIZING)
{
// get sizing rect
var rc = Marshal.PtrToStructure<RECT>(lParam);
// if coming from left/right only, we adjust height
const int WMSZ_LEFT = 1;
const int WMSZ_RIGHT = 2;
if (wParam.ToInt64() == WMSZ_LEFT || wParam.ToInt64() == WMSZ_RIGHT)
{
rc.height = rc.width * 9 / 16;
}
else
{
rc.width = rc.height * 16 / 9;
}
// put it back, say we handled it
Marshal.StructureToPtr(rc, lParam, false);
return new IntPtr(1);
}
return null; // unhandled, let Windows do the job
}
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
public int width { get => right - left; set => right = left + value; }
public int height { get => bottom - top; set => bottom = top + value; }
}
}
// a utility class to hook window procedure and handle messages, or not
public sealed class WindowProcedureHook
{
private readonly IntPtr _prevProc;
private readonly WNDPROC _wndProc;
private readonly Func<IntPtr, int, IntPtr, IntPtr, IntPtr?> _callback;
public WindowProcedureHook(Window window, Func<IntPtr, int, IntPtr, IntPtr, IntPtr?> callback)
{
ArgumentNullException.ThrowIfNull(window);
ArgumentNullException.ThrowIfNull(callback);
_wndProc = WndProc;
var handle = WinRT.Interop.WindowNative.GetWindowHandle(window);
_callback = callback;
const int GWLP_WNDPROC = -4;
_prevProc = GetWindowLong(handle, GWLP_WNDPROC);
SetWindowLong(handle, GWLP_WNDPROC, Marshal.GetFunctionPointerForDelegate(_wndProc));
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam) => _callback(hwnd, msg, wParam, lParam) ?? CallWindowProc(_prevProc, hwnd, msg, wParam, lParam);
private delegate IntPtr WNDPROC(IntPtr handle, int msg, IntPtr wParam, IntPtr lParam);
private static IntPtr GetWindowLong(IntPtr handle, int index) =>
IntPtr.Size == 8 ? GetWindowLongPtrW(handle, index) : (IntPtr)GetWindowLongW(handle, index);
private static IntPtr SetWindowLong(IntPtr handle, int index, IntPtr newLong) =>
IntPtr.Size == 8 ? SetWindowLongPtrW(handle, index, newLong) : (IntPtr)SetWindowLongW(handle, index, newLong.ToInt32());
[DllImport("user32")]
private static extern IntPtr CallWindowProc(IntPtr prevWndProc, IntPtr handle, int msg, IntPtr wParam, IntPtr lParam);
// note: WinUI3 windows are unicode, so we only use the "W" versions
[DllImport("user32")]
private static extern IntPtr GetWindowLongPtrW(IntPtr hWnd, int nIndex);
[DllImport("user32")]
private static extern int GetWindowLongW(IntPtr hWnd, int nIndex);
[DllImport("user32")]
private static extern int SetWindowLongW(IntPtr hWnd, int nIndexn, int dwNewLong);
[DllImport("user32")]
private static extern IntPtr SetWindowLongPtrW(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
}
}
It turns out that Window.Content covers the window which results the window doesn't receive mouse messages. Use UIElement.Pointer
* events instead. see https://github.com/castorix/WinUI3_Transparent/blob/86f5fff5cde4784422c6551b030c2b147e4b11f3/MainWindow.xaml.cs#L233 for an example.