GUI/NotifyIconAdv.cs
author moel.mich
Tue, 30 Dec 2014 22:47:39 +0000
changeset 431 0e46e3ca812a
parent 363 daa9590e1bee
permissions -rw-r--r--
Fixed the following issue (present only on 32-bit systems):

Version: 0.7.0.0

System.NullReferenceException: Object reference not set to an instance of an object.
at OpenHardwareMonitor.GUI.MainForm.timer_Tick(Object sender, EventArgs e)
at System.Windows.Forms.Timer.OnTick(EventArgs e)
at System.Windows.Forms.Timer.TimerNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Common Language Runtime: 4.0.30319.18444
Operating System: Microsoft Windows NT 6.1.7601 Service Pack 1
Process Type: 32-Bit
     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.Runtime.InteropServices;
    15 using System.Reflection;
    16 using System.Windows.Forms;
    17 
    18 namespace OpenHardwareMonitor.GUI {
    19 
    20   public class NotifyIconAdv : IDisposable {
    21 
    22     private NotifyIcon genericNotifyIcon;
    23     private NotifyIconWindowsImplementation windowsNotifyIcon;
    24 
    25     public NotifyIconAdv() {
    26       int p = (int)Environment.OSVersion.Platform;
    27       if ((p == 4) || (p == 128)) { // Unix
    28         genericNotifyIcon = new NotifyIcon();
    29       } else { // Windows
    30         windowsNotifyIcon = new NotifyIconWindowsImplementation();
    31       }
    32     }
    33 
    34     public event EventHandler BalloonTipClicked {
    35       add {
    36         if (genericNotifyIcon != null)
    37           genericNotifyIcon.BalloonTipClicked += value;
    38         else
    39           windowsNotifyIcon.BalloonTipClicked += value;
    40       }
    41       remove {
    42         if (genericNotifyIcon != null)
    43           genericNotifyIcon.BalloonTipClicked -= value;
    44         else
    45           windowsNotifyIcon.BalloonTipClicked -= value;
    46       }
    47     }
    48 
    49     public event EventHandler BalloonTipClosed {
    50       add {
    51         if (genericNotifyIcon != null)
    52           genericNotifyIcon.BalloonTipClosed += value;
    53         else
    54           windowsNotifyIcon.BalloonTipClosed += value;
    55       }
    56       remove {
    57         if (genericNotifyIcon != null)
    58           genericNotifyIcon.BalloonTipClosed -= value;
    59         else
    60           windowsNotifyIcon.BalloonTipClosed -= value;
    61       }
    62     }
    63 
    64     public event EventHandler BalloonTipShown {
    65       add {
    66         if (genericNotifyIcon != null)
    67           genericNotifyIcon.BalloonTipShown += value;
    68         else
    69           windowsNotifyIcon.BalloonTipShown += value;
    70       }
    71       remove {
    72         if (genericNotifyIcon != null)
    73           genericNotifyIcon.BalloonTipShown -= value;
    74         else
    75           windowsNotifyIcon.BalloonTipShown -= value;
    76       }
    77     }
    78 
    79     public event EventHandler Click {
    80       add {
    81         if (genericNotifyIcon != null)
    82           genericNotifyIcon.Click += value;
    83         else
    84           windowsNotifyIcon.Click += value;
    85       }
    86       remove {
    87         if (genericNotifyIcon != null)
    88           genericNotifyIcon.Click -= value;
    89         else
    90           windowsNotifyIcon.Click -= value;
    91       }
    92     }
    93 
    94     public event EventHandler DoubleClick {
    95       add {
    96         if (genericNotifyIcon != null)
    97           genericNotifyIcon.DoubleClick += value;
    98         else
    99           windowsNotifyIcon.DoubleClick += value;
   100       }
   101       remove {
   102         if (genericNotifyIcon != null)
   103           genericNotifyIcon.DoubleClick -= value;
   104         else
   105           windowsNotifyIcon.DoubleClick -= value;
   106       }
   107     }
   108 
   109     public event MouseEventHandler MouseClick {
   110       add {
   111         if (genericNotifyIcon != null)
   112           genericNotifyIcon.MouseClick += value;
   113         else
   114           windowsNotifyIcon.MouseClick += value;
   115       }
   116       remove {
   117         if (genericNotifyIcon != null)
   118           genericNotifyIcon.MouseClick -= value;
   119         else
   120           windowsNotifyIcon.MouseClick -= value;
   121       }
   122     }
   123 
   124     public event MouseEventHandler MouseDoubleClick {
   125       add {
   126         if (genericNotifyIcon != null)
   127           genericNotifyIcon.MouseDoubleClick += value;
   128         else
   129           windowsNotifyIcon.MouseDoubleClick += value;
   130       }
   131       remove {
   132         if (genericNotifyIcon != null)
   133           genericNotifyIcon.MouseDoubleClick -= value;
   134         else
   135           windowsNotifyIcon.MouseDoubleClick -= value;
   136       }
   137     }
   138 
   139     public event MouseEventHandler MouseDown {
   140       add {
   141         if (genericNotifyIcon != null)
   142           genericNotifyIcon.MouseDown += value;
   143         else
   144           windowsNotifyIcon.MouseDown += value;
   145       }
   146       remove {
   147         if (genericNotifyIcon != null)
   148           genericNotifyIcon.MouseDown -= value;
   149         else
   150           windowsNotifyIcon.MouseDown -= value;
   151       }
   152     }
   153 
   154     public event MouseEventHandler MouseMove {
   155       add {
   156         if (genericNotifyIcon != null)
   157           genericNotifyIcon.MouseMove += value;
   158         else
   159           windowsNotifyIcon.MouseMove += value;
   160       }
   161       remove {
   162         if (genericNotifyIcon != null)
   163           genericNotifyIcon.MouseMove -= value;
   164         else
   165           windowsNotifyIcon.MouseMove -= value;
   166       }
   167     }
   168 
   169     public event MouseEventHandler MouseUp {
   170       add {
   171         if (genericNotifyIcon != null)
   172           genericNotifyIcon.MouseUp += value;
   173         else
   174           windowsNotifyIcon.MouseUp += value;
   175       }
   176       remove {
   177         if (genericNotifyIcon != null)
   178           genericNotifyIcon.MouseUp -= value;
   179         else
   180           windowsNotifyIcon.MouseUp -= value;
   181       }
   182     }
   183 
   184     public string BalloonTipText {
   185       get {
   186         if (genericNotifyIcon != null)
   187           return genericNotifyIcon.BalloonTipText;
   188         else
   189           return windowsNotifyIcon.BalloonTipText;
   190       }
   191       set {
   192         if (genericNotifyIcon != null)
   193           genericNotifyIcon.BalloonTipText = value;
   194         else
   195           windowsNotifyIcon.BalloonTipText = value;
   196       }
   197     }
   198 
   199     public ToolTipIcon BalloonTipIcon {
   200       get {
   201         if (genericNotifyIcon != null)
   202           return genericNotifyIcon.BalloonTipIcon;
   203         else
   204           return windowsNotifyIcon.BalloonTipIcon;
   205       }
   206       set {
   207         if (genericNotifyIcon != null)
   208           genericNotifyIcon.BalloonTipIcon = value;
   209         else
   210           windowsNotifyIcon.BalloonTipIcon = value;
   211       }
   212     }
   213 
   214     public string BalloonTipTitle {
   215       get {
   216         if (genericNotifyIcon != null)
   217           return genericNotifyIcon.BalloonTipTitle;
   218         else
   219           return windowsNotifyIcon.BalloonTipTitle;
   220       }
   221       set {
   222         if (genericNotifyIcon != null)
   223           genericNotifyIcon.BalloonTipTitle = value;
   224         else
   225           windowsNotifyIcon.BalloonTipTitle = value;
   226       }
   227     }
   228 
   229     public ContextMenu ContextMenu {
   230       get {
   231         if (genericNotifyIcon != null)
   232           return genericNotifyIcon.ContextMenu;
   233         else
   234           return windowsNotifyIcon.ContextMenu;
   235       }
   236       set {
   237         if (genericNotifyIcon != null)
   238           genericNotifyIcon.ContextMenu = value;
   239         else
   240           windowsNotifyIcon.ContextMenu = value;
   241       }
   242     }
   243 
   244     public ContextMenuStrip ContextMenuStrip {
   245       get {
   246         if (genericNotifyIcon != null)
   247           return genericNotifyIcon.ContextMenuStrip;
   248         else
   249           return windowsNotifyIcon.ContextMenuStrip;
   250       }
   251       set {
   252         if (genericNotifyIcon != null)
   253           genericNotifyIcon.ContextMenuStrip = value;
   254         else
   255           windowsNotifyIcon.ContextMenuStrip = value;
   256       }
   257     }
   258 
   259     public object Tag { get; set; }
   260 
   261     public Icon Icon {
   262       get {
   263         if (genericNotifyIcon != null)
   264           return genericNotifyIcon.Icon;
   265         else
   266           return windowsNotifyIcon.Icon;
   267       }
   268       set {
   269         if (genericNotifyIcon != null)
   270           genericNotifyIcon.Icon = value;
   271         else
   272           windowsNotifyIcon.Icon = value;
   273       }
   274     }
   275 
   276     public string Text {
   277       get {
   278         if (genericNotifyIcon != null)
   279           return genericNotifyIcon.Text;
   280         else
   281           return windowsNotifyIcon.Text;
   282       }
   283       set {
   284         if (genericNotifyIcon != null)
   285           genericNotifyIcon.Text = value;
   286         else
   287           windowsNotifyIcon.Text = value;
   288       }
   289     }
   290 
   291     public bool Visible {
   292       get {
   293         if (genericNotifyIcon != null)
   294           return genericNotifyIcon.Visible;
   295         else
   296           return windowsNotifyIcon.Visible;
   297       }
   298       set {
   299         if (genericNotifyIcon != null)
   300           genericNotifyIcon.Visible = value;
   301         else
   302           windowsNotifyIcon.Visible = value;
   303       }
   304     }
   305 
   306     public void Dispose() {
   307       if (genericNotifyIcon != null)
   308         genericNotifyIcon.Dispose();
   309       else
   310         windowsNotifyIcon.Dispose();
   311     }
   312 
   313     public void ShowBalloonTip(int timeout) {
   314       ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
   315     }
   316 
   317     public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
   318       ToolTipIcon tipIcon) {
   319       if (genericNotifyIcon != null)
   320         genericNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
   321       else
   322         windowsNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
   323     }
   324     
   325     private class NotifyIconWindowsImplementation : Component {
   326 
   327       private static int nextId = 0;
   328 
   329       private object syncObj = new object();
   330       private Icon icon;
   331       private string text = "";
   332       private int id;
   333       private bool created;
   334       private NotifyIconNativeWindow window;
   335       private bool doubleClickDown;
   336       private bool visible;
   337       private MethodInfo commandDispatch;
   338 
   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;
   349 
   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; }
   356 
   357       public Icon Icon {
   358         get {
   359           return icon;
   360         }
   361         set {
   362           if (icon != value) {
   363             icon = value;
   364             UpdateNotifyIcon(visible);
   365           }
   366         }
   367       }
   368 
   369       public string Text {
   370         get {
   371           return text;
   372         }
   373         set {
   374           if (value == null)
   375             value = "";
   376 
   377           if (value.Length > 63)
   378             throw new ArgumentOutOfRangeException();
   379 
   380           if (!value.Equals(text)) {
   381             text = value;
   382 
   383             if (visible)
   384               UpdateNotifyIcon(visible);
   385           }
   386         }
   387       }
   388 
   389       public bool Visible {
   390         get {
   391           return visible;
   392         }
   393         set {
   394           if (visible != value) {
   395             visible = value;
   396             UpdateNotifyIcon(visible);
   397           }
   398         }
   399       }
   400 
   401       public NotifyIconWindowsImplementation() {
   402         BalloonTipText = "";
   403         BalloonTipTitle = "";
   404 
   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);
   409 
   410         id = ++NotifyIconWindowsImplementation.nextId;
   411         window = new NotifyIconNativeWindow(this);
   412         UpdateNotifyIcon(visible);
   413       }
   414 
   415       protected override void Dispose(bool disposing) {
   416         if (disposing) {
   417           if (window != null) {
   418             icon = null;
   419             text = "";
   420             UpdateNotifyIcon(false);
   421             window.DestroyHandle();
   422             window = null;
   423             ContextMenu = null;
   424             ContextMenuStrip = null;
   425           }
   426         } else {
   427           if (window != null && window.Handle != IntPtr.Zero) {
   428             NativeMethods.PostMessage(
   429               new HandleRef(window, window.Handle), WM_CLOSE, 0, 0);
   430             window.ReleaseHandle();
   431           }
   432         }
   433         base.Dispose(disposing);
   434       }
   435 
   436       public void ShowBalloonTip(int timeout) {
   437         ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
   438       }
   439 
   440       public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
   441         ToolTipIcon tipIcon) {
   442         if (timeout < 0)
   443           throw new ArgumentOutOfRangeException("timeout");
   444 
   445         if (string.IsNullOrEmpty(tipText))
   446           throw new ArgumentException("tipText");
   447 
   448         if (DesignMode)
   449           return;
   450 
   451         if (created) {
   452           NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
   453           if (window.Handle == IntPtr.Zero)
   454             window.CreateHandle(new CreateParams());
   455 
   456           data.Window = window.Handle;
   457           data.ID = id;
   458           data.Flags = NativeMethods.NotifyIconDataFlags.Info;
   459           data.TimeoutOrVersion = timeout;
   460           data.InfoTitle = tipTitle;
   461           data.Info = tipText;
   462           data.InfoFlags = (int)tipIcon;
   463 
   464           NativeMethods.Shell_NotifyIcon(
   465             NativeMethods.NotifyIconMessage.Modify, data);
   466         }
   467       }
   468 
   469       private void ShowContextMenu() {
   470         if (ContextMenu == null && ContextMenuStrip == null)
   471           return;
   472 
   473         NativeMethods.Point p = new NativeMethods.Point();
   474         NativeMethods.GetCursorPos(ref p);
   475         NativeMethods.SetForegroundWindow(
   476           new HandleRef(window, window.Handle));
   477 
   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 });
   483 
   484           NativeMethods.TrackPopupMenuEx(
   485             new HandleRef(ContextMenu, ContextMenu.Handle), 72,
   486             p.x, p.y, new HandleRef(window, window.Handle),
   487             IntPtr.Zero);
   488 
   489           NativeMethods.PostMessage(
   490             new HandleRef(window, window.Handle), WM_NULL, 0, 0);
   491           return;
   492         }
   493 
   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 });
   499       }
   500 
   501       private void UpdateNotifyIcon(bool showNotifyIcon) {
   502         if (DesignMode)
   503           return;
   504 
   505         lock (syncObj) {
   506           window.LockReference(showNotifyIcon);
   507 
   508           NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
   509           data.CallbackMessage = WM_TRAYMOUSEMESSAGE;
   510           data.Flags = NativeMethods.NotifyIconDataFlags.Message;
   511 
   512           if (showNotifyIcon && window.Handle == IntPtr.Zero)
   513             window.CreateHandle(new CreateParams());
   514 
   515           data.Window = window.Handle;
   516           data.ID = id;
   517 
   518           if (icon != null) {
   519             data.Flags |= NativeMethods.NotifyIconDataFlags.Icon;
   520             data.Icon = icon.Handle;
   521           }
   522 
   523           data.Flags |= NativeMethods.NotifyIconDataFlags.Tip;
   524           data.Tip = text;
   525 
   526           if (showNotifyIcon && icon != null) {
   527             if (!created) {
   528               int i = 0;
   529               do {
   530                 created = NativeMethods.Shell_NotifyIcon(
   531                   NativeMethods.NotifyIconMessage.Add, data);
   532                 if (!created) {
   533                   System.Threading.Thread.Sleep(200);
   534                   i++;
   535                 }
   536               } while (!created && i < 40);
   537             } else {
   538               NativeMethods.Shell_NotifyIcon(
   539                 NativeMethods.NotifyIconMessage.Modify, data);
   540             }
   541           } else {
   542             if (created) {
   543               int i = 0;
   544               bool deleted = false;
   545               do {
   546                 deleted = NativeMethods.Shell_NotifyIcon(
   547                   NativeMethods.NotifyIconMessage.Delete, data);
   548                 if (!deleted) {
   549                   System.Threading.Thread.Sleep(200);
   550                   i++;
   551                 }
   552               } while (!deleted && i < 40);
   553               created = false;
   554             }
   555           }
   556         }
   557       }
   558 
   559       private void ProcessMouseDown(ref Message message, MouseButtons button,
   560         bool doubleClick) {
   561         if (doubleClick) {
   562           if (DoubleClick != null)
   563             DoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
   564 
   565           if (MouseDoubleClick != null)
   566             MouseDoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
   567 
   568           doubleClickDown = true;
   569         }
   570 
   571         if (MouseDown != null)
   572           MouseDown(this,
   573             new MouseEventArgs(button, doubleClick ? 2 : 1, 0, 0, 0));
   574       }
   575 
   576       private void ProcessMouseUp(ref Message message, MouseButtons button) {
   577         if (MouseUp != null)
   578           MouseUp(this, new MouseEventArgs(button, 0, 0, 0, 0));
   579 
   580         if (!doubleClickDown) {
   581           if (Click != null)
   582             Click(this, new MouseEventArgs(button, 0, 0, 0, 0));
   583 
   584           if (MouseClick != null)
   585             MouseClick(this, new MouseEventArgs(button, 0, 0, 0, 0));
   586         }
   587         doubleClickDown = false;
   588       }
   589 
   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 })) {
   596           return;
   597         }
   598         window.DefWndProc(ref message);
   599       }
   600 
   601       private void WndProc(ref Message message) {
   602         switch (message.Msg) {
   603           case WM_DESTROY:
   604             UpdateNotifyIcon(false);
   605             return;
   606           case WM_COMMAND:
   607             if (message.LParam != IntPtr.Zero) {
   608               window.DefWndProc(ref message);
   609               return;
   610             }
   611             commandDispatch.Invoke(null, new object[] { 
   612             message.WParam.ToInt32() & 0xFFFF });
   613             return;
   614           case WM_INITMENUPOPUP:
   615             ProcessInitMenuPopup(ref message);
   616             return;
   617           case WM_TRAYMOUSEMESSAGE:
   618             switch ((int)message.LParam) {
   619               case WM_MOUSEMOVE:
   620                 if (MouseMove != null)
   621                   MouseMove(this,
   622                     new MouseEventArgs(Control.MouseButtons, 0, 0, 0, 0));
   623                 return;
   624               case WM_LBUTTONDOWN:
   625                 ProcessMouseDown(ref message, MouseButtons.Left, false);
   626                 return;
   627               case WM_LBUTTONUP:
   628                 ProcessMouseUp(ref message, MouseButtons.Left);
   629                 return;
   630               case WM_LBUTTONDBLCLK:
   631                 ProcessMouseDown(ref message, MouseButtons.Left, true);
   632                 return;
   633               case WM_RBUTTONDOWN:
   634                 ProcessMouseDown(ref message, MouseButtons.Right, false);
   635                 return;
   636               case WM_RBUTTONUP:
   637                 if (ContextMenu != null || ContextMenuStrip != null)
   638                   ShowContextMenu();
   639                 ProcessMouseUp(ref message, MouseButtons.Right);
   640                 return;
   641               case WM_RBUTTONDBLCLK:
   642                 ProcessMouseDown(ref message, MouseButtons.Right, true);
   643                 return;
   644               case WM_MBUTTONDOWN:
   645                 ProcessMouseDown(ref message, MouseButtons.Middle, false);
   646                 return;
   647               case WM_MBUTTONUP:
   648                 ProcessMouseUp(ref message, MouseButtons.Middle);
   649                 return;
   650               case WM_MBUTTONDBLCLK:
   651                 ProcessMouseDown(ref message, MouseButtons.Middle, true);
   652                 return;
   653               case NIN_BALLOONSHOW:
   654                 if (BalloonTipShown != null)
   655                   BalloonTipShown(this, EventArgs.Empty);
   656                 return;
   657               case NIN_BALLOONHIDE:
   658               case NIN_BALLOONTIMEOUT:
   659                 if (BalloonTipClosed != null)
   660                   BalloonTipClosed(this, EventArgs.Empty);
   661                 return;
   662               case NIN_BALLOONUSERCLICK:
   663                 if (BalloonTipClicked != null)
   664                   BalloonTipClicked(this, EventArgs.Empty);
   665                 return;
   666               default:
   667                 return;
   668             }
   669         }
   670 
   671         if (message.Msg == NotifyIconWindowsImplementation.WM_TASKBARCREATED) {
   672           lock (syncObj) {
   673             created = false;
   674           }
   675           UpdateNotifyIcon(visible);
   676         }
   677 
   678         window.DefWndProc(ref message);
   679       }
   680 
   681       private class NotifyIconNativeWindow : NativeWindow {
   682         private NotifyIconWindowsImplementation reference;
   683         private GCHandle referenceHandle;
   684 
   685         internal NotifyIconNativeWindow(NotifyIconWindowsImplementation component) {
   686           this.reference = component;
   687         }
   688 
   689         ~NotifyIconNativeWindow() {
   690           if (base.Handle != IntPtr.Zero)
   691             NativeMethods.PostMessage(
   692               new HandleRef(this, base.Handle), WM_CLOSE, 0, 0);
   693         }
   694 
   695         public void LockReference(bool locked) {
   696           if (locked) {
   697             if (!referenceHandle.IsAllocated) {
   698               referenceHandle = GCHandle.Alloc(reference, GCHandleType.Normal);
   699               return;
   700             }
   701           } else {
   702             if (referenceHandle.IsAllocated)
   703               referenceHandle.Free();
   704           }
   705         }
   706 
   707         protected override void OnThreadException(Exception e) {
   708           Application.OnThreadException(e);
   709         }
   710 
   711         protected override void WndProc(ref Message m) {
   712           reference.WndProc(ref m);
   713         }
   714       }
   715 
   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;
   732 
   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;
   737 
   738       private static int WM_TASKBARCREATED =
   739         NativeMethods.RegisterWindowMessage("TaskbarCreated");
   740 
   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);
   745 
   746         [DllImport("user32.dll", CharSet = CharSet.Auto)]
   747         public static extern int RegisterWindowMessage(string msg);
   748 
   749         [Flags]
   750         public enum NotifyIconDataFlags : int {
   751           Message = 0x1,
   752           Icon = 0x2,
   753           Tip = 0x4,
   754           State = 0x8,
   755           Info = 0x10
   756         }
   757 
   758         [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
   759         public class NotifyIconData {
   760           private int Size = Marshal.SizeOf(typeof(NotifyIconData));
   761           public IntPtr Window;
   762           public int ID;
   763           public NotifyIconDataFlags Flags;
   764           public int CallbackMessage;
   765           public IntPtr Icon;
   766           [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
   767           public string Tip;
   768           public int State;
   769           public int StateMask;
   770           [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
   771           public string Info;
   772           public int TimeoutOrVersion;
   773           [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
   774           public string InfoTitle;
   775           public int InfoFlags;
   776         }
   777 
   778         public enum NotifyIconMessage : int {
   779           Add = 0x0,
   780           Modify = 0x1,
   781           Delete = 0x2
   782         }
   783 
   784         [DllImport("shell32.dll", CharSet = CharSet.Auto)]
   785         [return: MarshalAs(UnmanagedType.Bool)]
   786         public static extern bool Shell_NotifyIcon(NotifyIconMessage message,
   787           NotifyIconData pnid);
   788 
   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);
   792 
   793         [StructLayout(LayoutKind.Sequential)]
   794         public struct Point {
   795           public int x;
   796           public int y;
   797         }
   798 
   799         [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
   800         public static extern bool GetCursorPos(ref Point point);
   801 
   802         [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
   803         public static extern bool SetForegroundWindow(HandleRef hWnd);
   804       }
   805     }
   806   }
   807 }