You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinUI3主窗口WM_MOUSEMOVE事件捕获失败问题排查

无法捕获WM_MOUSEMOVE消息的原因及解决方法

核心原因

  • WinUI3消息路由机制限制:WinUI3基于XAML框架,鼠标移动这类输入消息会被XAML输入系统优先拦截,转换为PointerMoved等XAML原生事件,不会传递到你Hook的顶层窗口过程。
  • 窗口层级结构问题:你Hook的是WinUI3窗口的顶层HWND,但客户区的鼠标消息实际发送给顶层窗口内部的XAML内容宿主子窗口,你的顶层窗口过程根本接收不到这些消息。

解决方案

方案一:使用XAML原生事件(推荐)

WinUI3框架提供了原生输入事件,完全可以替代Win32消息的方式,代码更简洁且符合框架设计:

public sealed partial class MainWindow : Window
{
    private readonly WindowProcedureHook _hook;

    public MainWindow()
    {
        this.InitializeComponent();
        _hook = new WindowProcedureHook(this, WndProc);
        // 订阅PointerMoved事件
        this.PointerMoved += MainWindow_PointerMoved;
        
        GetAppWindowAndPresenter();
        _presenter.IsMaximizable = true;
        _presenter.IsMinimizable = true;
        _apw.Title = "Title";
    }

    private void MainWindow_PointerMoved(object sender, PointerRoutedEventArgs e)
    {
        // 获取鼠标在窗口内的坐标
        var point = e.GetCurrentPoint(this).Position;
        // 这里添加你的处理逻辑
        System.Diagnostics.Debug.WriteLine($"鼠标位置:X={point.X}, Y={point.Y}");
    }

    // 其他原有代码...
}

方案二:Hook XAML内容宿主窗口(不推荐)

如果必须使用Win32消息机制,需要找到顶层窗口内部的XAML内容宿主子窗口并Hook它的过程,但这种方法依赖WinUI3内部实现,可能随版本变更失效:

// 在MainWindow构造函数中添加
var mainHwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
// 查找XAML内容宿主窗口
var contentHwnd = FindWindowEx(mainHwnd, IntPtr.Zero, "Windows.UI.Core.CoreWindow", null);
if (contentHwnd != IntPtr.Zero)
{
    // 为子窗口创建Hook,需要修改WindowProcedureHook类支持传入自定义HWND
    var contentHook = new WindowProcedureHook(contentHwnd, ContentWndProc);
}

// 子窗口的消息处理函数
private IntPtr? ContentWndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam)
{
    const int WM_MOUSEMOVE = 0x0200;
    if (msg == WM_MOUSEMOVE)
    {
        // 这里可以捕获到鼠标移动消息
        System.Diagnostics.Debug.WriteLine("捕获到WM_MOUSEMOVE");
        return null;
    }
    return null;
}

// 需要在WindowProcedureHook中添加支持自定义HWND的构造函数
public WindowProcedureHook(IntPtr hwnd, Func<IntPtr, int, IntPtr, IntPtr, IntPtr?> callback)
{
    ArgumentNullException.ThrowIfNull(callback);
    _wndProc = WndProc;
    _callback = callback;

    const int GWLP_WNDPROC = -4;
    _prevProc = GetWindowLong(hwnd, GWLP_WNDPROC);
    SetWindowLong(hwnd, GWLP_WNDPROC, Marshal.GetFunctionPointerForDelegate(_wndProc));
}

// 补充FindWindowEx的DllImport
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

内容的提问来源于stack exchange,提问作者user1094779

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 07:43:53