WPF Window 仅消息循环句柄

WPF Window Handle for Message Loop Only

我正在编写一个 WPF 应用程序,它将在系统托盘中放置一个图标,作为练习,我想在不依赖 System.Windows.Forms 并使用它的 NotifyIconNativeWindow classes.

这相当简单 - Shell_NotifyIcon 从 C# 调用并不难 - 事实上,我已经成功完成任务。

作为这项工作的一部分,我不得不创建一个 window 句柄,其唯一目的是从系统托盘接收消息。我创建原生 window 如下:

// Create a 'Native' window
_hwndSource = new HwndSource(0, 0, 0, 0, 0, 0, 0, null, parentHandle);
_hwndSource.AddHook(WndProc);

消息循环挂在 AddHook() 中,消息在函数中处理,如下所示:

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    // Handle windows messages in this...
}

最后,当需要销毁它时,我通过发布 WM_CLOSE 消息并处理 HwndSource.

来关闭 window
if (null != _hwndSource)
{
    UnsafeNativeMethods.PostMessage(_hwndSource.Handle, WindowMessage.WM_CLOSE, 0, 0);
    _hwndSource.Dispose();
    _hwndSource = null;
}

我的问题是:HwndSource的构造函数的前三个参数分别是class原生Win32的样式、样式和扩展样式window , 分别。对于仅用作 window 消息目标的不可见 window,它们应该是什么?

我的零、零和……呃..零的默认值确实有效,但我使用 Spy++ 来检查 Windows.Forms.NotifyIcon 的作用,它创建的 NativeWindow 似乎具有以下内容:

Class Style:     <zero>
Styles:          WS_CAPTION, WS_CLIPSIBLINGS,
                 WS_OVERLAPPED
Extended Styles: WS_EX_LEFT, WS_EX_LTRREADING,
                 WS_EX_RIGHTSCROLLBAR, WS_EX_WINDOWEDGE

这些对于不可见的 window 是否重要? (我认为不是。)

Windows 样式标志可追溯到 1986 年,当时 Windows v1.0 已发布。在过去的 29 年和 10 个主要版本中,有 很多 次 appcompat 黑客攻击,Windows 在应用指定不稳定的样式标志时静默覆盖样式标志。然而,这并没有什么特别奇怪的,请注意 WS_OVERLAPPED 样式标志的值为 0。它要求一个普通的 window,您会自动获得适合这样一个 window 的样式标志。

您的 HwndSource window 具有完全相同的样式标志,也许您还没有在 Spy++ 中找到正确的标志。所以你没有问题。不,当 window 永远不可见时,它们并不重要。

请注意您的代码中的一个错误,您 post 的 WM_CLOSE 消息从未被实际处理,因为您在调用 PostMessage() 后立即销毁了 window。删掉就好了,跟window好声好气也没用,它不会反对的。但是,您必须使用 NIM_DELETE 调用 Shell_NotifyIcon() 才能删除托盘图标。如果不这样做,会留下一个 "ghost" 图标,只有当您将鼠标移到它上面时该图标才会消失。

请注意,NotifyIcon 并不像您想象的那样微不足道,它有一个您可能会忽略的 non-obvious bug workaround。当上下文菜单拒绝关闭时,您会注意到。