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

WinUI3中FindWindow()始终返回0x0000000000000000问题求助

WinUI3 C# 跨进程消息通信问题:FindWindow 返回值始终为0

我用WinUI3 C#开发了发送端和接收端两个应用,发送端通过按钮点击调用FindWindow()和SendMessage(),接收端期望收到消息时显示通知,但目前FindWindow()返回值一直是0x0000000000000000,请问遗漏了哪些操作?

发送端代码

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

private const uint WM_USER = 0x0400; // 用户自定义消息范围
private const int WM_MY_MESSAGE = (int)(WM_USER + 1); // 自定义消息ID

private async void SendMessageButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
    try
    {
        // 查找接收端窗口句柄
        IntPtr hWnd = FindWindow(null, "com.receiver"); // 这里填的是应用命名空间,有误

        if (hWnd != IntPtr.Zero)
        {
            SendMessage(hWnd, (uint)WM_MY_MESSAGE, IntPtr.Zero, IntPtr.Zero);
            await ShowMessageDialog("消息已发送到接收端");
        }
        else
        {
            await ShowMessageDialog("未找到接收端窗口");
        }
    }
    catch (Exception ex)
    {
        await ShowMessageDialog("发生错误:" + ex.Message);
    }
}

接收端代码

private const int WM_MY_MESSAGE = 0x0400 + 1; // 自定义消息ID
public MainPage()
{
    this.InitializeComponent();
    RegisterWindowMessage();
}
private void RegisterWindowMessage()
{
    // 注册自定义窗口消息
    RegisterWindowMessage("WM_MY_MESSAGE");
}

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int RegisterWindowMessage(string lpString);

private void Dispatcher_AcceleratorKeyActivated(CoreDispatcher sender, AcceleratorKeyEventArgs args)
{
    // 错误的消息处理方式
    if (args.KeyStatus.RepeatCount == WM_MY_MESSAGE)
    {
        ShowNotification("收到发送端消息");
    }
}

private async void ShowNotification(string message)
{
    var dialog = new MessageDialog(message);
    await dialog.ShowAsync();
}

问题排查与修复方案

一、FindWindow 返回0的核心原因及修复

1. 窗口名称参数错误

FindWindow的第二个参数是窗口标题文本,不是应用的命名空间。WinUI3窗口默认标题是项目名称,你需要改成接收端窗口的实际标题:

  • 先在接收端设置明确的窗口标题:
    // 接收端MainWindow构造函数中
    this.Title = "MyReceiverWindow";
    
  • 发送端用正确标题查找:
    IntPtr hWnd = FindWindow(null, "MyReceiverWindow");
    
  • 或者通过WinUI3窗口类名"WinUI.Window"查找:
    IntPtr hWnd = FindWindow("WinUI.Window", "MyReceiverWindow");
    

2. 运行权限不匹配

如果两个应用一个以管理员权限运行,另一个以普通权限运行,FindWindow会无法找到窗口。确保两者运行权限一致。

3. 窗口未完成初始化

如果接收端窗口还没加载完成就调用FindWindow,会返回0。可以等接收端触发Loaded事件后再测试发送端。

4. MSIX打包应用的特殊情况

如果接收端是MSIX打包应用,窗口标题可能被系统修改(比如添加应用名称后缀),类名也可能有变化。可以用**Spy++**工具(Visual Studio工具集里可找到)查看接收端窗口的实际类名、标题和句柄。


二、接收端消息处理的错误修复

即使找到窗口,当前接收端代码也无法收到消息,需同步修复:

1. 错误的消息处理事件

Dispatcher_AcceleratorKeyActivated是处理键盘快捷键的事件,和窗口消息无关。WinUI3需要通过Hook窗口过程来处理自定义消息:

using System.Runtime.InteropServices;
using Microsoft.UI.Xaml;
using WinRT.Interop;

public sealed partial class MainWindow : Window
{
    private static int _wmMyMessage = RegisterWindowMessage("WM_MY_MESSAGE");
    private IntPtr _oldWndProc;

    public MainWindow()
    {
        this.InitializeComponent();
        this.Title = "MyReceiverWindow";
        HookWindowProc();
    }

    private void HookWindowProc()
    {
        // 获取窗口HWND
        IntPtr hWnd = WindowNative.GetWindowHandle(this);
        // 替换窗口过程
        _oldWndProc = SetWindowLongPtr(hWnd, GWLP_WNDPROC, Marshal.GetFunctionPointerForDelegate(new WndProcDelegate(WndProc)));
    }

    private delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);

    private IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam)
    {
        if (msg == (uint)_wmMyMessage)
        {
            ShowNotification("收到发送端消息");
            return IntPtr.Zero;
        }
        // 调用原窗口过程
        return CallWindowProc(_oldWndProc, hWnd, msg, wParam, lParam);
    }

    private async void ShowNotification(string message)
    {
        var dialog = new ContentDialog
        {
            Title = "通知",
            Content = message,
            CloseButtonText = "确定",
            XamlRoot = this.Content.XamlRoot
        };
        await dialog.ShowAsync();
    }

    // P/Invoke 声明
    private const int GWLP_WNDPROC = -4;
    [DllImport("user32.dll")]
    private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
    [DllImport("user32.dll")]
    private static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    public static extern int RegisterWindowMessage(string lpString);
}

2. 正确使用RegisterWindowMessage

跨进程自定义消息应该用RegisterWindowMessage返回的全局唯一ID,而不是固定的WM_USER+1,避免不同进程的消息ID冲突。发送端也需要同步修改:

// 发送端添加
private static int _wmMyMessage = RegisterWindowMessage("WM_MY_MESSAGE");

// 发送消息时使用这个ID
SendMessage(hWnd, (uint)_wmMyMessage, IntPtr.Zero, IntPtr.Zero);

内容的提问来源于stack exchange,提问作者Su Myat Kyaw

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 21:05:14