Under the "Remarks" section for the MSDN docs on TrackPopupMenuEx, it says:
To display a context menu for a notification icon, the current window
must be the foreground window before the application calls
TrackPopupMenu or TrackPopupMenuEx. Otherwise, the menu will not
disappear when the user clicks outside of the menu or the window that
created the menu (if it is visible). If the current window is a child
window, you must set the (top-level) parent window as the foreground
window.
So that could mean that when the ContextMenu
is visible, the window on the NotifyIcon
will be the foreground window. You can see from by looking at NotifyIcon.ShowContextMenu()
that it is indeed the case:
private void ShowContextMenu()
{
if (this.contextMenu != null || this.contextMenuStrip != null)
{
NativeMethods.POINT pOINT = new NativeMethods.POINT();
UnsafeNativeMethods.GetCursorPos(pOINT);
UnsafeNativeMethods.SetForegroundWindow(new HandleRef(this.window, this.window.Handle));
if (this.contextMenu != null)
{
this.contextMenu.OnPopup(EventArgs.Empty);
SafeNativeMethods.TrackPopupMenuEx(new HandleRef(this.contextMenu, this.contextMenu.Handle), 72, pOINT.x, pOINT.y, new HandleRef(this.window, this.window.Handle), null);
UnsafeNativeMethods.PostMessage(new HandleRef(this.window, this.window.Handle), 0, IntPtr.Zero, IntPtr.Zero);
return;
}
if (this.contextMenuStrip != null)
{
this.contextMenuStrip.ShowInTaskbar(pOINT.x, pOINT.y);
}
}
}
Using ILSpy I then noticed NotifyIcon
has a private member window
, which refers to a private class with base type NativeWindow
. Therefore, you can check like this:
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetForegroundWindow();
...
FieldInfo notifyIconNativeWindowInfo = typeof(NotifyIcon).GetField("window", BindingFlags.NonPublic | BindingFlags.Instance);
NativeWindow notifyIconNativeWindow = (NativeWindow)notifyIconNativeWindowInfo.GetValue(notifyIcon1);
bool visible = notifyIcon1.Handle == GetForegroundWindow();