GUI/NotifyIconAdv.cs
changeset 371 c1a0d321e646
parent 363 daa9590e1bee
     1.1 --- a/GUI/NotifyIconAdv.cs	Mon Jul 23 21:54:35 2012 +0000
     1.2 +++ b/GUI/NotifyIconAdv.cs	Tue Jul 24 16:04:30 2012 +0000
     1.3 @@ -16,115 +16,298 @@
     1.4  using System.Windows.Forms;
     1.5  
     1.6  namespace OpenHardwareMonitor.GUI {
     1.7 -  public class NotifyIconAdv : Component {
     1.8  
     1.9 -    private static int nextId = 0;
    1.10 +  public class NotifyIconAdv : IDisposable {
    1.11  
    1.12 -    private object syncObj = new object();
    1.13 -    private Icon icon;
    1.14 -    private string text = "";
    1.15 -    private int id;
    1.16 -    private bool created;
    1.17 -    private NotifyIconNativeWindow window;
    1.18 -    private bool doubleClickDown;
    1.19 -    private bool visible;
    1.20 -    private MethodInfo commandDispatch;
    1.21 +    private NotifyIcon genericNotifyIcon;
    1.22 +    private NotifyIconWindowsImplementation windowsNotifyIcon;
    1.23  
    1.24 -    public event EventHandler BalloonTipClicked;
    1.25 -    public event EventHandler BalloonTipClosed;
    1.26 -    public event EventHandler BalloonTipShown;
    1.27 -    public event EventHandler Click;
    1.28 -    public event EventHandler DoubleClick;
    1.29 -    public event MouseEventHandler MouseClick;
    1.30 -    public event MouseEventHandler MouseDoubleClick;
    1.31 -    public event MouseEventHandler MouseDown;
    1.32 -    public event MouseEventHandler MouseMove;
    1.33 -    public event MouseEventHandler MouseUp;
    1.34 +    public NotifyIconAdv() {
    1.35 +      int p = (int)Environment.OSVersion.Platform;
    1.36 +      if ((p == 4) || (p == 128)) { // Unix
    1.37 +        genericNotifyIcon = new NotifyIcon();
    1.38 +      } else { // Windows
    1.39 +        windowsNotifyIcon = new NotifyIconWindowsImplementation();
    1.40 +      }
    1.41 +    }
    1.42  
    1.43 -    public string BalloonTipText { get; set; }
    1.44 -    public ToolTipIcon BalloonTipIcon { get; set; }
    1.45 -    public string BalloonTipTitle { get; set; }
    1.46 -    public ContextMenu ContextMenu { get; set; }
    1.47 -    public ContextMenuStrip ContextMenuStrip { get; set; }
    1.48 +    public event EventHandler BalloonTipClicked {
    1.49 +      add {
    1.50 +        if (genericNotifyIcon != null)
    1.51 +          genericNotifyIcon.BalloonTipClicked += value;
    1.52 +        else
    1.53 +          windowsNotifyIcon.BalloonTipClicked += value;
    1.54 +      }
    1.55 +      remove {
    1.56 +        if (genericNotifyIcon != null)
    1.57 +          genericNotifyIcon.BalloonTipClicked -= value;
    1.58 +        else
    1.59 +          windowsNotifyIcon.BalloonTipClicked -= value;
    1.60 +      }
    1.61 +    }
    1.62 +
    1.63 +    public event EventHandler BalloonTipClosed {
    1.64 +      add {
    1.65 +        if (genericNotifyIcon != null)
    1.66 +          genericNotifyIcon.BalloonTipClosed += value;
    1.67 +        else
    1.68 +          windowsNotifyIcon.BalloonTipClosed += value;
    1.69 +      }
    1.70 +      remove {
    1.71 +        if (genericNotifyIcon != null)
    1.72 +          genericNotifyIcon.BalloonTipClosed -= value;
    1.73 +        else
    1.74 +          windowsNotifyIcon.BalloonTipClosed -= value;
    1.75 +      }
    1.76 +    }
    1.77 +
    1.78 +    public event EventHandler BalloonTipShown {
    1.79 +      add {
    1.80 +        if (genericNotifyIcon != null)
    1.81 +          genericNotifyIcon.BalloonTipShown += value;
    1.82 +        else
    1.83 +          windowsNotifyIcon.BalloonTipShown += value;
    1.84 +      }
    1.85 +      remove {
    1.86 +        if (genericNotifyIcon != null)
    1.87 +          genericNotifyIcon.BalloonTipShown -= value;
    1.88 +        else
    1.89 +          windowsNotifyIcon.BalloonTipShown -= value;
    1.90 +      }
    1.91 +    }
    1.92 +
    1.93 +    public event EventHandler Click {
    1.94 +      add {
    1.95 +        if (genericNotifyIcon != null)
    1.96 +          genericNotifyIcon.Click += value;
    1.97 +        else
    1.98 +          windowsNotifyIcon.Click += value;
    1.99 +      }
   1.100 +      remove {
   1.101 +        if (genericNotifyIcon != null)
   1.102 +          genericNotifyIcon.Click -= value;
   1.103 +        else
   1.104 +          windowsNotifyIcon.Click -= value;
   1.105 +      }
   1.106 +    }
   1.107 +
   1.108 +    public event EventHandler DoubleClick {
   1.109 +      add {
   1.110 +        if (genericNotifyIcon != null)
   1.111 +          genericNotifyIcon.DoubleClick += value;
   1.112 +        else
   1.113 +          windowsNotifyIcon.DoubleClick += value;
   1.114 +      }
   1.115 +      remove {
   1.116 +        if (genericNotifyIcon != null)
   1.117 +          genericNotifyIcon.DoubleClick -= value;
   1.118 +        else
   1.119 +          windowsNotifyIcon.DoubleClick -= value;
   1.120 +      }
   1.121 +    }
   1.122 +
   1.123 +    public event MouseEventHandler MouseClick {
   1.124 +      add {
   1.125 +        if (genericNotifyIcon != null)
   1.126 +          genericNotifyIcon.MouseClick += value;
   1.127 +        else
   1.128 +          windowsNotifyIcon.MouseClick += value;
   1.129 +      }
   1.130 +      remove {
   1.131 +        if (genericNotifyIcon != null)
   1.132 +          genericNotifyIcon.MouseClick -= value;
   1.133 +        else
   1.134 +          windowsNotifyIcon.MouseClick -= value;
   1.135 +      }
   1.136 +    }
   1.137 +
   1.138 +    public event MouseEventHandler MouseDoubleClick {
   1.139 +      add {
   1.140 +        if (genericNotifyIcon != null)
   1.141 +          genericNotifyIcon.MouseDoubleClick += value;
   1.142 +        else
   1.143 +          windowsNotifyIcon.MouseDoubleClick += value;
   1.144 +      }
   1.145 +      remove {
   1.146 +        if (genericNotifyIcon != null)
   1.147 +          genericNotifyIcon.MouseDoubleClick -= value;
   1.148 +        else
   1.149 +          windowsNotifyIcon.MouseDoubleClick -= value;
   1.150 +      }
   1.151 +    }
   1.152 +
   1.153 +    public event MouseEventHandler MouseDown {
   1.154 +      add {
   1.155 +        if (genericNotifyIcon != null)
   1.156 +          genericNotifyIcon.MouseDown += value;
   1.157 +        else
   1.158 +          windowsNotifyIcon.MouseDown += value;
   1.159 +      }
   1.160 +      remove {
   1.161 +        if (genericNotifyIcon != null)
   1.162 +          genericNotifyIcon.MouseDown -= value;
   1.163 +        else
   1.164 +          windowsNotifyIcon.MouseDown -= value;
   1.165 +      }
   1.166 +    }
   1.167 +
   1.168 +    public event MouseEventHandler MouseMove {
   1.169 +      add {
   1.170 +        if (genericNotifyIcon != null)
   1.171 +          genericNotifyIcon.MouseMove += value;
   1.172 +        else
   1.173 +          windowsNotifyIcon.MouseMove += value;
   1.174 +      }
   1.175 +      remove {
   1.176 +        if (genericNotifyIcon != null)
   1.177 +          genericNotifyIcon.MouseMove -= value;
   1.178 +        else
   1.179 +          windowsNotifyIcon.MouseMove -= value;
   1.180 +      }
   1.181 +    }
   1.182 +
   1.183 +    public event MouseEventHandler MouseUp {
   1.184 +      add {
   1.185 +        if (genericNotifyIcon != null)
   1.186 +          genericNotifyIcon.MouseUp += value;
   1.187 +        else
   1.188 +          windowsNotifyIcon.MouseUp += value;
   1.189 +      }
   1.190 +      remove {
   1.191 +        if (genericNotifyIcon != null)
   1.192 +          genericNotifyIcon.MouseUp -= value;
   1.193 +        else
   1.194 +          windowsNotifyIcon.MouseUp -= value;
   1.195 +      }
   1.196 +    }
   1.197 +
   1.198 +    public string BalloonTipText {
   1.199 +      get {
   1.200 +        if (genericNotifyIcon != null)
   1.201 +          return genericNotifyIcon.BalloonTipText;
   1.202 +        else
   1.203 +          return windowsNotifyIcon.BalloonTipText;
   1.204 +      }
   1.205 +      set {
   1.206 +        if (genericNotifyIcon != null)
   1.207 +          genericNotifyIcon.BalloonTipText = value;
   1.208 +        else
   1.209 +          windowsNotifyIcon.BalloonTipText = value;
   1.210 +      }
   1.211 +    }
   1.212 +
   1.213 +    public ToolTipIcon BalloonTipIcon {
   1.214 +      get {
   1.215 +        if (genericNotifyIcon != null)
   1.216 +          return genericNotifyIcon.BalloonTipIcon;
   1.217 +        else
   1.218 +          return windowsNotifyIcon.BalloonTipIcon;
   1.219 +      }
   1.220 +      set {
   1.221 +        if (genericNotifyIcon != null)
   1.222 +          genericNotifyIcon.BalloonTipIcon = value;
   1.223 +        else
   1.224 +          windowsNotifyIcon.BalloonTipIcon = value;
   1.225 +      }
   1.226 +    }
   1.227 +
   1.228 +    public string BalloonTipTitle {
   1.229 +      get {
   1.230 +        if (genericNotifyIcon != null)
   1.231 +          return genericNotifyIcon.BalloonTipTitle;
   1.232 +        else
   1.233 +          return windowsNotifyIcon.BalloonTipTitle;
   1.234 +      }
   1.235 +      set {
   1.236 +        if (genericNotifyIcon != null)
   1.237 +          genericNotifyIcon.BalloonTipTitle = value;
   1.238 +        else
   1.239 +          windowsNotifyIcon.BalloonTipTitle = value;
   1.240 +      }
   1.241 +    }
   1.242 +
   1.243 +    public ContextMenu ContextMenu {
   1.244 +      get {
   1.245 +        if (genericNotifyIcon != null)
   1.246 +          return genericNotifyIcon.ContextMenu;
   1.247 +        else
   1.248 +          return windowsNotifyIcon.ContextMenu;
   1.249 +      }
   1.250 +      set {
   1.251 +        if (genericNotifyIcon != null)
   1.252 +          genericNotifyIcon.ContextMenu = value;
   1.253 +        else
   1.254 +          windowsNotifyIcon.ContextMenu = value;
   1.255 +      }
   1.256 +    }
   1.257 +
   1.258 +    public ContextMenuStrip ContextMenuStrip {
   1.259 +      get {
   1.260 +        if (genericNotifyIcon != null)
   1.261 +          return genericNotifyIcon.ContextMenuStrip;
   1.262 +        else
   1.263 +          return windowsNotifyIcon.ContextMenuStrip;
   1.264 +      }
   1.265 +      set {
   1.266 +        if (genericNotifyIcon != null)
   1.267 +          genericNotifyIcon.ContextMenuStrip = value;
   1.268 +        else
   1.269 +          windowsNotifyIcon.ContextMenuStrip = value;
   1.270 +      }
   1.271 +    }
   1.272 +
   1.273      public object Tag { get; set; }
   1.274  
   1.275      public Icon Icon {
   1.276        get {
   1.277 -        return icon;
   1.278 +        if (genericNotifyIcon != null)
   1.279 +          return genericNotifyIcon.Icon;
   1.280 +        else
   1.281 +          return windowsNotifyIcon.Icon;
   1.282        }
   1.283        set {
   1.284 -        if (icon != value) {
   1.285 -          icon = value;
   1.286 -          UpdateNotifyIcon(visible);
   1.287 -        }
   1.288 +        if (genericNotifyIcon != null)
   1.289 +          genericNotifyIcon.Icon = value;
   1.290 +        else
   1.291 +          windowsNotifyIcon.Icon = value;
   1.292        }
   1.293      }
   1.294  
   1.295      public string Text {
   1.296        get {
   1.297 -        return text;
   1.298 +        if (genericNotifyIcon != null)
   1.299 +          return genericNotifyIcon.Text;
   1.300 +        else
   1.301 +          return windowsNotifyIcon.Text;
   1.302        }
   1.303        set {
   1.304 -        if (value == null)
   1.305 -          value = "";
   1.306 -
   1.307 -        if (value.Length > 63)
   1.308 -          throw new ArgumentOutOfRangeException();
   1.309 -
   1.310 -        if (!value.Equals(text)) {
   1.311 -          text = value;
   1.312 -
   1.313 -          if (visible) 
   1.314 -            UpdateNotifyIcon(visible);          
   1.315 -        }
   1.316 +        if (genericNotifyIcon != null)
   1.317 +          genericNotifyIcon.Text = value;
   1.318 +        else
   1.319 +          windowsNotifyIcon.Text = value;
   1.320        }
   1.321      }
   1.322  
   1.323      public bool Visible {
   1.324        get {
   1.325 -        return visible;
   1.326 +        if (genericNotifyIcon != null)
   1.327 +          return genericNotifyIcon.Visible;
   1.328 +        else
   1.329 +          return windowsNotifyIcon.Visible;
   1.330        }
   1.331        set {
   1.332 -        if (visible != value) {
   1.333 -          visible = value;
   1.334 -          UpdateNotifyIcon(visible);          
   1.335 -        }
   1.336 +        if (genericNotifyIcon != null)
   1.337 +          genericNotifyIcon.Visible = value;
   1.338 +        else
   1.339 +          windowsNotifyIcon.Visible = value;
   1.340        }
   1.341      }
   1.342 -    
   1.343 -    public NotifyIconAdv() {
   1.344 -      BalloonTipText = "";
   1.345 -      BalloonTipTitle = "";
   1.346  
   1.347 -      commandDispatch = typeof(Form).Assembly.
   1.348 -        GetType("System.Windows.Forms.Command").GetMethod("DispatchID",
   1.349 -        BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public,
   1.350 -        null, new Type[] { typeof(int) }, null);
   1.351 -
   1.352 -      id = ++NotifyIconAdv.nextId;
   1.353 -      window = new NotifyIconNativeWindow(this);
   1.354 -      UpdateNotifyIcon(visible);
   1.355 -    }
   1.356 -
   1.357 -    protected override void Dispose(bool disposing) {
   1.358 -      if (disposing) {
   1.359 -        if (window != null) {
   1.360 -          icon = null;
   1.361 -          text = "";
   1.362 -          UpdateNotifyIcon(false);
   1.363 -          window.DestroyHandle();
   1.364 -          window = null;
   1.365 -          ContextMenu = null;
   1.366 -          ContextMenuStrip = null;
   1.367 -        }
   1.368 -      } else {
   1.369 -        if (window != null && window.Handle != IntPtr.Zero) {
   1.370 -          NativeMethods.PostMessage(
   1.371 -            new HandleRef(window, window.Handle), WM_CLOSE, 0, 0);
   1.372 -          window.ReleaseHandle();
   1.373 -        }
   1.374 -      }
   1.375 -      base.Dispose(disposing);
   1.376 +    public void Dispose() {
   1.377 +      if (genericNotifyIcon != null)
   1.378 +        genericNotifyIcon.Dispose();
   1.379 +      else
   1.380 +        windowsNotifyIcon.Dispose();
   1.381      }
   1.382  
   1.383      public void ShowBalloonTip(int timeout) {
   1.384 @@ -132,371 +315,493 @@
   1.385      }
   1.386  
   1.387      public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
   1.388 -      ToolTipIcon tipIcon) 
   1.389 -    {
   1.390 -      if (timeout < 0)
   1.391 -        throw new ArgumentOutOfRangeException("timeout");
   1.392 +      ToolTipIcon tipIcon) {
   1.393 +      if (genericNotifyIcon != null)
   1.394 +        genericNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
   1.395 +      else
   1.396 +        windowsNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon);
   1.397 +    }
   1.398 +    
   1.399 +    private class NotifyIconWindowsImplementation : Component {
   1.400  
   1.401 -      if (string.IsNullOrEmpty(tipText))
   1.402 -        throw new ArgumentException("tipText");
   1.403 +      private static int nextId = 0;
   1.404  
   1.405 -      if (DesignMode)
   1.406 -        return;
   1.407 +      private object syncObj = new object();
   1.408 +      private Icon icon;
   1.409 +      private string text = "";
   1.410 +      private int id;
   1.411 +      private bool created;
   1.412 +      private NotifyIconNativeWindow window;
   1.413 +      private bool doubleClickDown;
   1.414 +      private bool visible;
   1.415 +      private MethodInfo commandDispatch;
   1.416  
   1.417 -      if (created) {
   1.418 -        NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
   1.419 -        if (window.Handle == IntPtr.Zero)
   1.420 -          window.CreateHandle(new CreateParams());
   1.421 +      public event EventHandler BalloonTipClicked;
   1.422 +      public event EventHandler BalloonTipClosed;
   1.423 +      public event EventHandler BalloonTipShown;
   1.424 +      public event EventHandler Click;
   1.425 +      public event EventHandler DoubleClick;
   1.426 +      public event MouseEventHandler MouseClick;
   1.427 +      public event MouseEventHandler MouseDoubleClick;
   1.428 +      public event MouseEventHandler MouseDown;
   1.429 +      public event MouseEventHandler MouseMove;
   1.430 +      public event MouseEventHandler MouseUp;
   1.431  
   1.432 -        data.Window = window.Handle;
   1.433 -        data.ID = id;
   1.434 -        data.Flags = NativeMethods.NotifyIconDataFlags.Info;
   1.435 -        data.TimeoutOrVersion = timeout;
   1.436 -        data.InfoTitle = tipTitle;
   1.437 -        data.Info = tipText;
   1.438 -        data.InfoFlags = (int)tipIcon;
   1.439 +      public string BalloonTipText { get; set; }
   1.440 +      public ToolTipIcon BalloonTipIcon { get; set; }
   1.441 +      public string BalloonTipTitle { get; set; }
   1.442 +      public ContextMenu ContextMenu { get; set; }
   1.443 +      public ContextMenuStrip ContextMenuStrip { get; set; }
   1.444 +      public object Tag { get; set; }
   1.445  
   1.446 -        NativeMethods.Shell_NotifyIcon(
   1.447 -          NativeMethods.NotifyIconMessage.Modify, data);
   1.448 -      }
   1.449 -    }
   1.450 -
   1.451 -    private void ShowContextMenu() {
   1.452 -      if (ContextMenu == null && ContextMenuStrip == null)
   1.453 -        return;
   1.454 -
   1.455 -      NativeMethods.Point p = new NativeMethods.Point();
   1.456 -      NativeMethods.GetCursorPos(ref p);
   1.457 -      NativeMethods.SetForegroundWindow(
   1.458 -        new HandleRef(window, window.Handle));
   1.459 -
   1.460 -      if (ContextMenu != null) {
   1.461 -        ContextMenu.GetType().InvokeMember("OnPopup",
   1.462 -          BindingFlags.NonPublic | BindingFlags.InvokeMethod |
   1.463 -          BindingFlags.Instance, null, ContextMenu,
   1.464 -          new Object[] { System.EventArgs.Empty });
   1.465 -
   1.466 -        NativeMethods.TrackPopupMenuEx(
   1.467 -          new HandleRef(ContextMenu, ContextMenu.Handle), 72,
   1.468 -          p.x, p.y, new HandleRef(window, window.Handle),
   1.469 -          IntPtr.Zero);
   1.470 -
   1.471 -        NativeMethods.PostMessage(
   1.472 -          new HandleRef(window, window.Handle), WM_NULL, 0, 0);
   1.473 -        return;
   1.474 -      }
   1.475 -
   1.476 -      if (ContextMenuStrip != null)
   1.477 -        ContextMenuStrip.GetType().InvokeMember("ShowInTaskbar",
   1.478 -          BindingFlags.NonPublic | BindingFlags.InvokeMethod |
   1.479 -          BindingFlags.Instance, null, ContextMenuStrip,
   1.480 -          new Object[] { p.x, p.y });
   1.481 -    }
   1.482 -
   1.483 -    private void UpdateNotifyIcon(bool showNotifyIcon) {
   1.484 -      if (DesignMode)
   1.485 -        return;
   1.486 -
   1.487 -      lock (syncObj) {
   1.488 -        window.LockReference(showNotifyIcon);
   1.489 -
   1.490 -        NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
   1.491 -        data.CallbackMessage = WM_TRAYMOUSEMESSAGE;
   1.492 -        data.Flags = NativeMethods.NotifyIconDataFlags.Message;
   1.493 -
   1.494 -        if (showNotifyIcon && window.Handle == IntPtr.Zero)
   1.495 -          window.CreateHandle(new CreateParams());
   1.496 -
   1.497 -        data.Window = window.Handle;
   1.498 -        data.ID = id;
   1.499 -
   1.500 -        if (icon != null) {
   1.501 -          data.Flags |= NativeMethods.NotifyIconDataFlags.Icon;
   1.502 -          data.Icon = icon.Handle;
   1.503 +      public Icon Icon {
   1.504 +        get {
   1.505 +          return icon;
   1.506          }
   1.507 -
   1.508 -        data.Flags |= NativeMethods.NotifyIconDataFlags.Tip;
   1.509 -        data.Tip = text;
   1.510 -
   1.511 -        if (showNotifyIcon && icon != null) {
   1.512 -          if (!created) {
   1.513 -            int i = 0;
   1.514 -            do {
   1.515 -              created = NativeMethods.Shell_NotifyIcon(
   1.516 -                NativeMethods.NotifyIconMessage.Add, data);
   1.517 -              if (!created) {
   1.518 -                System.Threading.Thread.Sleep(200);
   1.519 -                i++;
   1.520 -              }
   1.521 -            } while (!created && i < 40);
   1.522 -          } else {
   1.523 -            NativeMethods.Shell_NotifyIcon(
   1.524 -              NativeMethods.NotifyIconMessage.Modify, data);
   1.525 -          }
   1.526 -        } else {
   1.527 -          if (created) {
   1.528 -            int i = 0;
   1.529 -            bool deleted = false;
   1.530 -            do {
   1.531 -              deleted = NativeMethods.Shell_NotifyIcon(
   1.532 -                NativeMethods.NotifyIconMessage.Delete, data);
   1.533 -              if (!deleted) {
   1.534 -                System.Threading.Thread.Sleep(200);
   1.535 -                i++;
   1.536 -              }
   1.537 -            } while (!deleted && i < 40);
   1.538 -            created = false;
   1.539 +        set {
   1.540 +          if (icon != value) {
   1.541 +            icon = value;
   1.542 +            UpdateNotifyIcon(visible);
   1.543            }
   1.544          }
   1.545        }
   1.546 -    }
   1.547  
   1.548 -    private void ProcessMouseDown(ref Message message, MouseButtons button, 
   1.549 -      bool doubleClick) 
   1.550 -    {
   1.551 -      if (doubleClick) {
   1.552 -        if (DoubleClick != null)
   1.553 -          DoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
   1.554 +      public string Text {
   1.555 +        get {
   1.556 +          return text;
   1.557 +        }
   1.558 +        set {
   1.559 +          if (value == null)
   1.560 +            value = "";
   1.561  
   1.562 -        if (MouseDoubleClick != null)
   1.563 -          MouseDoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
   1.564 +          if (value.Length > 63)
   1.565 +            throw new ArgumentOutOfRangeException();
   1.566  
   1.567 -        doubleClickDown = true;
   1.568 +          if (!value.Equals(text)) {
   1.569 +            text = value;
   1.570 +
   1.571 +            if (visible)
   1.572 +              UpdateNotifyIcon(visible);
   1.573 +          }
   1.574 +        }
   1.575        }
   1.576  
   1.577 -      if (MouseDown != null)
   1.578 -        MouseDown(this, 
   1.579 -          new MouseEventArgs(button, doubleClick ? 2 : 1, 0, 0, 0));      
   1.580 -    }
   1.581 -
   1.582 -    private void ProcessMouseUp(ref Message message, MouseButtons button) {
   1.583 -      if (MouseUp != null)
   1.584 -        MouseUp(this, new MouseEventArgs(button, 0, 0, 0, 0));
   1.585 -
   1.586 -      if (!doubleClickDown) {
   1.587 -        if (Click != null)
   1.588 -          Click(this, new MouseEventArgs(button, 0, 0, 0, 0));
   1.589 -
   1.590 -        if (MouseClick != null)
   1.591 -          MouseClick(this, new MouseEventArgs(button, 0, 0, 0, 0));
   1.592 -      }
   1.593 -      doubleClickDown = false;
   1.594 -    }
   1.595 -
   1.596 -    private void ProcessInitMenuPopup(ref Message message) {
   1.597 -      if (ContextMenu != null &&
   1.598 -        (bool)ContextMenu.GetType().InvokeMember("ProcessInitMenuPopup",
   1.599 -          BindingFlags.NonPublic | BindingFlags.InvokeMethod |
   1.600 -          BindingFlags.Instance, null, ContextMenu,
   1.601 -          new Object[] { message.WParam })) {
   1.602 -        return;
   1.603 -      }
   1.604 -      window.DefWndProc(ref message);
   1.605 -    }
   1.606 -
   1.607 -    private void WndProc(ref Message message) {
   1.608 -      switch (message.Msg) {
   1.609 -        case WM_DESTROY:
   1.610 -          UpdateNotifyIcon(false);
   1.611 -          return;
   1.612 -        case WM_COMMAND:
   1.613 -          if (message.LParam != IntPtr.Zero) {
   1.614 -            window.DefWndProc(ref message);
   1.615 -            return;
   1.616 +      public bool Visible {
   1.617 +        get {
   1.618 +          return visible;
   1.619 +        }
   1.620 +        set {
   1.621 +          if (visible != value) {
   1.622 +            visible = value;
   1.623 +            UpdateNotifyIcon(visible);
   1.624            }
   1.625 -          commandDispatch.Invoke(null, new object[] { 
   1.626 -            message.WParam.ToInt32() & 0xFFFF });
   1.627 -          return;
   1.628 -        case WM_INITMENUPOPUP:
   1.629 -          ProcessInitMenuPopup(ref message);
   1.630 -          return;
   1.631 -        case WM_TRAYMOUSEMESSAGE:
   1.632 -          switch ((int)message.LParam) {
   1.633 -            case WM_MOUSEMOVE:
   1.634 -              if (MouseMove != null)
   1.635 -                MouseMove(this, 
   1.636 -                  new MouseEventArgs(Control.MouseButtons, 0, 0, 0, 0));              
   1.637 -              return;
   1.638 -            case WM_LBUTTONDOWN:
   1.639 -              ProcessMouseDown(ref message, MouseButtons.Left, false);
   1.640 -              return;
   1.641 -            case WM_LBUTTONUP:
   1.642 -              ProcessMouseUp(ref message, MouseButtons.Left);
   1.643 -              return;
   1.644 -            case WM_LBUTTONDBLCLK:
   1.645 -              ProcessMouseDown(ref message, MouseButtons.Left, true);
   1.646 -              return;
   1.647 -            case WM_RBUTTONDOWN:
   1.648 -              ProcessMouseDown(ref message, MouseButtons.Right, false);
   1.649 -              return;
   1.650 -            case WM_RBUTTONUP:
   1.651 -              if (ContextMenu != null || ContextMenuStrip != null)
   1.652 -                ShowContextMenu();
   1.653 -              ProcessMouseUp(ref message, MouseButtons.Right);
   1.654 -              return;
   1.655 -            case WM_RBUTTONDBLCLK:
   1.656 -              ProcessMouseDown(ref message, MouseButtons.Right, true);
   1.657 -              return;
   1.658 -            case WM_MBUTTONDOWN:
   1.659 -              ProcessMouseDown(ref message, MouseButtons.Middle, false);
   1.660 -              return;
   1.661 -            case WM_MBUTTONUP:
   1.662 -              ProcessMouseUp(ref message, MouseButtons.Middle);
   1.663 -              return;
   1.664 -            case WM_MBUTTONDBLCLK:
   1.665 -              ProcessMouseDown(ref message, MouseButtons.Middle, true);
   1.666 -              return;
   1.667 -            case NIN_BALLOONSHOW:
   1.668 -              if (BalloonTipShown != null)
   1.669 -                BalloonTipShown(this, EventArgs.Empty);
   1.670 -              return;
   1.671 -            case NIN_BALLOONHIDE:
   1.672 -            case NIN_BALLOONTIMEOUT:
   1.673 -              if (BalloonTipClosed != null)
   1.674 -                BalloonTipClosed(this, EventArgs.Empty);
   1.675 -              return;
   1.676 -            case NIN_BALLOONUSERCLICK:
   1.677 -              if (BalloonTipClicked != null)
   1.678 -                BalloonTipClicked(this, EventArgs.Empty);
   1.679 -              return;
   1.680 -            default:
   1.681 -              return;
   1.682 -          }
   1.683 +        }
   1.684        }
   1.685  
   1.686 -      if (message.Msg == NotifyIconAdv.WM_TASKBARCREATED) {
   1.687 -        lock (syncObj) {
   1.688 -          created = false;
   1.689 -        }
   1.690 +      public NotifyIconWindowsImplementation() {
   1.691 +        BalloonTipText = "";
   1.692 +        BalloonTipTitle = "";
   1.693 +
   1.694 +        commandDispatch = typeof(Form).Assembly.
   1.695 +          GetType("System.Windows.Forms.Command").GetMethod("DispatchID",
   1.696 +          BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public,
   1.697 +          null, new Type[] { typeof(int) }, null);
   1.698 +
   1.699 +        id = ++NotifyIconWindowsImplementation.nextId;
   1.700 +        window = new NotifyIconNativeWindow(this);
   1.701          UpdateNotifyIcon(visible);
   1.702        }
   1.703  
   1.704 -      window.DefWndProc(ref message);
   1.705 -    }
   1.706 -
   1.707 -    private class NotifyIconNativeWindow : NativeWindow {
   1.708 -      private NotifyIconAdv reference;
   1.709 -      private GCHandle referenceHandle;
   1.710 -
   1.711 -      internal NotifyIconNativeWindow(NotifyIconAdv component) {
   1.712 -        this.reference = component;
   1.713 +      protected override void Dispose(bool disposing) {
   1.714 +        if (disposing) {
   1.715 +          if (window != null) {
   1.716 +            icon = null;
   1.717 +            text = "";
   1.718 +            UpdateNotifyIcon(false);
   1.719 +            window.DestroyHandle();
   1.720 +            window = null;
   1.721 +            ContextMenu = null;
   1.722 +            ContextMenuStrip = null;
   1.723 +          }
   1.724 +        } else {
   1.725 +          if (window != null && window.Handle != IntPtr.Zero) {
   1.726 +            NativeMethods.PostMessage(
   1.727 +              new HandleRef(window, window.Handle), WM_CLOSE, 0, 0);
   1.728 +            window.ReleaseHandle();
   1.729 +          }
   1.730 +        }
   1.731 +        base.Dispose(disposing);
   1.732        }
   1.733  
   1.734 -      ~NotifyIconNativeWindow() {
   1.735 -        if (base.Handle != IntPtr.Zero)
   1.736 -          NativeMethods.PostMessage(
   1.737 -            new HandleRef(this, base.Handle), WM_CLOSE, 0, 0);
   1.738 +      public void ShowBalloonTip(int timeout) {
   1.739 +        ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
   1.740        }
   1.741  
   1.742 -      public void LockReference(bool locked) {
   1.743 -        if (locked) {
   1.744 -          if (!referenceHandle.IsAllocated) {
   1.745 -            referenceHandle = GCHandle.Alloc(reference, GCHandleType.Normal);
   1.746 -            return;
   1.747 -          }
   1.748 -        } else {
   1.749 -          if (referenceHandle.IsAllocated)
   1.750 -            referenceHandle.Free();
   1.751 +      public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
   1.752 +        ToolTipIcon tipIcon) {
   1.753 +        if (timeout < 0)
   1.754 +          throw new ArgumentOutOfRangeException("timeout");
   1.755 +
   1.756 +        if (string.IsNullOrEmpty(tipText))
   1.757 +          throw new ArgumentException("tipText");
   1.758 +
   1.759 +        if (DesignMode)
   1.760 +          return;
   1.761 +
   1.762 +        if (created) {
   1.763 +          NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
   1.764 +          if (window.Handle == IntPtr.Zero)
   1.765 +            window.CreateHandle(new CreateParams());
   1.766 +
   1.767 +          data.Window = window.Handle;
   1.768 +          data.ID = id;
   1.769 +          data.Flags = NativeMethods.NotifyIconDataFlags.Info;
   1.770 +          data.TimeoutOrVersion = timeout;
   1.771 +          data.InfoTitle = tipTitle;
   1.772 +          data.Info = tipText;
   1.773 +          data.InfoFlags = (int)tipIcon;
   1.774 +
   1.775 +          NativeMethods.Shell_NotifyIcon(
   1.776 +            NativeMethods.NotifyIconMessage.Modify, data);
   1.777          }
   1.778        }
   1.779  
   1.780 -      protected override void OnThreadException(Exception e) {
   1.781 -        Application.OnThreadException(e);
   1.782 +      private void ShowContextMenu() {
   1.783 +        if (ContextMenu == null && ContextMenuStrip == null)
   1.784 +          return;
   1.785 +
   1.786 +        NativeMethods.Point p = new NativeMethods.Point();
   1.787 +        NativeMethods.GetCursorPos(ref p);
   1.788 +        NativeMethods.SetForegroundWindow(
   1.789 +          new HandleRef(window, window.Handle));
   1.790 +
   1.791 +        if (ContextMenu != null) {
   1.792 +          ContextMenu.GetType().InvokeMember("OnPopup",
   1.793 +            BindingFlags.NonPublic | BindingFlags.InvokeMethod |
   1.794 +            BindingFlags.Instance, null, ContextMenu,
   1.795 +            new Object[] { System.EventArgs.Empty });
   1.796 +
   1.797 +          NativeMethods.TrackPopupMenuEx(
   1.798 +            new HandleRef(ContextMenu, ContextMenu.Handle), 72,
   1.799 +            p.x, p.y, new HandleRef(window, window.Handle),
   1.800 +            IntPtr.Zero);
   1.801 +
   1.802 +          NativeMethods.PostMessage(
   1.803 +            new HandleRef(window, window.Handle), WM_NULL, 0, 0);
   1.804 +          return;
   1.805 +        }
   1.806 +
   1.807 +        if (ContextMenuStrip != null)
   1.808 +          ContextMenuStrip.GetType().InvokeMember("ShowInTaskbar",
   1.809 +            BindingFlags.NonPublic | BindingFlags.InvokeMethod |
   1.810 +            BindingFlags.Instance, null, ContextMenuStrip,
   1.811 +            new Object[] { p.x, p.y });
   1.812        }
   1.813  
   1.814 -      protected override void WndProc(ref Message m) {
   1.815 -        reference.WndProc(ref m);
   1.816 -      }
   1.817 -    }    
   1.818 +      private void UpdateNotifyIcon(bool showNotifyIcon) {
   1.819 +        if (DesignMode)
   1.820 +          return;
   1.821  
   1.822 -    private const int WM_NULL = 0x00;
   1.823 -    private const int WM_DESTROY = 0x02;
   1.824 -    private const int WM_CLOSE = 0x10;
   1.825 -    private const int WM_COMMAND = 0x111;
   1.826 -    private const int WM_INITMENUPOPUP = 0x117;
   1.827 -    private const int WM_MOUSEMOVE = 0x200;
   1.828 -    private const int WM_LBUTTONDOWN = 0x201;
   1.829 -    private const int WM_LBUTTONUP = 0x202;
   1.830 -    private const int WM_LBUTTONDBLCLK = 0x203;
   1.831 -    private const int WM_RBUTTONDOWN = 0x204;
   1.832 -    private const int WM_RBUTTONUP = 0x205;
   1.833 -    private const int WM_RBUTTONDBLCLK = 0x206;
   1.834 -    private const int WM_MBUTTONDOWN = 0x207;
   1.835 -    private const int WM_MBUTTONUP = 0x208;
   1.836 -    private const int WM_MBUTTONDBLCLK = 0x209;
   1.837 -    private const int WM_TRAYMOUSEMESSAGE = 0x800;
   1.838 +        lock (syncObj) {
   1.839 +          window.LockReference(showNotifyIcon);
   1.840  
   1.841 -    private const int NIN_BALLOONSHOW = 0x402;
   1.842 -    private const int NIN_BALLOONHIDE = 0x403;
   1.843 -    private const int NIN_BALLOONTIMEOUT = 0x404;
   1.844 -    private const int NIN_BALLOONUSERCLICK = 0x405;
   1.845 +          NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
   1.846 +          data.CallbackMessage = WM_TRAYMOUSEMESSAGE;
   1.847 +          data.Flags = NativeMethods.NotifyIconDataFlags.Message;
   1.848  
   1.849 -    private static int WM_TASKBARCREATED =
   1.850 -      NativeMethods.RegisterWindowMessage("TaskbarCreated");
   1.851 +          if (showNotifyIcon && window.Handle == IntPtr.Zero)
   1.852 +            window.CreateHandle(new CreateParams());
   1.853  
   1.854 -    private static class NativeMethods {
   1.855 -      [DllImport("user32.dll", CharSet = CharSet.Auto)]
   1.856 -      public static extern IntPtr PostMessage(HandleRef hwnd, int msg,
   1.857 -        int wparam, int lparam);
   1.858 +          data.Window = window.Handle;
   1.859 +          data.ID = id;
   1.860  
   1.861 -      [DllImport("user32.dll", CharSet = CharSet.Auto)]
   1.862 -      public static extern int RegisterWindowMessage(string msg);
   1.863 +          if (icon != null) {
   1.864 +            data.Flags |= NativeMethods.NotifyIconDataFlags.Icon;
   1.865 +            data.Icon = icon.Handle;
   1.866 +          }
   1.867  
   1.868 -      [Flags]
   1.869 -      public enum NotifyIconDataFlags : int {
   1.870 -        Message = 0x1,
   1.871 -        Icon = 0x2,
   1.872 -        Tip = 0x4,
   1.873 -        State = 0x8,
   1.874 -        Info = 0x10
   1.875 +          data.Flags |= NativeMethods.NotifyIconDataFlags.Tip;
   1.876 +          data.Tip = text;
   1.877 +
   1.878 +          if (showNotifyIcon && icon != null) {
   1.879 +            if (!created) {
   1.880 +              int i = 0;
   1.881 +              do {
   1.882 +                created = NativeMethods.Shell_NotifyIcon(
   1.883 +                  NativeMethods.NotifyIconMessage.Add, data);
   1.884 +                if (!created) {
   1.885 +                  System.Threading.Thread.Sleep(200);
   1.886 +                  i++;
   1.887 +                }
   1.888 +              } while (!created && i < 40);
   1.889 +            } else {
   1.890 +              NativeMethods.Shell_NotifyIcon(
   1.891 +                NativeMethods.NotifyIconMessage.Modify, data);
   1.892 +            }
   1.893 +          } else {
   1.894 +            if (created) {
   1.895 +              int i = 0;
   1.896 +              bool deleted = false;
   1.897 +              do {
   1.898 +                deleted = NativeMethods.Shell_NotifyIcon(
   1.899 +                  NativeMethods.NotifyIconMessage.Delete, data);
   1.900 +                if (!deleted) {
   1.901 +                  System.Threading.Thread.Sleep(200);
   1.902 +                  i++;
   1.903 +                }
   1.904 +              } while (!deleted && i < 40);
   1.905 +              created = false;
   1.906 +            }
   1.907 +          }
   1.908 +        }
   1.909        }
   1.910  
   1.911 -      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
   1.912 -      public class NotifyIconData {
   1.913 -        private int Size = Marshal.SizeOf(typeof(NotifyIconData));
   1.914 -        public IntPtr Window;
   1.915 -        public int ID;
   1.916 -        public NotifyIconDataFlags Flags;
   1.917 -        public int CallbackMessage;
   1.918 -        public IntPtr Icon;
   1.919 -        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
   1.920 -        public string Tip;
   1.921 -        public int State;
   1.922 -        public int StateMask;
   1.923 -        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
   1.924 -        public string Info;
   1.925 -        public int TimeoutOrVersion;
   1.926 -        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
   1.927 -        public string InfoTitle;
   1.928 -        public int InfoFlags;
   1.929 +      private void ProcessMouseDown(ref Message message, MouseButtons button,
   1.930 +        bool doubleClick) {
   1.931 +        if (doubleClick) {
   1.932 +          if (DoubleClick != null)
   1.933 +            DoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
   1.934 +
   1.935 +          if (MouseDoubleClick != null)
   1.936 +            MouseDoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
   1.937 +
   1.938 +          doubleClickDown = true;
   1.939 +        }
   1.940 +
   1.941 +        if (MouseDown != null)
   1.942 +          MouseDown(this,
   1.943 +            new MouseEventArgs(button, doubleClick ? 2 : 1, 0, 0, 0));
   1.944        }
   1.945  
   1.946 -      public enum NotifyIconMessage : int {
   1.947 -        Add = 0x0,
   1.948 -        Modify = 0x1,
   1.949 -        Delete = 0x2
   1.950 +      private void ProcessMouseUp(ref Message message, MouseButtons button) {
   1.951 +        if (MouseUp != null)
   1.952 +          MouseUp(this, new MouseEventArgs(button, 0, 0, 0, 0));
   1.953 +
   1.954 +        if (!doubleClickDown) {
   1.955 +          if (Click != null)
   1.956 +            Click(this, new MouseEventArgs(button, 0, 0, 0, 0));
   1.957 +
   1.958 +          if (MouseClick != null)
   1.959 +            MouseClick(this, new MouseEventArgs(button, 0, 0, 0, 0));
   1.960 +        }
   1.961 +        doubleClickDown = false;
   1.962        }
   1.963  
   1.964 -      [DllImport("shell32.dll", CharSet = CharSet.Auto)]
   1.965 -      [return: MarshalAs(UnmanagedType.Bool)]
   1.966 -      public static extern bool Shell_NotifyIcon(NotifyIconMessage message,
   1.967 -        NotifyIconData pnid);
   1.968 -
   1.969 -      [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
   1.970 -      public static extern bool TrackPopupMenuEx(HandleRef hmenu, int fuFlags,
   1.971 -        int x, int y, HandleRef hwnd, IntPtr tpm);
   1.972 -
   1.973 -      [StructLayout(LayoutKind.Sequential)]
   1.974 -      public struct Point {
   1.975 -        public int x;
   1.976 -        public int y;
   1.977 +      private void ProcessInitMenuPopup(ref Message message) {
   1.978 +        if (ContextMenu != null &&
   1.979 +          (bool)ContextMenu.GetType().InvokeMember("ProcessInitMenuPopup",
   1.980 +            BindingFlags.NonPublic | BindingFlags.InvokeMethod |
   1.981 +            BindingFlags.Instance, null, ContextMenu,
   1.982 +            new Object[] { message.WParam })) {
   1.983 +          return;
   1.984 +        }
   1.985 +        window.DefWndProc(ref message);
   1.986        }
   1.987  
   1.988 -      [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
   1.989 -      public static extern bool GetCursorPos(ref Point point);
   1.990 +      private void WndProc(ref Message message) {
   1.991 +        switch (message.Msg) {
   1.992 +          case WM_DESTROY:
   1.993 +            UpdateNotifyIcon(false);
   1.994 +            return;
   1.995 +          case WM_COMMAND:
   1.996 +            if (message.LParam != IntPtr.Zero) {
   1.997 +              window.DefWndProc(ref message);
   1.998 +              return;
   1.999 +            }
  1.1000 +            commandDispatch.Invoke(null, new object[] { 
  1.1001 +            message.WParam.ToInt32() & 0xFFFF });
  1.1002 +            return;
  1.1003 +          case WM_INITMENUPOPUP:
  1.1004 +            ProcessInitMenuPopup(ref message);
  1.1005 +            return;
  1.1006 +          case WM_TRAYMOUSEMESSAGE:
  1.1007 +            switch ((int)message.LParam) {
  1.1008 +              case WM_MOUSEMOVE:
  1.1009 +                if (MouseMove != null)
  1.1010 +                  MouseMove(this,
  1.1011 +                    new MouseEventArgs(Control.MouseButtons, 0, 0, 0, 0));
  1.1012 +                return;
  1.1013 +              case WM_LBUTTONDOWN:
  1.1014 +                ProcessMouseDown(ref message, MouseButtons.Left, false);
  1.1015 +                return;
  1.1016 +              case WM_LBUTTONUP:
  1.1017 +                ProcessMouseUp(ref message, MouseButtons.Left);
  1.1018 +                return;
  1.1019 +              case WM_LBUTTONDBLCLK:
  1.1020 +                ProcessMouseDown(ref message, MouseButtons.Left, true);
  1.1021 +                return;
  1.1022 +              case WM_RBUTTONDOWN:
  1.1023 +                ProcessMouseDown(ref message, MouseButtons.Right, false);
  1.1024 +                return;
  1.1025 +              case WM_RBUTTONUP:
  1.1026 +                if (ContextMenu != null || ContextMenuStrip != null)
  1.1027 +                  ShowContextMenu();
  1.1028 +                ProcessMouseUp(ref message, MouseButtons.Right);
  1.1029 +                return;
  1.1030 +              case WM_RBUTTONDBLCLK:
  1.1031 +                ProcessMouseDown(ref message, MouseButtons.Right, true);
  1.1032 +                return;
  1.1033 +              case WM_MBUTTONDOWN:
  1.1034 +                ProcessMouseDown(ref message, MouseButtons.Middle, false);
  1.1035 +                return;
  1.1036 +              case WM_MBUTTONUP:
  1.1037 +                ProcessMouseUp(ref message, MouseButtons.Middle);
  1.1038 +                return;
  1.1039 +              case WM_MBUTTONDBLCLK:
  1.1040 +                ProcessMouseDown(ref message, MouseButtons.Middle, true);
  1.1041 +                return;
  1.1042 +              case NIN_BALLOONSHOW:
  1.1043 +                if (BalloonTipShown != null)
  1.1044 +                  BalloonTipShown(this, EventArgs.Empty);
  1.1045 +                return;
  1.1046 +              case NIN_BALLOONHIDE:
  1.1047 +              case NIN_BALLOONTIMEOUT:
  1.1048 +                if (BalloonTipClosed != null)
  1.1049 +                  BalloonTipClosed(this, EventArgs.Empty);
  1.1050 +                return;
  1.1051 +              case NIN_BALLOONUSERCLICK:
  1.1052 +                if (BalloonTipClicked != null)
  1.1053 +                  BalloonTipClicked(this, EventArgs.Empty);
  1.1054 +                return;
  1.1055 +              default:
  1.1056 +                return;
  1.1057 +            }
  1.1058 +        }
  1.1059  
  1.1060 -      [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
  1.1061 -      public static extern bool SetForegroundWindow(HandleRef hWnd);
  1.1062 +        if (message.Msg == NotifyIconWindowsImplementation.WM_TASKBARCREATED) {
  1.1063 +          lock (syncObj) {
  1.1064 +            created = false;
  1.1065 +          }
  1.1066 +          UpdateNotifyIcon(visible);
  1.1067 +        }
  1.1068 +
  1.1069 +        window.DefWndProc(ref message);
  1.1070 +      }
  1.1071 +
  1.1072 +      private class NotifyIconNativeWindow : NativeWindow {
  1.1073 +        private NotifyIconWindowsImplementation reference;
  1.1074 +        private GCHandle referenceHandle;
  1.1075 +
  1.1076 +        internal NotifyIconNativeWindow(NotifyIconWindowsImplementation component) {
  1.1077 +          this.reference = component;
  1.1078 +        }
  1.1079 +
  1.1080 +        ~NotifyIconNativeWindow() {
  1.1081 +          if (base.Handle != IntPtr.Zero)
  1.1082 +            NativeMethods.PostMessage(
  1.1083 +              new HandleRef(this, base.Handle), WM_CLOSE, 0, 0);
  1.1084 +        }
  1.1085 +
  1.1086 +        public void LockReference(bool locked) {
  1.1087 +          if (locked) {
  1.1088 +            if (!referenceHandle.IsAllocated) {
  1.1089 +              referenceHandle = GCHandle.Alloc(reference, GCHandleType.Normal);
  1.1090 +              return;
  1.1091 +            }
  1.1092 +          } else {
  1.1093 +            if (referenceHandle.IsAllocated)
  1.1094 +              referenceHandle.Free();
  1.1095 +          }
  1.1096 +        }
  1.1097 +
  1.1098 +        protected override void OnThreadException(Exception e) {
  1.1099 +          Application.OnThreadException(e);
  1.1100 +        }
  1.1101 +
  1.1102 +        protected override void WndProc(ref Message m) {
  1.1103 +          reference.WndProc(ref m);
  1.1104 +        }
  1.1105 +      }
  1.1106 +
  1.1107 +      private const int WM_NULL = 0x00;
  1.1108 +      private const int WM_DESTROY = 0x02;
  1.1109 +      private const int WM_CLOSE = 0x10;
  1.1110 +      private const int WM_COMMAND = 0x111;
  1.1111 +      private const int WM_INITMENUPOPUP = 0x117;
  1.1112 +      private const int WM_MOUSEMOVE = 0x200;
  1.1113 +      private const int WM_LBUTTONDOWN = 0x201;
  1.1114 +      private const int WM_LBUTTONUP = 0x202;
  1.1115 +      private const int WM_LBUTTONDBLCLK = 0x203;
  1.1116 +      private const int WM_RBUTTONDOWN = 0x204;
  1.1117 +      private const int WM_RBUTTONUP = 0x205;
  1.1118 +      private const int WM_RBUTTONDBLCLK = 0x206;
  1.1119 +      private const int WM_MBUTTONDOWN = 0x207;
  1.1120 +      private const int WM_MBUTTONUP = 0x208;
  1.1121 +      private const int WM_MBUTTONDBLCLK = 0x209;
  1.1122 +      private const int WM_TRAYMOUSEMESSAGE = 0x800;
  1.1123 +
  1.1124 +      private const int NIN_BALLOONSHOW = 0x402;
  1.1125 +      private const int NIN_BALLOONHIDE = 0x403;
  1.1126 +      private const int NIN_BALLOONTIMEOUT = 0x404;
  1.1127 +      private const int NIN_BALLOONUSERCLICK = 0x405;
  1.1128 +
  1.1129 +      private static int WM_TASKBARCREATED =
  1.1130 +        NativeMethods.RegisterWindowMessage("TaskbarCreated");
  1.1131 +
  1.1132 +      private static class NativeMethods {
  1.1133 +        [DllImport("user32.dll", CharSet = CharSet.Auto)]
  1.1134 +        public static extern IntPtr PostMessage(HandleRef hwnd, int msg,
  1.1135 +          int wparam, int lparam);
  1.1136 +
  1.1137 +        [DllImport("user32.dll", CharSet = CharSet.Auto)]
  1.1138 +        public static extern int RegisterWindowMessage(string msg);
  1.1139 +
  1.1140 +        [Flags]
  1.1141 +        public enum NotifyIconDataFlags : int {
  1.1142 +          Message = 0x1,
  1.1143 +          Icon = 0x2,
  1.1144 +          Tip = 0x4,
  1.1145 +          State = 0x8,
  1.1146 +          Info = 0x10
  1.1147 +        }
  1.1148 +
  1.1149 +        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  1.1150 +        public class NotifyIconData {
  1.1151 +          private int Size = Marshal.SizeOf(typeof(NotifyIconData));
  1.1152 +          public IntPtr Window;
  1.1153 +          public int ID;
  1.1154 +          public NotifyIconDataFlags Flags;
  1.1155 +          public int CallbackMessage;
  1.1156 +          public IntPtr Icon;
  1.1157 +          [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
  1.1158 +          public string Tip;
  1.1159 +          public int State;
  1.1160 +          public int StateMask;
  1.1161 +          [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
  1.1162 +          public string Info;
  1.1163 +          public int TimeoutOrVersion;
  1.1164 +          [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
  1.1165 +          public string InfoTitle;
  1.1166 +          public int InfoFlags;
  1.1167 +        }
  1.1168 +
  1.1169 +        public enum NotifyIconMessage : int {
  1.1170 +          Add = 0x0,
  1.1171 +          Modify = 0x1,
  1.1172 +          Delete = 0x2
  1.1173 +        }
  1.1174 +
  1.1175 +        [DllImport("shell32.dll", CharSet = CharSet.Auto)]
  1.1176 +        [return: MarshalAs(UnmanagedType.Bool)]
  1.1177 +        public static extern bool Shell_NotifyIcon(NotifyIconMessage message,
  1.1178 +          NotifyIconData pnid);
  1.1179 +
  1.1180 +        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
  1.1181 +        public static extern bool TrackPopupMenuEx(HandleRef hmenu, int fuFlags,
  1.1182 +          int x, int y, HandleRef hwnd, IntPtr tpm);
  1.1183 +
  1.1184 +        [StructLayout(LayoutKind.Sequential)]
  1.1185 +        public struct Point {
  1.1186 +          public int x;
  1.1187 +          public int y;
  1.1188 +        }
  1.1189 +
  1.1190 +        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
  1.1191 +        public static extern bool GetCursorPos(ref Point point);
  1.1192 +
  1.1193 +        [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
  1.1194 +        public static extern bool SetForegroundWindow(HandleRef hWnd);
  1.1195 +      }
  1.1196      }
  1.1197    }
  1.1198  }