Server/NotifyIconAdv.cs
author Stephane Lenclud
Fri, 19 Aug 2016 17:12:54 +0200
changeset 243 cc2251d065db
permissions -rw-r--r--
Optical drive eject action now functional.
     1 /*
     2 
     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/.
     6 
     7   Copyright (C) 2012 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 
     9 */
    10 
    11 using System;
    12 using System.ComponentModel;
    13 using System.Drawing;
    14 using System.Reflection;
    15 using System.Runtime.InteropServices;
    16 using System.Windows.Forms;
    17 
    18 namespace SharpDisplayManager
    19 {
    20 	public class NotifyIconAdv : IDisposable
    21 	{
    22 		private NotifyIcon genericNotifyIcon;
    23 		private NotifyIconWindowsImplementation windowsNotifyIcon;
    24 
    25 		public NotifyIconAdv()
    26 		{
    27 			int p = (int)Environment.OSVersion.Platform;
    28 			if ((p == 4) || (p == 128))
    29 			{ // Unix
    30 				genericNotifyIcon = new NotifyIcon();
    31 			}
    32 			else
    33 			{ // Windows
    34 				windowsNotifyIcon = new NotifyIconWindowsImplementation();
    35 			}
    36 		}
    37 
    38 		public event EventHandler BalloonTipClicked
    39 		{
    40 			add
    41 			{
    42 				if (genericNotifyIcon != null)
    43 					genericNotifyIcon.BalloonTipClicked += value;
    44 				else
    45 					windowsNotifyIcon.BalloonTipClicked += value;
    46 			}
    47 			remove
    48 			{
    49 				if (genericNotifyIcon != null)
    50 					genericNotifyIcon.BalloonTipClicked -= value;
    51 				else
    52 					windowsNotifyIcon.BalloonTipClicked -= value;
    53 			}
    54 		}
    55 
    56 		public event EventHandler BalloonTipClosed
    57 		{
    58 			add
    59 			{
    60 				if (genericNotifyIcon != null)
    61 					genericNotifyIcon.BalloonTipClosed += value;
    62 				else
    63 					windowsNotifyIcon.BalloonTipClosed += value;
    64 			}
    65 			remove
    66 			{
    67 				if (genericNotifyIcon != null)
    68 					genericNotifyIcon.BalloonTipClosed -= value;
    69 				else
    70 					windowsNotifyIcon.BalloonTipClosed -= value;
    71 			}
    72 		}
    73 
    74 		public event EventHandler BalloonTipShown
    75 		{
    76 			add
    77 			{
    78 				if (genericNotifyIcon != null)
    79 					genericNotifyIcon.BalloonTipShown += value;
    80 				else
    81 					windowsNotifyIcon.BalloonTipShown += value;
    82 			}
    83 			remove
    84 			{
    85 				if (genericNotifyIcon != null)
    86 					genericNotifyIcon.BalloonTipShown -= value;
    87 				else
    88 					windowsNotifyIcon.BalloonTipShown -= value;
    89 			}
    90 		}
    91 
    92 		public event EventHandler Click
    93 		{
    94 			add
    95 			{
    96 				if (genericNotifyIcon != null)
    97 					genericNotifyIcon.Click += value;
    98 				else
    99 					windowsNotifyIcon.Click += value;
   100 			}
   101 			remove
   102 			{
   103 				if (genericNotifyIcon != null)
   104 					genericNotifyIcon.Click -= value;
   105 				else
   106 					windowsNotifyIcon.Click -= value;
   107 			}
   108 		}
   109 
   110 		public event EventHandler DoubleClick
   111 		{
   112 			add
   113 			{
   114 				if (genericNotifyIcon != null)
   115 					genericNotifyIcon.DoubleClick += value;
   116 				else
   117 					windowsNotifyIcon.DoubleClick += value;
   118 			}
   119 			remove
   120 			{
   121 				if (genericNotifyIcon != null)
   122 					genericNotifyIcon.DoubleClick -= value;
   123 				else
   124 					windowsNotifyIcon.DoubleClick -= value;
   125 			}
   126 		}
   127 
   128 		public event MouseEventHandler MouseClick
   129 		{
   130 			add
   131 			{
   132 				if (genericNotifyIcon != null)
   133 					genericNotifyIcon.MouseClick += value;
   134 				else
   135 					windowsNotifyIcon.MouseClick += value;
   136 			}
   137 			remove
   138 			{
   139 				if (genericNotifyIcon != null)
   140 					genericNotifyIcon.MouseClick -= value;
   141 				else
   142 					windowsNotifyIcon.MouseClick -= value;
   143 			}
   144 		}
   145 
   146 		public event MouseEventHandler MouseDoubleClick
   147 		{
   148 			add
   149 			{
   150 				if (genericNotifyIcon != null)
   151 					genericNotifyIcon.MouseDoubleClick += value;
   152 				else
   153 					windowsNotifyIcon.MouseDoubleClick += value;
   154 			}
   155 			remove
   156 			{
   157 				if (genericNotifyIcon != null)
   158 					genericNotifyIcon.MouseDoubleClick -= value;
   159 				else
   160 					windowsNotifyIcon.MouseDoubleClick -= value;
   161 			}
   162 		}
   163 
   164 		public event MouseEventHandler MouseDown
   165 		{
   166 			add
   167 			{
   168 				if (genericNotifyIcon != null)
   169 					genericNotifyIcon.MouseDown += value;
   170 				else
   171 					windowsNotifyIcon.MouseDown += value;
   172 			}
   173 			remove
   174 			{
   175 				if (genericNotifyIcon != null)
   176 					genericNotifyIcon.MouseDown -= value;
   177 				else
   178 					windowsNotifyIcon.MouseDown -= value;
   179 			}
   180 		}
   181 
   182 		public event MouseEventHandler MouseMove
   183 		{
   184 			add
   185 			{
   186 				if (genericNotifyIcon != null)
   187 					genericNotifyIcon.MouseMove += value;
   188 				else
   189 					windowsNotifyIcon.MouseMove += value;
   190 			}
   191 			remove
   192 			{
   193 				if (genericNotifyIcon != null)
   194 					genericNotifyIcon.MouseMove -= value;
   195 				else
   196 					windowsNotifyIcon.MouseMove -= value;
   197 			}
   198 		}
   199 
   200 		public event MouseEventHandler MouseUp
   201 		{
   202 			add
   203 			{
   204 				if (genericNotifyIcon != null)
   205 					genericNotifyIcon.MouseUp += value;
   206 				else
   207 					windowsNotifyIcon.MouseUp += value;
   208 			}
   209 			remove
   210 			{
   211 				if (genericNotifyIcon != null)
   212 					genericNotifyIcon.MouseUp -= value;
   213 				else
   214 					windowsNotifyIcon.MouseUp -= value;
   215 			}
   216 		}
   217 
   218 		public string BalloonTipText
   219 		{
   220 			get
   221 			{
   222 				if (genericNotifyIcon != null)
   223 					return genericNotifyIcon.BalloonTipText;
   224 				else
   225 					return windowsNotifyIcon.BalloonTipText;
   226 			}
   227 			set
   228 			{
   229 				if (genericNotifyIcon != null)
   230 					genericNotifyIcon.BalloonTipText = value;
   231 				else
   232 					windowsNotifyIcon.BalloonTipText = value;
   233 			}
   234 		}
   235 
   236 		public ToolTipIcon BalloonTipIcon
   237 		{
   238 			get
   239 			{
   240 				if (genericNotifyIcon != null)
   241 					return genericNotifyIcon.BalloonTipIcon;
   242 				else
   243 					return windowsNotifyIcon.BalloonTipIcon;
   244 			}
   245 			set
   246 			{
   247 				if (genericNotifyIcon != null)
   248 					genericNotifyIcon.BalloonTipIcon = value;
   249 				else
   250 					windowsNotifyIcon.BalloonTipIcon = value;
   251 			}
   252 		}
   253 
   254 		public string BalloonTipTitle
   255 		{
   256 			get
   257 			{
   258 				if (genericNotifyIcon != null)
   259 					return genericNotifyIcon.BalloonTipTitle;
   260 				else
   261 					return windowsNotifyIcon.BalloonTipTitle;
   262 			}
   263 			set
   264 			{
   265 				if (genericNotifyIcon != null)
   266 					genericNotifyIcon.BalloonTipTitle = value;
   267 				else
   268 					windowsNotifyIcon.BalloonTipTitle = value;
   269 			}
   270 		}
   271 
   272 		public ContextMenu ContextMenu
   273 		{
   274 			get
   275 			{
   276 				if (genericNotifyIcon != null)
   277 					return genericNotifyIcon.ContextMenu;
   278 				else
   279 					return windowsNotifyIcon.ContextMenu;
   280 			}
   281 			set
   282 			{
   283 				if (genericNotifyIcon != null)
   284 					genericNotifyIcon.ContextMenu = value;
   285 				else
   286 					windowsNotifyIcon.ContextMenu = value;
   287 			}
   288 		}
   289 
   290 		public ContextMenuStrip ContextMenuStrip
   291 		{
   292 			get
   293 			{
   294 				if (genericNotifyIcon != null)
   295 					return genericNotifyIcon.ContextMenuStrip;
   296 				else
   297 					return windowsNotifyIcon.ContextMenuStrip;
   298 			}
   299 			set
   300 			{
   301 				if (genericNotifyIcon != null)
   302 					genericNotifyIcon.ContextMenuStrip = value;
   303 				else
   304 					windowsNotifyIcon.ContextMenuStrip = value;
   305 			}
   306 		}
   307 
   308 		public object Tag { get; set; }
   309 
   310 		public Icon Icon
   311 		{
   312 			get
   313 			{
   314 				if (genericNotifyIcon != null)
   315 					return genericNotifyIcon.Icon;
   316 				else
   317 					return windowsNotifyIcon.Icon;
   318 			}
   319 			set
   320 			{
   321 				if (genericNotifyIcon != null)
   322 					genericNotifyIcon.Icon = value;
   323 				else
   324 					windowsNotifyIcon.Icon = value;
   325 			}
   326 		}
   327 
   328 		public string Text
   329 		{
   330 			get
   331 			{
   332 				if (genericNotifyIcon != null)
   333 					return genericNotifyIcon.Text;
   334 				else
   335 					return windowsNotifyIcon.Text;
   336 			}
   337 			set
   338 			{
   339 				if (genericNotifyIcon != null)
   340 					genericNotifyIcon.Text = value;
   341 				else
   342 					windowsNotifyIcon.Text = value;
   343 			}
   344 		}
   345 
   346 		public bool Visible
   347 		{
   348 			get
   349 			{
   350 				if (genericNotifyIcon != null)
   351 					return genericNotifyIcon.Visible;
   352 				else
   353 					return windowsNotifyIcon.Visible;
   354 			}
   355 			set
   356 			{
   357 				if (genericNotifyIcon != null)
   358 					genericNotifyIcon.Visible = value;
   359 				else
   360 					windowsNotifyIcon.Visible = value;
   361 			}
   362 		}
   363 
   364 		public void Dispose()
   365 		{
   366 			if (genericNotifyIcon != null)
   367 				genericNotifyIcon.Dispose();
   368 			else
   369 				windowsNotifyIcon.Dispose();
   370 		}
   371 
   372 		public void ShowBalloonTip(int timeout)
   373 		{
   374 			ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
   375 		}
   376 
   377 		public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
   378 		  ToolTipIcon tipIcon)
   379 		{
   380 			if (genericNotifyIcon != null)
   381 				genericNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
   382 			else
   383 				windowsNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
   384 		}
   385 
   386 		private class NotifyIconWindowsImplementation : Component
   387 		{
   388 			private static int nextId = 0;
   389 
   390 			private object syncObj = new object();
   391 			private Icon icon;
   392 			private string text = "";
   393 			private int id;
   394 			private bool created;
   395 			private NotifyIconNativeWindow window;
   396 			private bool doubleClickDown;
   397 			private bool visible;
   398 			private MethodInfo commandDispatch;
   399 
   400 			public event EventHandler BalloonTipClicked;
   401 
   402 			public event EventHandler BalloonTipClosed;
   403 
   404 			public event EventHandler BalloonTipShown;
   405 
   406 			public event EventHandler Click;
   407 
   408 			public event EventHandler DoubleClick;
   409 
   410 			public event MouseEventHandler MouseClick;
   411 
   412 			public event MouseEventHandler MouseDoubleClick;
   413 
   414 			public event MouseEventHandler MouseDown;
   415 
   416 			public event MouseEventHandler MouseMove;
   417 
   418 			public event MouseEventHandler MouseUp;
   419 
   420 			public string BalloonTipText { get; set; }
   421 
   422 			public ToolTipIcon BalloonTipIcon { get; set; }
   423 
   424 			public string BalloonTipTitle { get; set; }
   425 
   426 			public ContextMenu ContextMenu { get; set; }
   427 
   428 			public ContextMenuStrip ContextMenuStrip { get; set; }
   429 
   430 			public object Tag { get; set; }
   431 
   432 			public Icon Icon
   433 			{
   434 				get
   435 				{
   436 					return icon;
   437 				}
   438 				set
   439 				{
   440 					if (icon != value)
   441 					{
   442 						icon = value;
   443 						UpdateNotifyIcon(visible);
   444 					}
   445 				}
   446 			}
   447 
   448 			public string Text
   449 			{
   450 				get
   451 				{
   452 					return text;
   453 				}
   454 				set
   455 				{
   456 					if (value == null)
   457 						value = "";
   458 
   459 					if (value.Length > 63)
   460 						throw new ArgumentOutOfRangeException();
   461 
   462 					if (!value.Equals(text))
   463 					{
   464 						text = value;
   465 
   466 						if (visible)
   467 							UpdateNotifyIcon(visible);
   468 					}
   469 				}
   470 			}
   471 
   472 			public bool Visible
   473 			{
   474 				get
   475 				{
   476 					return visible;
   477 				}
   478 				set
   479 				{
   480 					if (visible != value)
   481 					{
   482 						visible = value;
   483 						UpdateNotifyIcon(visible);
   484 					}
   485 				}
   486 			}
   487 
   488 			public NotifyIconWindowsImplementation()
   489 			{
   490 				BalloonTipText = "";
   491 				BalloonTipTitle = "";
   492 
   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);
   497 
   498 				id = ++NotifyIconWindowsImplementation.nextId;
   499 				window = new NotifyIconNativeWindow(this);
   500 				UpdateNotifyIcon(visible);
   501 			}
   502 
   503 			protected override void Dispose(bool disposing)
   504 			{
   505 				if (disposing)
   506 				{
   507 					if (window != null)
   508 					{
   509 						icon = null;
   510 						text = "";
   511 						UpdateNotifyIcon(false);
   512 						window.DestroyHandle();
   513 						window = null;
   514 						ContextMenu = null;
   515 						ContextMenuStrip = null;
   516 					}
   517 				}
   518 				else
   519 				{
   520 					if (window != null && window.Handle != IntPtr.Zero)
   521 					{
   522 						NativeMethods.PostMessage(
   523 						  new HandleRef(window, window.Handle), WM_CLOSE, 0, 0);
   524 						window.ReleaseHandle();
   525 					}
   526 				}
   527 				base.Dispose(disposing);
   528 			}
   529 
   530 			public void ShowBalloonTip(int timeout)
   531 			{
   532 				ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
   533 			}
   534 
   535 			public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
   536 			  ToolTipIcon tipIcon)
   537 			{
   538 				if (timeout < 0)
   539 					throw new ArgumentOutOfRangeException("timeout");
   540 
   541 				if (string.IsNullOrEmpty(tipText))
   542 					throw new ArgumentException("tipText");
   543 
   544 				if (DesignMode)
   545 					return;
   546 
   547 				if (created)
   548 				{
   549 					NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
   550 					if (window.Handle == IntPtr.Zero)
   551 						window.CreateHandle(new CreateParams());
   552 
   553 					data.Window = window.Handle;
   554 					data.ID = id;
   555 					data.Flags = NativeMethods.NotifyIconDataFlags.Info;
   556 					data.TimeoutOrVersion = timeout;
   557 					data.InfoTitle = tipTitle;
   558 					data.Info = tipText;
   559 					data.InfoFlags = (int)tipIcon;
   560 
   561 					NativeMethods.Shell_NotifyIcon(
   562 					  NativeMethods.NotifyIconMessage.Modify, data);
   563 				}
   564 			}
   565 
   566 			private void ShowContextMenu()
   567 			{
   568 				if (ContextMenu == null && ContextMenuStrip == null)
   569 					return;
   570 
   571 				NativeMethods.Point p = new NativeMethods.Point();
   572 				NativeMethods.GetCursorPos(ref p);
   573 				NativeMethods.SetForegroundWindow(
   574 				  new HandleRef(window, window.Handle));
   575 
   576 				if (ContextMenu != null)
   577 				{
   578 					ContextMenu.GetType().InvokeMember("OnPopup",
   579 					  BindingFlags.NonPublic | BindingFlags.InvokeMethod |
   580 					  BindingFlags.Instance, null, ContextMenu,
   581 					  new Object[] { System.EventArgs.Empty });
   582 
   583 					NativeMethods.TrackPopupMenuEx(
   584 					  new HandleRef(ContextMenu, ContextMenu.Handle), 72,
   585 					  p.x, p.y, new HandleRef(window, window.Handle),
   586 					  IntPtr.Zero);
   587 
   588 					NativeMethods.PostMessage(
   589 					  new HandleRef(window, window.Handle), WM_NULL, 0, 0);
   590 					return;
   591 				}
   592 
   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 });
   598 			}
   599 
   600 			private void UpdateNotifyIcon(bool showNotifyIcon)
   601 			{
   602 				if (DesignMode)
   603 					return;
   604 
   605 				lock (syncObj)
   606 				{
   607 					window.LockReference(showNotifyIcon);
   608 
   609 					NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
   610 					data.CallbackMessage = WM_TRAYMOUSEMESSAGE;
   611 					data.Flags = NativeMethods.NotifyIconDataFlags.Message;
   612 
   613 					if (showNotifyIcon && window.Handle == IntPtr.Zero)
   614 						window.CreateHandle(new CreateParams());
   615 
   616 					data.Window = window.Handle;
   617 					data.ID = id;
   618 
   619 					if (icon != null)
   620 					{
   621 						data.Flags |= NativeMethods.NotifyIconDataFlags.Icon;
   622 						data.Icon = icon.Handle;
   623 					}
   624 
   625 					data.Flags |= NativeMethods.NotifyIconDataFlags.Tip;
   626 					data.Tip = text;
   627 
   628 					if (showNotifyIcon && icon != null)
   629 					{
   630 						if (!created)
   631 						{
   632 							int i = 0;
   633 							do
   634 							{
   635 								created = NativeMethods.Shell_NotifyIcon(
   636 								  NativeMethods.NotifyIconMessage.Add, data);
   637 								if (!created)
   638 								{
   639 									System.Threading.Thread.Sleep(200);
   640 									i++;
   641 								}
   642 							} while (!created && i < 40);
   643 						}
   644 						else
   645 						{
   646 							NativeMethods.Shell_NotifyIcon(
   647 							  NativeMethods.NotifyIconMessage.Modify, data);
   648 						}
   649 					}
   650 					else
   651 					{
   652 						if (created)
   653 						{
   654 							int i = 0;
   655 							bool deleted = false;
   656 							do
   657 							{
   658 								deleted = NativeMethods.Shell_NotifyIcon(
   659 								  NativeMethods.NotifyIconMessage.Delete, data);
   660 								if (!deleted)
   661 								{
   662 									System.Threading.Thread.Sleep(200);
   663 									i++;
   664 								}
   665 							} while (!deleted && i < 40);
   666 							created = false;
   667 						}
   668 					}
   669 				}
   670 			}
   671 
   672 			private void ProcessMouseDown(ref Message message, MouseButtons button,
   673 			  bool doubleClick)
   674 			{
   675 				if (doubleClick)
   676 				{
   677 					if (DoubleClick != null)
   678 						DoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
   679 
   680 					if (MouseDoubleClick != null)
   681 						MouseDoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
   682 
   683 					doubleClickDown = true;
   684 				}
   685 
   686 				if (MouseDown != null)
   687 					MouseDown(this,
   688 					  new MouseEventArgs(button, doubleClick ? 2 : 1, 0, 0, 0));
   689 			}
   690 
   691 			private void ProcessMouseUp(ref Message message, MouseButtons button)
   692 			{
   693 				if (MouseUp != null)
   694 					MouseUp(this, new MouseEventArgs(button, 0, 0, 0, 0));
   695 
   696 				if (!doubleClickDown)
   697 				{
   698 					if (Click != null)
   699 						Click(this, new MouseEventArgs(button, 0, 0, 0, 0));
   700 
   701 					if (MouseClick != null)
   702 						MouseClick(this, new MouseEventArgs(button, 0, 0, 0, 0));
   703 				}
   704 				doubleClickDown = false;
   705 			}
   706 
   707 			private void ProcessInitMenuPopup(ref Message message)
   708 			{
   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 }))
   714 				{
   715 					return;
   716 				}
   717 				window.DefWndProc(ref message);
   718 			}
   719 
   720 			private void WndProc(ref Message message)
   721 			{
   722 				switch (message.Msg)
   723 				{
   724 					case WM_DESTROY:
   725 						UpdateNotifyIcon(false);
   726 						return;
   727 
   728 					case WM_COMMAND:
   729 						if (message.LParam != IntPtr.Zero)
   730 						{
   731 							window.DefWndProc(ref message);
   732 							return;
   733 						}
   734 						commandDispatch.Invoke(null, new object[] {
   735             message.WParam.ToInt32() & 0xFFFF });
   736 						return;
   737 
   738 					case WM_INITMENUPOPUP:
   739 						ProcessInitMenuPopup(ref message);
   740 						return;
   741 
   742 					case WM_TRAYMOUSEMESSAGE:
   743 						switch ((int)message.LParam)
   744 						{
   745 							case WM_MOUSEMOVE:
   746 								if (MouseMove != null)
   747 									MouseMove(this,
   748 									  new MouseEventArgs(Control.MouseButtons, 0, 0, 0, 0));
   749 								return;
   750 
   751 							case WM_LBUTTONDOWN:
   752 								ProcessMouseDown(ref message, MouseButtons.Left, false);
   753 								return;
   754 
   755 							case WM_LBUTTONUP:
   756 								ProcessMouseUp(ref message, MouseButtons.Left);
   757 								return;
   758 
   759 							case WM_LBUTTONDBLCLK:
   760 								ProcessMouseDown(ref message, MouseButtons.Left, true);
   761 								return;
   762 
   763 							case WM_RBUTTONDOWN:
   764 								ProcessMouseDown(ref message, MouseButtons.Right, false);
   765 								return;
   766 
   767 							case WM_RBUTTONUP:
   768 								if (ContextMenu != null || ContextMenuStrip != null)
   769 									ShowContextMenu();
   770 								ProcessMouseUp(ref message, MouseButtons.Right);
   771 								return;
   772 
   773 							case WM_RBUTTONDBLCLK:
   774 								ProcessMouseDown(ref message, MouseButtons.Right, true);
   775 								return;
   776 
   777 							case WM_MBUTTONDOWN:
   778 								ProcessMouseDown(ref message, MouseButtons.Middle, false);
   779 								return;
   780 
   781 							case WM_MBUTTONUP:
   782 								ProcessMouseUp(ref message, MouseButtons.Middle);
   783 								return;
   784 
   785 							case WM_MBUTTONDBLCLK:
   786 								ProcessMouseDown(ref message, MouseButtons.Middle, true);
   787 								return;
   788 
   789 							case NIN_BALLOONSHOW:
   790 								if (BalloonTipShown != null)
   791 									BalloonTipShown(this, EventArgs.Empty);
   792 								return;
   793 
   794 							case NIN_BALLOONHIDE:
   795 							case NIN_BALLOONTIMEOUT:
   796 								if (BalloonTipClosed != null)
   797 									BalloonTipClosed(this, EventArgs.Empty);
   798 								return;
   799 
   800 							case NIN_BALLOONUSERCLICK:
   801 								if (BalloonTipClicked != null)
   802 									BalloonTipClicked(this, EventArgs.Empty);
   803 								return;
   804 
   805 							default:
   806 								return;
   807 						}
   808 				}
   809 
   810 				if (message.Msg == NotifyIconWindowsImplementation.WM_TASKBARCREATED)
   811 				{
   812 					lock (syncObj)
   813 					{
   814 						created = false;
   815 					}
   816 					UpdateNotifyIcon(visible);
   817 				}
   818 
   819 				window.DefWndProc(ref message);
   820 			}
   821 
   822 			private class NotifyIconNativeWindow : NativeWindow
   823 			{
   824 				private NotifyIconWindowsImplementation reference;
   825 				private GCHandle referenceHandle;
   826 
   827 				internal NotifyIconNativeWindow(NotifyIconWindowsImplementation component)
   828 				{
   829 					this.reference = component;
   830 				}
   831 
   832 				~NotifyIconNativeWindow()
   833 				{
   834 					if (base.Handle != IntPtr.Zero)
   835 						NativeMethods.PostMessage(
   836 						  new HandleRef(this, base.Handle), WM_CLOSE, 0, 0);
   837 				}
   838 
   839 				public void LockReference(bool locked)
   840 				{
   841 					if (locked)
   842 					{
   843 						if (!referenceHandle.IsAllocated)
   844 						{
   845 							referenceHandle = GCHandle.Alloc(reference, GCHandleType.Normal);
   846 							return;
   847 						}
   848 					}
   849 					else
   850 					{
   851 						if (referenceHandle.IsAllocated)
   852 							referenceHandle.Free();
   853 					}
   854 				}
   855 
   856 				protected override void OnThreadException(Exception e)
   857 				{
   858 					Application.OnThreadException(e);
   859 				}
   860 
   861 				protected override void WndProc(ref Message m)
   862 				{
   863 					reference.WndProc(ref m);
   864 				}
   865 			}
   866 
   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;
   883 
   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;
   888 
   889 			private static int WM_TASKBARCREATED =
   890 			  NativeMethods.RegisterWindowMessage("TaskbarCreated");
   891 
   892 			private static class NativeMethods
   893 			{
   894 				[DllImport("user32.dll", CharSet = CharSet.Auto)]
   895 				public static extern IntPtr PostMessage(HandleRef hwnd, int msg,
   896 				  int wparam, int lparam);
   897 
   898 				[DllImport("user32.dll", CharSet = CharSet.Auto)]
   899 				public static extern int RegisterWindowMessage(string msg);
   900 
   901 				[Flags]
   902 				public enum NotifyIconDataFlags : int
   903 				{
   904 					Message = 0x1,
   905 					Icon = 0x2,
   906 					Tip = 0x4,
   907 					State = 0x8,
   908 					Info = 0x10
   909 				}
   910 
   911 				[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
   912 				public class NotifyIconData
   913 				{
   914 					private int Size = Marshal.SizeOf(typeof(NotifyIconData));
   915 					public IntPtr Window;
   916 					public int ID;
   917 					public NotifyIconDataFlags Flags;
   918 					public int CallbackMessage;
   919 					public IntPtr Icon;
   920 
   921 					[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
   922 					public string Tip;
   923 
   924 					public int State;
   925 					public int StateMask;
   926 
   927 					[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
   928 					public string Info;
   929 
   930 					public int TimeoutOrVersion;
   931 
   932 					[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
   933 					public string InfoTitle;
   934 
   935 					public int InfoFlags;
   936 				}
   937 
   938 				public enum NotifyIconMessage : int
   939 				{
   940 					Add = 0x0,
   941 					Modify = 0x1,
   942 					Delete = 0x2
   943 				}
   944 
   945 				[DllImport("shell32.dll", CharSet = CharSet.Auto)]
   946 				[return: MarshalAs(UnmanagedType.Bool)]
   947 				public static extern bool Shell_NotifyIcon(NotifyIconMessage message,
   948 				  NotifyIconData pnid);
   949 
   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);
   953 
   954 				[StructLayout(LayoutKind.Sequential)]
   955 				public struct Point
   956 				{
   957 					public int x;
   958 					public int y;
   959 				}
   960 
   961 				[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
   962 				public static extern bool GetCursorPos(ref Point point);
   963 
   964 				[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
   965 				public static extern bool SetForegroundWindow(HandleRef hWnd);
   966 			}
   967 		}
   968 	}
   969 }