Converted project to VisualStudio 2012.
Adding SoundGraphDisplay and SensorFrontView classes.
They were respectively based on SystemTray and SensorNotifyIcon.
SoundGraphDisplay is now able to load iMONDisplay.dll providing it lives on your PATH.
Adding option to sensor context menu for adding it into FrontView.
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.Runtime.InteropServices;
15 using System.Reflection;
16 using System.Windows.Forms;
18 namespace OpenHardwareMonitor.GUI {
20 public class NotifyIconAdv : IDisposable {
22 private NotifyIcon genericNotifyIcon;
23 private NotifyIconWindowsImplementation windowsNotifyIcon;
25 public NotifyIconAdv() {
26 int p = (int)Environment.OSVersion.Platform;
27 if ((p == 4) || (p == 128)) { // Unix
28 genericNotifyIcon = new NotifyIcon();
30 windowsNotifyIcon = new NotifyIconWindowsImplementation();
34 public event EventHandler BalloonTipClicked {
36 if (genericNotifyIcon != null)
37 genericNotifyIcon.BalloonTipClicked += value;
39 windowsNotifyIcon.BalloonTipClicked += value;
42 if (genericNotifyIcon != null)
43 genericNotifyIcon.BalloonTipClicked -= value;
45 windowsNotifyIcon.BalloonTipClicked -= value;
49 public event EventHandler BalloonTipClosed {
51 if (genericNotifyIcon != null)
52 genericNotifyIcon.BalloonTipClosed += value;
54 windowsNotifyIcon.BalloonTipClosed += value;
57 if (genericNotifyIcon != null)
58 genericNotifyIcon.BalloonTipClosed -= value;
60 windowsNotifyIcon.BalloonTipClosed -= value;
64 public event EventHandler BalloonTipShown {
66 if (genericNotifyIcon != null)
67 genericNotifyIcon.BalloonTipShown += value;
69 windowsNotifyIcon.BalloonTipShown += value;
72 if (genericNotifyIcon != null)
73 genericNotifyIcon.BalloonTipShown -= value;
75 windowsNotifyIcon.BalloonTipShown -= value;
79 public event EventHandler Click {
81 if (genericNotifyIcon != null)
82 genericNotifyIcon.Click += value;
84 windowsNotifyIcon.Click += value;
87 if (genericNotifyIcon != null)
88 genericNotifyIcon.Click -= value;
90 windowsNotifyIcon.Click -= value;
94 public event EventHandler DoubleClick {
96 if (genericNotifyIcon != null)
97 genericNotifyIcon.DoubleClick += value;
99 windowsNotifyIcon.DoubleClick += value;
102 if (genericNotifyIcon != null)
103 genericNotifyIcon.DoubleClick -= value;
105 windowsNotifyIcon.DoubleClick -= value;
109 public event MouseEventHandler MouseClick {
111 if (genericNotifyIcon != null)
112 genericNotifyIcon.MouseClick += value;
114 windowsNotifyIcon.MouseClick += value;
117 if (genericNotifyIcon != null)
118 genericNotifyIcon.MouseClick -= value;
120 windowsNotifyIcon.MouseClick -= value;
124 public event MouseEventHandler MouseDoubleClick {
126 if (genericNotifyIcon != null)
127 genericNotifyIcon.MouseDoubleClick += value;
129 windowsNotifyIcon.MouseDoubleClick += value;
132 if (genericNotifyIcon != null)
133 genericNotifyIcon.MouseDoubleClick -= value;
135 windowsNotifyIcon.MouseDoubleClick -= value;
139 public event MouseEventHandler MouseDown {
141 if (genericNotifyIcon != null)
142 genericNotifyIcon.MouseDown += value;
144 windowsNotifyIcon.MouseDown += value;
147 if (genericNotifyIcon != null)
148 genericNotifyIcon.MouseDown -= value;
150 windowsNotifyIcon.MouseDown -= value;
154 public event MouseEventHandler MouseMove {
156 if (genericNotifyIcon != null)
157 genericNotifyIcon.MouseMove += value;
159 windowsNotifyIcon.MouseMove += value;
162 if (genericNotifyIcon != null)
163 genericNotifyIcon.MouseMove -= value;
165 windowsNotifyIcon.MouseMove -= value;
169 public event MouseEventHandler MouseUp {
171 if (genericNotifyIcon != null)
172 genericNotifyIcon.MouseUp += value;
174 windowsNotifyIcon.MouseUp += value;
177 if (genericNotifyIcon != null)
178 genericNotifyIcon.MouseUp -= value;
180 windowsNotifyIcon.MouseUp -= value;
184 public string BalloonTipText {
186 if (genericNotifyIcon != null)
187 return genericNotifyIcon.BalloonTipText;
189 return windowsNotifyIcon.BalloonTipText;
192 if (genericNotifyIcon != null)
193 genericNotifyIcon.BalloonTipText = value;
195 windowsNotifyIcon.BalloonTipText = value;
199 public ToolTipIcon BalloonTipIcon {
201 if (genericNotifyIcon != null)
202 return genericNotifyIcon.BalloonTipIcon;
204 return windowsNotifyIcon.BalloonTipIcon;
207 if (genericNotifyIcon != null)
208 genericNotifyIcon.BalloonTipIcon = value;
210 windowsNotifyIcon.BalloonTipIcon = value;
214 public string BalloonTipTitle {
216 if (genericNotifyIcon != null)
217 return genericNotifyIcon.BalloonTipTitle;
219 return windowsNotifyIcon.BalloonTipTitle;
222 if (genericNotifyIcon != null)
223 genericNotifyIcon.BalloonTipTitle = value;
225 windowsNotifyIcon.BalloonTipTitle = value;
229 public ContextMenu ContextMenu {
231 if (genericNotifyIcon != null)
232 return genericNotifyIcon.ContextMenu;
234 return windowsNotifyIcon.ContextMenu;
237 if (genericNotifyIcon != null)
238 genericNotifyIcon.ContextMenu = value;
240 windowsNotifyIcon.ContextMenu = value;
244 public ContextMenuStrip ContextMenuStrip {
246 if (genericNotifyIcon != null)
247 return genericNotifyIcon.ContextMenuStrip;
249 return windowsNotifyIcon.ContextMenuStrip;
252 if (genericNotifyIcon != null)
253 genericNotifyIcon.ContextMenuStrip = value;
255 windowsNotifyIcon.ContextMenuStrip = value;
259 public object Tag { get; set; }
263 if (genericNotifyIcon != null)
264 return genericNotifyIcon.Icon;
266 return windowsNotifyIcon.Icon;
269 if (genericNotifyIcon != null)
270 genericNotifyIcon.Icon = value;
272 windowsNotifyIcon.Icon = value;
278 if (genericNotifyIcon != null)
279 return genericNotifyIcon.Text;
281 return windowsNotifyIcon.Text;
284 if (genericNotifyIcon != null)
285 genericNotifyIcon.Text = value;
287 windowsNotifyIcon.Text = value;
291 public bool Visible {
293 if (genericNotifyIcon != null)
294 return genericNotifyIcon.Visible;
296 return windowsNotifyIcon.Visible;
299 if (genericNotifyIcon != null)
300 genericNotifyIcon.Visible = value;
302 windowsNotifyIcon.Visible = value;
306 public void Dispose() {
307 if (genericNotifyIcon != null)
308 genericNotifyIcon.Dispose();
310 windowsNotifyIcon.Dispose();
313 public void ShowBalloonTip(int timeout) {
314 ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
317 public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
318 ToolTipIcon tipIcon) {
319 if (genericNotifyIcon != null)
320 genericNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
322 windowsNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
325 private class NotifyIconWindowsImplementation : Component {
327 private static int nextId = 0;
329 private object syncObj = new object();
331 private string text = "";
333 private bool created;
334 private NotifyIconNativeWindow window;
335 private bool doubleClickDown;
336 private bool visible;
337 private MethodInfo commandDispatch;
339 public event EventHandler BalloonTipClicked;
340 public event EventHandler BalloonTipClosed;
341 public event EventHandler BalloonTipShown;
342 public event EventHandler Click;
343 public event EventHandler DoubleClick;
344 public event MouseEventHandler MouseClick;
345 public event MouseEventHandler MouseDoubleClick;
346 public event MouseEventHandler MouseDown;
347 public event MouseEventHandler MouseMove;
348 public event MouseEventHandler MouseUp;
350 public string BalloonTipText { get; set; }
351 public ToolTipIcon BalloonTipIcon { get; set; }
352 public string BalloonTipTitle { get; set; }
353 public ContextMenu ContextMenu { get; set; }
354 public ContextMenuStrip ContextMenuStrip { get; set; }
355 public object Tag { get; set; }
364 UpdateNotifyIcon(visible);
377 if (value.Length > 63)
378 throw new ArgumentOutOfRangeException();
380 if (!value.Equals(text)) {
384 UpdateNotifyIcon(visible);
389 public bool Visible {
394 if (visible != value) {
396 UpdateNotifyIcon(visible);
401 public NotifyIconWindowsImplementation() {
403 BalloonTipTitle = "";
405 commandDispatch = typeof(Form).Assembly.
406 GetType("System.Windows.Forms.Command").GetMethod("DispatchID",
407 BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public,
408 null, new Type[] { typeof(int) }, null);
410 id = ++NotifyIconWindowsImplementation.nextId;
411 window = new NotifyIconNativeWindow(this);
412 UpdateNotifyIcon(visible);
415 protected override void Dispose(bool disposing) {
417 if (window != null) {
420 UpdateNotifyIcon(false);
421 window.DestroyHandle();
424 ContextMenuStrip = null;
427 if (window != null && window.Handle != IntPtr.Zero) {
428 NativeMethods.PostMessage(
429 new HandleRef(window, window.Handle), WM_CLOSE, 0, 0);
430 window.ReleaseHandle();
433 base.Dispose(disposing);
436 public void ShowBalloonTip(int timeout) {
437 ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
440 public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
441 ToolTipIcon tipIcon) {
443 throw new ArgumentOutOfRangeException("timeout");
445 if (string.IsNullOrEmpty(tipText))
446 throw new ArgumentException("tipText");
452 NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
453 if (window.Handle == IntPtr.Zero)
454 window.CreateHandle(new CreateParams());
456 data.Window = window.Handle;
458 data.Flags = NativeMethods.NotifyIconDataFlags.Info;
459 data.TimeoutOrVersion = timeout;
460 data.InfoTitle = tipTitle;
462 data.InfoFlags = (int)tipIcon;
464 NativeMethods.Shell_NotifyIcon(
465 NativeMethods.NotifyIconMessage.Modify, data);
469 private void ShowContextMenu() {
470 if (ContextMenu == null && ContextMenuStrip == null)
473 NativeMethods.Point p = new NativeMethods.Point();
474 NativeMethods.GetCursorPos(ref p);
475 NativeMethods.SetForegroundWindow(
476 new HandleRef(window, window.Handle));
478 if (ContextMenu != null) {
479 ContextMenu.GetType().InvokeMember("OnPopup",
480 BindingFlags.NonPublic | BindingFlags.InvokeMethod |
481 BindingFlags.Instance, null, ContextMenu,
482 new Object[] { System.EventArgs.Empty });
484 NativeMethods.TrackPopupMenuEx(
485 new HandleRef(ContextMenu, ContextMenu.Handle), 72,
486 p.x, p.y, new HandleRef(window, window.Handle),
489 NativeMethods.PostMessage(
490 new HandleRef(window, window.Handle), WM_NULL, 0, 0);
494 if (ContextMenuStrip != null)
495 ContextMenuStrip.GetType().InvokeMember("ShowInTaskbar",
496 BindingFlags.NonPublic | BindingFlags.InvokeMethod |
497 BindingFlags.Instance, null, ContextMenuStrip,
498 new Object[] { p.x, p.y });
501 private void UpdateNotifyIcon(bool showNotifyIcon) {
506 window.LockReference(showNotifyIcon);
508 NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
509 data.CallbackMessage = WM_TRAYMOUSEMESSAGE;
510 data.Flags = NativeMethods.NotifyIconDataFlags.Message;
512 if (showNotifyIcon && window.Handle == IntPtr.Zero)
513 window.CreateHandle(new CreateParams());
515 data.Window = window.Handle;
519 data.Flags |= NativeMethods.NotifyIconDataFlags.Icon;
520 data.Icon = icon.Handle;
523 data.Flags |= NativeMethods.NotifyIconDataFlags.Tip;
526 if (showNotifyIcon && icon != null) {
530 created = NativeMethods.Shell_NotifyIcon(
531 NativeMethods.NotifyIconMessage.Add, data);
533 System.Threading.Thread.Sleep(200);
536 } while (!created && i < 40);
538 NativeMethods.Shell_NotifyIcon(
539 NativeMethods.NotifyIconMessage.Modify, data);
544 bool deleted = false;
546 deleted = NativeMethods.Shell_NotifyIcon(
547 NativeMethods.NotifyIconMessage.Delete, data);
549 System.Threading.Thread.Sleep(200);
552 } while (!deleted && i < 40);
559 private void ProcessMouseDown(ref Message message, MouseButtons button,
562 if (DoubleClick != null)
563 DoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
565 if (MouseDoubleClick != null)
566 MouseDoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
568 doubleClickDown = true;
571 if (MouseDown != null)
573 new MouseEventArgs(button, doubleClick ? 2 : 1, 0, 0, 0));
576 private void ProcessMouseUp(ref Message message, MouseButtons button) {
578 MouseUp(this, new MouseEventArgs(button, 0, 0, 0, 0));
580 if (!doubleClickDown) {
582 Click(this, new MouseEventArgs(button, 0, 0, 0, 0));
584 if (MouseClick != null)
585 MouseClick(this, new MouseEventArgs(button, 0, 0, 0, 0));
587 doubleClickDown = false;
590 private void ProcessInitMenuPopup(ref Message message) {
591 if (ContextMenu != null &&
592 (bool)ContextMenu.GetType().InvokeMember("ProcessInitMenuPopup",
593 BindingFlags.NonPublic | BindingFlags.InvokeMethod |
594 BindingFlags.Instance, null, ContextMenu,
595 new Object[] { message.WParam })) {
598 window.DefWndProc(ref message);
601 private void WndProc(ref Message message) {
602 switch (message.Msg) {
604 UpdateNotifyIcon(false);
607 if (message.LParam != IntPtr.Zero) {
608 window.DefWndProc(ref message);
611 commandDispatch.Invoke(null, new object[] {
612 message.WParam.ToInt32() & 0xFFFF });
614 case WM_INITMENUPOPUP:
615 ProcessInitMenuPopup(ref message);
617 case WM_TRAYMOUSEMESSAGE:
618 switch ((int)message.LParam) {
620 if (MouseMove != null)
622 new MouseEventArgs(Control.MouseButtons, 0, 0, 0, 0));
625 ProcessMouseDown(ref message, MouseButtons.Left, false);
628 ProcessMouseUp(ref message, MouseButtons.Left);
630 case WM_LBUTTONDBLCLK:
631 ProcessMouseDown(ref message, MouseButtons.Left, true);
634 ProcessMouseDown(ref message, MouseButtons.Right, false);
637 if (ContextMenu != null || ContextMenuStrip != null)
639 ProcessMouseUp(ref message, MouseButtons.Right);
641 case WM_RBUTTONDBLCLK:
642 ProcessMouseDown(ref message, MouseButtons.Right, true);
645 ProcessMouseDown(ref message, MouseButtons.Middle, false);
648 ProcessMouseUp(ref message, MouseButtons.Middle);
650 case WM_MBUTTONDBLCLK:
651 ProcessMouseDown(ref message, MouseButtons.Middle, true);
653 case NIN_BALLOONSHOW:
654 if (BalloonTipShown != null)
655 BalloonTipShown(this, EventArgs.Empty);
657 case NIN_BALLOONHIDE:
658 case NIN_BALLOONTIMEOUT:
659 if (BalloonTipClosed != null)
660 BalloonTipClosed(this, EventArgs.Empty);
662 case NIN_BALLOONUSERCLICK:
663 if (BalloonTipClicked != null)
664 BalloonTipClicked(this, EventArgs.Empty);
671 if (message.Msg == NotifyIconWindowsImplementation.WM_TASKBARCREATED) {
675 UpdateNotifyIcon(visible);
678 window.DefWndProc(ref message);
681 private class NotifyIconNativeWindow : NativeWindow {
682 private NotifyIconWindowsImplementation reference;
683 private GCHandle referenceHandle;
685 internal NotifyIconNativeWindow(NotifyIconWindowsImplementation component) {
686 this.reference = component;
689 ~NotifyIconNativeWindow() {
690 if (base.Handle != IntPtr.Zero)
691 NativeMethods.PostMessage(
692 new HandleRef(this, base.Handle), WM_CLOSE, 0, 0);
695 public void LockReference(bool locked) {
697 if (!referenceHandle.IsAllocated) {
698 referenceHandle = GCHandle.Alloc(reference, GCHandleType.Normal);
702 if (referenceHandle.IsAllocated)
703 referenceHandle.Free();
707 protected override void OnThreadException(Exception e) {
708 Application.OnThreadException(e);
711 protected override void WndProc(ref Message m) {
712 reference.WndProc(ref m);
716 private const int WM_NULL = 0x00;
717 private const int WM_DESTROY = 0x02;
718 private const int WM_CLOSE = 0x10;
719 private const int WM_COMMAND = 0x111;
720 private const int WM_INITMENUPOPUP = 0x117;
721 private const int WM_MOUSEMOVE = 0x200;
722 private const int WM_LBUTTONDOWN = 0x201;
723 private const int WM_LBUTTONUP = 0x202;
724 private const int WM_LBUTTONDBLCLK = 0x203;
725 private const int WM_RBUTTONDOWN = 0x204;
726 private const int WM_RBUTTONUP = 0x205;
727 private const int WM_RBUTTONDBLCLK = 0x206;
728 private const int WM_MBUTTONDOWN = 0x207;
729 private const int WM_MBUTTONUP = 0x208;
730 private const int WM_MBUTTONDBLCLK = 0x209;
731 private const int WM_TRAYMOUSEMESSAGE = 0x800;
733 private const int NIN_BALLOONSHOW = 0x402;
734 private const int NIN_BALLOONHIDE = 0x403;
735 private const int NIN_BALLOONTIMEOUT = 0x404;
736 private const int NIN_BALLOONUSERCLICK = 0x405;
738 private static int WM_TASKBARCREATED =
739 NativeMethods.RegisterWindowMessage("TaskbarCreated");
741 private static class NativeMethods {
742 [DllImport("user32.dll", CharSet = CharSet.Auto)]
743 public static extern IntPtr PostMessage(HandleRef hwnd, int msg,
744 int wparam, int lparam);
746 [DllImport("user32.dll", CharSet = CharSet.Auto)]
747 public static extern int RegisterWindowMessage(string msg);
750 public enum NotifyIconDataFlags : int {
758 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
759 public class NotifyIconData {
760 private int Size = Marshal.SizeOf(typeof(NotifyIconData));
761 public IntPtr Window;
763 public NotifyIconDataFlags Flags;
764 public int CallbackMessage;
766 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
769 public int StateMask;
770 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
772 public int TimeoutOrVersion;
773 [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
774 public string InfoTitle;
775 public int InfoFlags;
778 public enum NotifyIconMessage : int {
784 [DllImport("shell32.dll", CharSet = CharSet.Auto)]
785 [return: MarshalAs(UnmanagedType.Bool)]
786 public static extern bool Shell_NotifyIcon(NotifyIconMessage message,
787 NotifyIconData pnid);
789 [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
790 public static extern bool TrackPopupMenuEx(HandleRef hmenu, int fuFlags,
791 int x, int y, HandleRef hwnd, IntPtr tpm);
793 [StructLayout(LayoutKind.Sequential)]
794 public struct Point {
799 [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
800 public static extern bool GetCursorPos(ref Point point);
802 [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
803 public static extern bool SetForegroundWindow(HandleRef hWnd);