I am writing a WPF application that will put an icon in the system tray and, as an exercise, I want to do this without depending on System.Windows.Forms
and using its NotifyIcon
or NativeWindow
classes.
This is fairly easy - Shell_NotifyIcon
isn't hard to call from C# - and, indeed, I have succeeded in my task.
As part of this effort, I have had to create a window handle for the sole purpose of receiving messages from the system-tray. I create the native window as follows:
// Create a 'Native' window
_hwndSource = new HwndSource(0, 0, 0, 0, 0, 0, 0, null, parentHandle);
_hwndSource.AddHook(WndProc);
The message loop is hooked in AddHook()
and messages are processed in a function that looks like this:
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Handle windows messages in this...
}
And, finally, when it comes time to destroy the thing, I close the window by posting it a WM_CLOSE
message and disposing the HwndSource
.
if (null != _hwndSource)
{
UnsafeNativeMethods.PostMessage(_hwndSource.Handle, WindowMessage.WM_CLOSE, 0, 0);
_hwndSource.Dispose();
_hwndSource = null;
}
My question is this: the first three parameters to the constructor of HwndSource
are the class style, style and extended style of the native Win32 window, respectively. For a non-visible window that will only be used as a target for window-messages, what should they be?
My defaults of zero, zero and ... er.. zero do work but I have used Spy++ to examine what Windows.Forms.NotifyIcon
does and it seems that the NativeWindow
it creates have the following:
Class Style: <zero>
Styles: WS_CAPTION, WS_CLIPSIBLINGS,
WS_OVERLAPPED
Extended Styles: WS_EX_LEFT, WS_EX_LTRREADING,
WS_EX_RIGHTSCROLLBAR, WS_EX_WINDOWEDGE
Are any of those important for a non-visible window? (I think not.)
Windows style flags date from 1986, back when Windows v1.0 was released. There have been lots of appcompat hacks in the past 29 years and 10 major versions, Windows silently overrides style flags when the app specifies wonky ones. Nothing terribly wonky about this however, note that the value of the WS_OVERLAPPED
style flag is 0. Which asks for a plain window, you automatically get the appropriate style flags for such a window.
Your HwndSource
window has the exact same style flags, maybe you haven't found the correct one back in Spy++. So you don't have a problem. And no, they don't matter when the window never becomes visible.
Note a bug in your code, the WM_CLOSE
message you post is never actually processed since you destroy the window right after calling PostMessage()
. Just delete it, there is no point in asking the window nicely, it isn't going to object. You do however have to call Shell_NotifyIcon()
with NIM_DELETE
to delete the tray icon. Failure to do so leaves a "ghost" icon that only disappears when you move the mouse over it.
And do note that NotifyIcon
is not as trivial as you assume it is, it has a non-obvious bug workaround that you are likely to overlook. You'll notice when the context menu refuses to close.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With