Optical drive eject action now functional.
3 This Source Code Form is subject to the terms of the Mozilla Public
4 License, v. 2.0. If a copy of the MPL was not distributed with this
5 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 Copyright (C) 2012 Michael Möller <mmoeller@openhardwaremonitor.org>
12 using System.ComponentModel;
14 using System.Reflection;
15 using System.Runtime.InteropServices;
16 using System.Windows.Forms;
18 namespace SharpDisplayManager
20 public class NotifyIconAdv : IDisposable
22 private NotifyIcon genericNotifyIcon;
23 private NotifyIconWindowsImplementation windowsNotifyIcon;
25 public NotifyIconAdv()
27 int p = (int)Environment.OSVersion.Platform;
28 if ((p == 4) || (p == 128))
30 genericNotifyIcon = new NotifyIcon();
34 windowsNotifyIcon = new NotifyIconWindowsImplementation();
38 public event EventHandler BalloonTipClicked
42 if (genericNotifyIcon != null)
43 genericNotifyIcon.BalloonTipClicked += value;
45 windowsNotifyIcon.BalloonTipClicked += value;
49 if (genericNotifyIcon != null)
50 genericNotifyIcon.BalloonTipClicked -= value;
52 windowsNotifyIcon.BalloonTipClicked -= value;
56 public event EventHandler BalloonTipClosed
60 if (genericNotifyIcon != null)
61 genericNotifyIcon.BalloonTipClosed += value;
63 windowsNotifyIcon.BalloonTipClosed += value;
67 if (genericNotifyIcon != null)
68 genericNotifyIcon.BalloonTipClosed -= value;
70 windowsNotifyIcon.BalloonTipClosed -= value;
74 public event EventHandler BalloonTipShown
78 if (genericNotifyIcon != null)
79 genericNotifyIcon.BalloonTipShown += value;
81 windowsNotifyIcon.BalloonTipShown += value;
85 if (genericNotifyIcon != null)
86 genericNotifyIcon.BalloonTipShown -= value;
88 windowsNotifyIcon.BalloonTipShown -= value;
92 public event EventHandler Click
96 if (genericNotifyIcon != null)
97 genericNotifyIcon.Click += value;
99 windowsNotifyIcon.Click += value;
103 if (genericNotifyIcon != null)
104 genericNotifyIcon.Click -= value;
106 windowsNotifyIcon.Click -= value;
110 public event EventHandler DoubleClick
114 if (genericNotifyIcon != null)
115 genericNotifyIcon.DoubleClick += value;
117 windowsNotifyIcon.DoubleClick += value;
121 if (genericNotifyIcon != null)
122 genericNotifyIcon.DoubleClick -= value;
124 windowsNotifyIcon.DoubleClick -= value;
128 public event MouseEventHandler MouseClick
132 if (genericNotifyIcon != null)
133 genericNotifyIcon.MouseClick += value;
135 windowsNotifyIcon.MouseClick += value;
139 if (genericNotifyIcon != null)
140 genericNotifyIcon.MouseClick -= value;
142 windowsNotifyIcon.MouseClick -= value;
146 public event MouseEventHandler MouseDoubleClick
150 if (genericNotifyIcon != null)
151 genericNotifyIcon.MouseDoubleClick += value;
153 windowsNotifyIcon.MouseDoubleClick += value;
157 if (genericNotifyIcon != null)
158 genericNotifyIcon.MouseDoubleClick -= value;
160 windowsNotifyIcon.MouseDoubleClick -= value;
164 public event MouseEventHandler MouseDown
168 if (genericNotifyIcon != null)
169 genericNotifyIcon.MouseDown += value;
171 windowsNotifyIcon.MouseDown += value;
175 if (genericNotifyIcon != null)
176 genericNotifyIcon.MouseDown -= value;
178 windowsNotifyIcon.MouseDown -= value;
182 public event MouseEventHandler MouseMove
186 if (genericNotifyIcon != null)
187 genericNotifyIcon.MouseMove += value;
189 windowsNotifyIcon.MouseMove += value;
193 if (genericNotifyIcon != null)
194 genericNotifyIcon.MouseMove -= value;
196 windowsNotifyIcon.MouseMove -= value;
200 public event MouseEventHandler MouseUp
204 if (genericNotifyIcon != null)
205 genericNotifyIcon.MouseUp += value;
207 windowsNotifyIcon.MouseUp += value;
211 if (genericNotifyIcon != null)
212 genericNotifyIcon.MouseUp -= value;
214 windowsNotifyIcon.MouseUp -= value;
218 public string BalloonTipText
222 if (genericNotifyIcon != null)
223 return genericNotifyIcon.BalloonTipText;
225 return windowsNotifyIcon.BalloonTipText;
229 if (genericNotifyIcon != null)
230 genericNotifyIcon.BalloonTipText = value;
232 windowsNotifyIcon.BalloonTipText = value;
236 public ToolTipIcon BalloonTipIcon
240 if (genericNotifyIcon != null)
241 return genericNotifyIcon.BalloonTipIcon;
243 return windowsNotifyIcon.BalloonTipIcon;
247 if (genericNotifyIcon != null)
248 genericNotifyIcon.BalloonTipIcon = value;
250 windowsNotifyIcon.BalloonTipIcon = value;
254 public string BalloonTipTitle
258 if (genericNotifyIcon != null)
259 return genericNotifyIcon.BalloonTipTitle;
261 return windowsNotifyIcon.BalloonTipTitle;
265 if (genericNotifyIcon != null)
266 genericNotifyIcon.BalloonTipTitle = value;
268 windowsNotifyIcon.BalloonTipTitle = value;
272 public ContextMenu ContextMenu
276 if (genericNotifyIcon != null)
277 return genericNotifyIcon.ContextMenu;
279 return windowsNotifyIcon.ContextMenu;
283 if (genericNotifyIcon != null)
284 genericNotifyIcon.ContextMenu = value;
286 windowsNotifyIcon.ContextMenu = value;
290 public ContextMenuStrip ContextMenuStrip
294 if (genericNotifyIcon != null)
295 return genericNotifyIcon.ContextMenuStrip;
297 return windowsNotifyIcon.ContextMenuStrip;
301 if (genericNotifyIcon != null)
302 genericNotifyIcon.ContextMenuStrip = value;
304 windowsNotifyIcon.ContextMenuStrip = value;
308 public object Tag { get; set; }
314 if (genericNotifyIcon != null)
315 return genericNotifyIcon.Icon;
317 return windowsNotifyIcon.Icon;
321 if (genericNotifyIcon != null)
322 genericNotifyIcon.Icon = value;
324 windowsNotifyIcon.Icon = value;
332 if (genericNotifyIcon != null)
333 return genericNotifyIcon.Text;
335 return windowsNotifyIcon.Text;
339 if (genericNotifyIcon != null)
340 genericNotifyIcon.Text = value;
342 windowsNotifyIcon.Text = value;
350 if (genericNotifyIcon != null)
351 return genericNotifyIcon.Visible;
353 return windowsNotifyIcon.Visible;
357 if (genericNotifyIcon != null)
358 genericNotifyIcon.Visible = value;
360 windowsNotifyIcon.Visible = value;
364 public void Dispose()
366 if (genericNotifyIcon != null)
367 genericNotifyIcon.Dispose();
369 windowsNotifyIcon.Dispose();
372 public void ShowBalloonTip(int timeout)
374 ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
377 public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
380 if (genericNotifyIcon != null)
381 genericNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
383 windowsNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
386 private class NotifyIconWindowsImplementation : Component
388 private static int nextId = 0;
390 private object syncObj = new object();
392 private string text = "";
394 private bool created;
395 private NotifyIconNativeWindow window;
396 private bool doubleClickDown;
397 private bool visible;
398 private MethodInfo commandDispatch;
400 public event EventHandler BalloonTipClicked;
402 public event EventHandler BalloonTipClosed;
404 public event EventHandler BalloonTipShown;
406 public event EventHandler Click;
408 public event EventHandler DoubleClick;
410 public event MouseEventHandler MouseClick;
412 public event MouseEventHandler MouseDoubleClick;
414 public event MouseEventHandler MouseDown;
416 public event MouseEventHandler MouseMove;
418 public event MouseEventHandler MouseUp;
420 public string BalloonTipText { get; set; }
422 public ToolTipIcon BalloonTipIcon { get; set; }
424 public string BalloonTipTitle { get; set; }
426 public ContextMenu ContextMenu { get; set; }
428 public ContextMenuStrip ContextMenuStrip { get; set; }
430 public object Tag { get; set; }
443 UpdateNotifyIcon(visible);
459 if (value.Length > 63)
460 throw new ArgumentOutOfRangeException();
462 if (!value.Equals(text))
467 UpdateNotifyIcon(visible);
480 if (visible != value)
483 UpdateNotifyIcon(visible);
488 public NotifyIconWindowsImplementation()
491 BalloonTipTitle = "";
493 commandDispatch = typeof(Form).Assembly.
494 GetType("System.Windows.Forms.Command").GetMethod("DispatchID",
495 BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public,
496 null, new Type[] { typeof(int) }, null);
498 id = ++NotifyIconWindowsImplementation.nextId;
499 window = new NotifyIconNativeWindow(this);
500 UpdateNotifyIcon(visible);
503 protected override void Dispose(bool disposing)
511 UpdateNotifyIcon(false);
512 window.DestroyHandle();
515 ContextMenuStrip = null;
520 if (window != null && window.Handle != IntPtr.Zero)
522 NativeMethods.PostMessage(
523 new HandleRef(window, window.Handle), WM_CLOSE, 0, 0);
524 window.ReleaseHandle();
527 base.Dispose(disposing);
530 public void ShowBalloonTip(int timeout)
532 ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
535 public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
539 throw new ArgumentOutOfRangeException("timeout");
541 if (string.IsNullOrEmpty(tipText))
542 throw new ArgumentException("tipText");
549 NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
550 if (window.Handle == IntPtr.Zero)
551 window.CreateHandle(new CreateParams());
553 data.Window = window.Handle;
555 data.Flags = NativeMethods.NotifyIconDataFlags.Info;
556 data.TimeoutOrVersion = timeout;
557 data.InfoTitle = tipTitle;
559 data.InfoFlags = (int)tipIcon;
561 NativeMethods.Shell_NotifyIcon(
562 NativeMethods.NotifyIconMessage.Modify, data);
566 private void ShowContextMenu()
568 if (ContextMenu == null && ContextMenuStrip == null)
571 NativeMethods.Point p = new NativeMethods.Point();
572 NativeMethods.GetCursorPos(ref p);
573 NativeMethods.SetForegroundWindow(
574 new HandleRef(window, window.Handle));
576 if (ContextMenu != null)
578 ContextMenu.GetType().InvokeMember("OnPopup",
579 BindingFlags.NonPublic | BindingFlags.InvokeMethod |
580 BindingFlags.Instance, null, ContextMenu,
581 new Object[] { System.EventArgs.Empty });
583 NativeMethods.TrackPopupMenuEx(
584 new HandleRef(ContextMenu, ContextMenu.Handle), 72,
585 p.x, p.y, new HandleRef(window, window.Handle),
588 NativeMethods.PostMessage(
589 new HandleRef(window, window.Handle), WM_NULL, 0, 0);
593 if (ContextMenuStrip != null)
594 ContextMenuStrip.GetType().InvokeMember("ShowInTaskbar",
595 BindingFlags.NonPublic | BindingFlags.InvokeMethod |
596 BindingFlags.Instance, null, ContextMenuStrip,
597 new Object[] { p.x, p.y });
600 private void UpdateNotifyIcon(bool showNotifyIcon)
607 window.LockReference(showNotifyIcon);
609 NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
610 data.CallbackMessage = WM_TRAYMOUSEMESSAGE;
611 data.Flags = NativeMethods.NotifyIconDataFlags.Message;
613 if (showNotifyIcon && window.Handle == IntPtr.Zero)
614 window.CreateHandle(new CreateParams());
616 data.Window = window.Handle;
621 data.Flags |= NativeMethods.NotifyIconDataFlags.Icon;
622 data.Icon = icon.Handle;
625 data.Flags |= NativeMethods.NotifyIconDataFlags.Tip;
628 if (showNotifyIcon && icon != null)
635 created = NativeMethods.Shell_NotifyIcon(
636 NativeMethods.NotifyIconMessage.Add, data);
639 System.Threading.Thread.Sleep(200);
642 } while (!created && i < 40);
646 NativeMethods.Shell_NotifyIcon(
647 NativeMethods.NotifyIconMessage.Modify, data);
655 bool deleted = false;
658 deleted = NativeMethods.Shell_NotifyIcon(
659 NativeMethods.NotifyIconMessage.Delete, data);
662 System.Threading.Thread.Sleep(200);
665 } while (!deleted && i < 40);
672 private void ProcessMouseDown(ref Message message, MouseButtons button,
677 if (DoubleClick != null)
678 DoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
680 if (MouseDoubleClick != null)
681 MouseDoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
683 doubleClickDown = true;
686 if (MouseDown != null)
688 new MouseEventArgs(button, doubleClick ? 2 : 1, 0, 0, 0));
691 private void ProcessMouseUp(ref Message message, MouseButtons button)
694 MouseUp(this, new MouseEventArgs(button, 0, 0, 0, 0));
696 if (!doubleClickDown)
699 Click(this, new MouseEventArgs(button, 0, 0, 0, 0));
701 if (MouseClick != null)
702 MouseClick(this, new MouseEventArgs(button, 0, 0, 0, 0));
704 doubleClickDown = false;
707 private void ProcessInitMenuPopup(ref Message message)
709 if (ContextMenu != null &&
710 (bool)ContextMenu.GetType().InvokeMember("ProcessInitMenuPopup",
711 BindingFlags.NonPublic | BindingFlags.InvokeMethod |
712 BindingFlags.Instance, null, ContextMenu,
713 new Object[] { message.WParam }))
717 window.DefWndProc(ref message);
720 private void WndProc(ref Message message)
725 UpdateNotifyIcon(false);
729 if (message.LParam != IntPtr.Zero)
731 window.DefWndProc(ref message);
734 commandDispatch.Invoke(null, new object[] {
735 message.WParam.ToInt32() & 0xFFFF });
738 case WM_INITMENUPOPUP:
739 ProcessInitMenuPopup(ref message);
742 case WM_TRAYMOUSEMESSAGE:
743 switch ((int)message.LParam)
746 if (MouseMove != null)
748 new MouseEventArgs(Control.MouseButtons, 0, 0, 0, 0));
752 ProcessMouseDown(ref message, MouseButtons.Left, false);
756 ProcessMouseUp(ref message, MouseButtons.Left);
759 case WM_LBUTTONDBLCLK:
760 ProcessMouseDown(ref message, MouseButtons.Left, true);
764 ProcessMouseDown(ref message, MouseButtons.Right, false);
768 if (ContextMenu != null || ContextMenuStrip != null)
770 ProcessMouseUp(ref message, MouseButtons.Right);
773 case WM_RBUTTONDBLCLK:
774 ProcessMouseDown(ref message, MouseButtons.Right, true);
778 ProcessMouseDown(ref message, MouseButtons.Middle, false);
782 ProcessMouseUp(ref message, MouseButtons.Middle);
785 case WM_MBUTTONDBLCLK:
786 ProcessMouseDown(ref message, MouseButtons.Middle, true);
789 case NIN_BALLOONSHOW:
790 if (BalloonTipShown != null)
791 BalloonTipShown(this, EventArgs.Empty);
794 case NIN_BALLOONHIDE:
795 case NIN_BALLOONTIMEOUT:
796 if (BalloonTipClosed != null)
797 BalloonTipClosed(this, EventArgs.Empty);
800 case NIN_BALLOONUSERCLICK:
801 if (BalloonTipClicked != null)
802 BalloonTipClicked(this, EventArgs.Empty);
810 if (message.Msg == NotifyIconWindowsImplementation.WM_TASKBARCREATED)
816 UpdateNotifyIcon(visible);
819 window.DefWndProc(ref message);
822 private class NotifyIconNativeWindow : NativeWindow
824 private NotifyIconWindowsImplementation reference;
825 private GCHandle referenceHandle;
827 internal NotifyIconNativeWindow(NotifyIconWindowsImplementation component)
829 this.reference = component;
832 ~NotifyIconNativeWindow()
834 if (base.Handle != IntPtr.Zero)
835 NativeMethods.PostMessage(
836 new HandleRef(this, base.Handle), WM_CLOSE, 0, 0);
839 public void LockReference(bool locked)
843 if (!referenceHandle.IsAllocated)
845 referenceHandle = GCHandle.Alloc(reference, GCHandleType.Normal);
851 if (referenceHandle.IsAllocated)
852 referenceHandle.Free();
856 protected override void OnThreadException(Exception e)
858 Application.OnThreadException(e);
861 protected override void WndProc(ref Message m)
863 reference.WndProc(ref m);
867 private const int WM_NULL = 0x00;
868 private const int WM_DESTROY = 0x02;
869 private const int WM_CLOSE = 0x10;
870 private const int WM_COMMAND = 0x111;
871 private const int WM_INITMENUPOPUP = 0x117;
872 private const int WM_MOUSEMOVE = 0x200;
873 private const int WM_LBUTTONDOWN = 0x201;
874 private const int WM_LBUTTONUP = 0x202;
875 private const int WM_LBUTTONDBLCLK = 0x203;
876 private const int WM_RBUTTONDOWN = 0x204;
877 private const int WM_RBUTTONUP = 0x205;
878 private const int WM_RBUTTONDBLCLK = 0x206;
879 private const int WM_MBUTTONDOWN = 0x207;
880 private const int WM_MBUTTONUP = 0x208;
881 private const int WM_MBUTTONDBLCLK = 0x209;
882 private const int WM_TRAYMOUSEMESSAGE = 0x800;
884 private const int NIN_BALLOONSHOW = 0x402;
885 private const int NIN_BALLOONHIDE = 0x403;
886 private const int NIN_BALLOONTIMEOUT = 0x404;
887 private const int NIN_BALLOONUSERCLICK = 0x405;
889 private static int WM_TASKBARCREATED =
890 NativeMethods.RegisterWindowMessage("TaskbarCreated");
892 private static class NativeMethods
894 [DllImport("user32.dll", CharSet = CharSet.Auto)]
895 public static extern IntPtr PostMessage(HandleRef hwnd, int msg,
896 int wparam, int lparam);
898 [DllImport("user32.dll", CharSet = CharSet.Auto)]
899 public static extern int RegisterWindowMessage(string msg);
902 public enum NotifyIconDataFlags : int
911 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
912 public class NotifyIconData
914 private int Size = Marshal.SizeOf(typeof(NotifyIconData));
915 public IntPtr Window;
917 public NotifyIconDataFlags Flags;
918 public int CallbackMessage;
921 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
925 public int StateMask;
927 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
930 public int TimeoutOrVersion;
932 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
933 public string InfoTitle;
935 public int InfoFlags;
938 public enum NotifyIconMessage : int
945 [DllImport("shell32.dll", CharSet = CharSet.Auto)]
946 [return: MarshalAs(UnmanagedType.Bool)]
947 public static extern bool Shell_NotifyIcon(NotifyIconMessage message,
948 NotifyIconData pnid);
950 [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
951 public static extern bool TrackPopupMenuEx(HandleRef hmenu, int fuFlags,
952 int x, int y, HandleRef hwnd, IntPtr tpm);
954 [StructLayout(LayoutKind.Sequential)]
961 [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
962 public static extern bool GetCursorPos(ref Point point);
964 [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
965 public static extern bool SetForegroundWindow(HandleRef hWnd);