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
相关产品推荐
相关产品推荐

