Last active
May 20, 2024 02:44
-
-
Save KOZ60/a62ff318ec3dbf128953af0be1c04a2d to your computer and use it in GitHub Desktop.
NotifyIcon Sample
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.ComponentModel; | |
using System.Drawing; | |
using System.Reflection; | |
using System.Runtime.InteropServices; | |
using System.Windows.Forms; | |
public partial class Form1 : Form | |
{ | |
private NotifyIcon notifyIcon; | |
public Form1() { | |
InitializeComponent(); | |
ControlBox = false; | |
ShowInTaskbar = false; | |
Text = "NotifyIcon Demo"; | |
InitializeNotifyIcon(); | |
} | |
private void InitializeNotifyIcon() { | |
notifyIcon = new NotifyIcon(); | |
notifyIcon.Icon = SystemIcons.Information; | |
notifyIcon.Text = "NotifyIcon Demo"; | |
notifyIcon.Visible = true; | |
notifyIcon.ContextMenu = CreateContextMenu(); | |
notifyIcon.MouseClick += NotifyIcon_MouseClick; | |
} | |
private ContextMenu CreateContextMenu() { | |
var exitMenuItem = new MenuItem("Exit"); | |
exitMenuItem.Click += (s, e) => { | |
Application.Exit(); | |
}; | |
var menu = new ContextMenu(); | |
menu.MenuItems.Add(exitMenuItem); | |
return menu; | |
} | |
protected override void SetVisibleCore(bool value) { | |
if (!IsHandleCreated) CreateHandle(); | |
// Hide form on startup (Load event is not fired) | |
base.SetVisibleCore(false); | |
} | |
private const int WM_ACTIVATEAPP = 0x001C; | |
protected override void WndProc(ref Message m) { | |
// Hide Form when disactivate | |
if (m.Msg == WM_ACTIVATEAPP && m.WParam == IntPtr.Zero) { | |
base.SetVisibleCore(false); | |
} | |
base.WndProc(ref m); | |
} | |
private void NotifyIcon_MouseClick(object sender, MouseEventArgs e) { | |
if (e.Button == MouseButtons.Left) { | |
Rectangle iconRectangle = GetIconRectangle(notifyIcon); | |
Screen screen = Screen.FromRectangle(iconRectangle); | |
Rectangle workingArea = screen.WorkingArea; | |
Rectangle dwmBounds = GetDwmRectangle(this); | |
Size offset = (Size)dwmBounds.Location - (Size)Location; | |
// It's difficult to display the taskbar anywhere other than at the bottom in Windows 11 | |
// so I'll leave it up to you. | |
switch (GetTaskBarPosision()) { | |
case TaskBarPosision.Left: | |
break; | |
case TaskBarPosision.Right: | |
break; | |
case TaskBarPosision.Top: | |
break; | |
case TaskBarPosision.Bottom: | |
Left = workingArea.Right - dwmBounds.Width - offset.Width; | |
Top = iconRectangle.Top - dwmBounds.Height + offset.Height; | |
break; | |
} | |
base.SetVisibleCore(true); // Show Form | |
Activate(); | |
} | |
} | |
private static Rectangle GetIconRectangle(NotifyIcon notifyIcon) { | |
var id = GetFieldValue<int>(notifyIcon, "id"); | |
var window = GetFieldValue<NativeWindow>(notifyIcon, "window"); | |
var identifier = new NOTIFYICONIDENTIFIER { | |
cbSize = Marshal.SizeOf(typeof(NOTIFYICONIDENTIFIER)), | |
hWnd = window.Handle, | |
uID = id, | |
guidItem = Guid.Empty | |
}; | |
Shell_NotifyIconGetRect(ref identifier, out RECT rc); | |
return rc.Rectangle; | |
} | |
private static TValue GetFieldValue<TValue>(object target, string fieldName) { | |
var fi = target.GetType().GetField(fieldName, | |
BindingFlags.NonPublic | BindingFlags.Instance); | |
return (TValue)fi.GetValue(target); | |
} | |
public static Rectangle GetDwmRectangle(Form form) { | |
IntPtr hwnd = form.Handle; | |
int hResult; | |
// non-client rendering is enabled? | |
hResult = DwmGetWindowAttribute(hwnd, | |
DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_ENABLED, out bool enablled, | |
Marshal.SizeOf(typeof(bool))); | |
if (hResult != 0) throw new Win32Exception(); | |
if (enablled) { | |
// Retrieves the extended frame bounds rectangle in screen space. | |
hResult = DwmGetWindowAttribute(hwnd, | |
DWMWINDOWATTRIBUTE.DWMWA_EXTENDED_FRAME_BOUNDS, out RECT rc, | |
Marshal.SizeOf(typeof(RECT))); | |
if (hResult != 0) throw new Win32Exception(); | |
return rc.Rectangle; | |
} else { | |
return form.Bounds; | |
} | |
} | |
[DllImport("dwmapi.dll", SetLastError = true)] | |
private static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out RECT rect, int cbAttribute); | |
[DllImport("dwmapi.dll", SetLastError = true)] | |
private static extern int DwmGetWindowAttribute(IntPtr hWnd, DWMWINDOWATTRIBUTE dwAttribute, out bool enabled, int cbAttribute); | |
private enum DWMWINDOWATTRIBUTE | |
{ | |
DWMWA_NCRENDERING_ENABLED = 1, | |
DWMWA_NCRENDERING_POLICY, | |
DWMWA_TRANSITIONS_FORCEDISABLED, | |
DWMWA_ALLOW_NCPAINT, | |
DWMWA_CAPTION_BUTTON_BOUNDS, | |
DWMWA_NONCLIENT_RTL_LAYOUT, | |
DWMWA_FORCE_ICONIC_REPRESENTATION, | |
DWMWA_FLIP3D_POLICY, | |
DWMWA_EXTENDED_FRAME_BOUNDS, | |
DWMWA_HAS_ICONIC_BITMAP, | |
DWMWA_DISALLOW_PEEK, | |
DWMWA_EXCLUDED_FROM_PEEK, | |
DWMWA_CLOAK, | |
DWMWA_CLOAKED, | |
DWMWA_FREEZE_REPRESENTATION, | |
DWMWA_LAST | |
}; | |
public static TaskBarPosision GetTaskBarPosision() { | |
var abd = new APPBARDATA(); | |
if (SHAppBarMessage(ABM_GETTASKBARPOS, abd) != 0) { | |
return abd.uEdge; | |
} else { | |
throw new Win32Exception(); | |
} | |
} | |
private const int ABM_GETTASKBARPOS = 0x00000005; | |
public enum TaskBarPosision | |
{ | |
Left, | |
Top, | |
Right, | |
Bottom | |
} | |
[DllImport("shell32.dll", SetLastError = true)] | |
private static extern uint SHAppBarMessage(int dwMessage, APPBARDATA pData); | |
[StructLayout(LayoutKind.Sequential)] | |
private class APPBARDATA | |
{ | |
public int cbSize; | |
public IntPtr hWnd; | |
public int uCallbackMessage; | |
public TaskBarPosision uEdge; | |
public RECT rc; | |
public int lParam; | |
public APPBARDATA() { | |
cbSize = Marshal.SizeOf(this); | |
} | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
private struct RECT | |
{ | |
public int Left; | |
public int Top; | |
public int Right; | |
public int Bottom; | |
public Rectangle Rectangle { | |
get { | |
return Rectangle.FromLTRB(Left, Top, Right, Bottom); | |
} | |
} | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
private struct NOTIFYICONIDENTIFIER | |
{ | |
public int cbSize; | |
public IntPtr hWnd; | |
public int uID; | |
public Guid guidItem; | |
} | |
[DllImport("shell32.dll")] | |
private static extern int Shell_NotifyIconGetRect( | |
ref NOTIFYICONIDENTIFIER identifier, out RECT iconLocation); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment