WPF Window 仅消息循环句柄
WPF Window Handle for Message Loop Only
我正在编写一个 WPF 应用程序,它将在系统托盘中放置一个图标,作为练习,我想在不依赖 System.Windows.Forms
并使用它的 NotifyIcon
或 NativeWindow
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。当上下文菜单拒绝关闭时,您会注意到。
我正在编写一个 WPF 应用程序,它将在系统托盘中放置一个图标,作为练习,我想在不依赖 System.Windows.Forms
并使用它的 NotifyIcon
或 NativeWindow
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
.
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。当上下文菜单拒绝关闭时,您会注意到。