GUI/NotifyIconAdv.cs
author moel.mich
Tue, 17 Jul 2012 16:10:59 +0000
changeset 364 25ef2c489ce8
child 371 c1a0d321e646
permissions -rw-r--r--
Attempt at fixing Issue 253 without breaking Issue 159 once more.
moel@363
     1
/*
moel@363
     2
 
moel@363
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@363
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@363
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@363
     6
 
moel@363
     7
  Copyright (C) 2012 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@363
     8
	
moel@363
     9
*/
moel@363
    10
moel@363
    11
using System;
moel@363
    12
using System.ComponentModel;
moel@363
    13
using System.Drawing;
moel@363
    14
using System.Runtime.InteropServices;
moel@363
    15
using System.Reflection;
moel@363
    16
using System.Windows.Forms;
moel@363
    17
moel@363
    18
namespace OpenHardwareMonitor.GUI {
moel@363
    19
  public class NotifyIconAdv : Component {
moel@363
    20
moel@363
    21
    private static int nextId = 0;
moel@363
    22
moel@363
    23
    private object syncObj = new object();
moel@363
    24
    private Icon icon;
moel@363
    25
    private string text = "";
moel@363
    26
    private int id;
moel@363
    27
    private bool created;
moel@363
    28
    private NotifyIconNativeWindow window;
moel@363
    29
    private bool doubleClickDown;
moel@363
    30
    private bool visible;
moel@363
    31
    private MethodInfo commandDispatch;
moel@363
    32
moel@363
    33
    public event EventHandler BalloonTipClicked;
moel@363
    34
    public event EventHandler BalloonTipClosed;
moel@363
    35
    public event EventHandler BalloonTipShown;
moel@363
    36
    public event EventHandler Click;
moel@363
    37
    public event EventHandler DoubleClick;
moel@363
    38
    public event MouseEventHandler MouseClick;
moel@363
    39
    public event MouseEventHandler MouseDoubleClick;
moel@363
    40
    public event MouseEventHandler MouseDown;
moel@363
    41
    public event MouseEventHandler MouseMove;
moel@363
    42
    public event MouseEventHandler MouseUp;
moel@363
    43
moel@363
    44
    public string BalloonTipText { get; set; }
moel@363
    45
    public ToolTipIcon BalloonTipIcon { get; set; }
moel@363
    46
    public string BalloonTipTitle { get; set; }
moel@363
    47
    public ContextMenu ContextMenu { get; set; }
moel@363
    48
    public ContextMenuStrip ContextMenuStrip { get; set; }
moel@363
    49
    public object Tag { get; set; }
moel@363
    50
moel@363
    51
    public Icon Icon {
moel@363
    52
      get {
moel@363
    53
        return icon;
moel@363
    54
      }
moel@363
    55
      set {
moel@363
    56
        if (icon != value) {
moel@363
    57
          icon = value;
moel@363
    58
          UpdateNotifyIcon(visible);
moel@363
    59
        }
moel@363
    60
      }
moel@363
    61
    }
moel@363
    62
moel@363
    63
    public string Text {
moel@363
    64
      get {
moel@363
    65
        return text;
moel@363
    66
      }
moel@363
    67
      set {
moel@363
    68
        if (value == null)
moel@363
    69
          value = "";
moel@363
    70
moel@363
    71
        if (value.Length > 63)
moel@363
    72
          throw new ArgumentOutOfRangeException();
moel@363
    73
moel@363
    74
        if (!value.Equals(text)) {
moel@363
    75
          text = value;
moel@363
    76
moel@363
    77
          if (visible) 
moel@363
    78
            UpdateNotifyIcon(visible);          
moel@363
    79
        }
moel@363
    80
      }
moel@363
    81
    }
moel@363
    82
moel@363
    83
    public bool Visible {
moel@363
    84
      get {
moel@363
    85
        return visible;
moel@363
    86
      }
moel@363
    87
      set {
moel@363
    88
        if (visible != value) {
moel@363
    89
          visible = value;
moel@363
    90
          UpdateNotifyIcon(visible);          
moel@363
    91
        }
moel@363
    92
      }
moel@363
    93
    }
moel@363
    94
    
moel@363
    95
    public NotifyIconAdv() {
moel@363
    96
      BalloonTipText = "";
moel@363
    97
      BalloonTipTitle = "";
moel@363
    98
moel@363
    99
      commandDispatch = typeof(Form).Assembly.
moel@363
   100
        GetType("System.Windows.Forms.Command").GetMethod("DispatchID",
moel@363
   101
        BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public,
moel@363
   102
        null, new Type[] { typeof(int) }, null);
moel@363
   103
moel@363
   104
      id = ++NotifyIconAdv.nextId;
moel@363
   105
      window = new NotifyIconNativeWindow(this);
moel@363
   106
      UpdateNotifyIcon(visible);
moel@363
   107
    }
moel@363
   108
moel@363
   109
    protected override void Dispose(bool disposing) {
moel@363
   110
      if (disposing) {
moel@363
   111
        if (window != null) {
moel@363
   112
          icon = null;
moel@363
   113
          text = "";
moel@363
   114
          UpdateNotifyIcon(false);
moel@363
   115
          window.DestroyHandle();
moel@363
   116
          window = null;
moel@363
   117
          ContextMenu = null;
moel@363
   118
          ContextMenuStrip = null;
moel@363
   119
        }
moel@363
   120
      } else {
moel@363
   121
        if (window != null && window.Handle != IntPtr.Zero) {
moel@363
   122
          NativeMethods.PostMessage(
moel@363
   123
            new HandleRef(window, window.Handle), WM_CLOSE, 0, 0);
moel@363
   124
          window.ReleaseHandle();
moel@363
   125
        }
moel@363
   126
      }
moel@363
   127
      base.Dispose(disposing);
moel@363
   128
    }
moel@363
   129
moel@363
   130
    public void ShowBalloonTip(int timeout) {
moel@363
   131
      ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon);
moel@363
   132
    }
moel@363
   133
moel@363
   134
    public void ShowBalloonTip(int timeout, string tipTitle, string tipText,
moel@363
   135
      ToolTipIcon tipIcon) 
moel@363
   136
    {
moel@363
   137
      if (timeout < 0)
moel@363
   138
        throw new ArgumentOutOfRangeException("timeout");
moel@363
   139
moel@363
   140
      if (string.IsNullOrEmpty(tipText))
moel@363
   141
        throw new ArgumentException("tipText");
moel@363
   142
moel@363
   143
      if (DesignMode)
moel@363
   144
        return;
moel@363
   145
moel@363
   146
      if (created) {
moel@363
   147
        NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
moel@363
   148
        if (window.Handle == IntPtr.Zero)
moel@363
   149
          window.CreateHandle(new CreateParams());
moel@363
   150
moel@363
   151
        data.Window = window.Handle;
moel@363
   152
        data.ID = id;
moel@363
   153
        data.Flags = NativeMethods.NotifyIconDataFlags.Info;
moel@363
   154
        data.TimeoutOrVersion = timeout;
moel@363
   155
        data.InfoTitle = tipTitle;
moel@363
   156
        data.Info = tipText;
moel@363
   157
        data.InfoFlags = (int)tipIcon;
moel@363
   158
moel@363
   159
        NativeMethods.Shell_NotifyIcon(
moel@363
   160
          NativeMethods.NotifyIconMessage.Modify, data);
moel@363
   161
      }
moel@363
   162
    }
moel@363
   163
moel@363
   164
    private void ShowContextMenu() {
moel@363
   165
      if (ContextMenu == null && ContextMenuStrip == null)
moel@363
   166
        return;
moel@363
   167
moel@363
   168
      NativeMethods.Point p = new NativeMethods.Point();
moel@363
   169
      NativeMethods.GetCursorPos(ref p);
moel@363
   170
      NativeMethods.SetForegroundWindow(
moel@363
   171
        new HandleRef(window, window.Handle));
moel@363
   172
moel@363
   173
      if (ContextMenu != null) {
moel@363
   174
        ContextMenu.GetType().InvokeMember("OnPopup",
moel@363
   175
          BindingFlags.NonPublic | BindingFlags.InvokeMethod |
moel@363
   176
          BindingFlags.Instance, null, ContextMenu,
moel@363
   177
          new Object[] { System.EventArgs.Empty });
moel@363
   178
moel@363
   179
        NativeMethods.TrackPopupMenuEx(
moel@363
   180
          new HandleRef(ContextMenu, ContextMenu.Handle), 72,
moel@363
   181
          p.x, p.y, new HandleRef(window, window.Handle),
moel@363
   182
          IntPtr.Zero);
moel@363
   183
moel@363
   184
        NativeMethods.PostMessage(
moel@363
   185
          new HandleRef(window, window.Handle), WM_NULL, 0, 0);
moel@363
   186
        return;
moel@363
   187
      }
moel@363
   188
moel@363
   189
      if (ContextMenuStrip != null)
moel@363
   190
        ContextMenuStrip.GetType().InvokeMember("ShowInTaskbar",
moel@363
   191
          BindingFlags.NonPublic | BindingFlags.InvokeMethod |
moel@363
   192
          BindingFlags.Instance, null, ContextMenuStrip,
moel@363
   193
          new Object[] { p.x, p.y });
moel@363
   194
    }
moel@363
   195
moel@363
   196
    private void UpdateNotifyIcon(bool showNotifyIcon) {
moel@363
   197
      if (DesignMode)
moel@363
   198
        return;
moel@363
   199
moel@363
   200
      lock (syncObj) {
moel@363
   201
        window.LockReference(showNotifyIcon);
moel@363
   202
moel@363
   203
        NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData();
moel@363
   204
        data.CallbackMessage = WM_TRAYMOUSEMESSAGE;
moel@363
   205
        data.Flags = NativeMethods.NotifyIconDataFlags.Message;
moel@363
   206
moel@363
   207
        if (showNotifyIcon && window.Handle == IntPtr.Zero)
moel@363
   208
          window.CreateHandle(new CreateParams());
moel@363
   209
moel@363
   210
        data.Window = window.Handle;
moel@363
   211
        data.ID = id;
moel@363
   212
moel@363
   213
        if (icon != null) {
moel@363
   214
          data.Flags |= NativeMethods.NotifyIconDataFlags.Icon;
moel@363
   215
          data.Icon = icon.Handle;
moel@363
   216
        }
moel@363
   217
moel@363
   218
        data.Flags |= NativeMethods.NotifyIconDataFlags.Tip;
moel@363
   219
        data.Tip = text;
moel@363
   220
moel@363
   221
        if (showNotifyIcon && icon != null) {
moel@363
   222
          if (!created) {
moel@363
   223
            int i = 0;
moel@363
   224
            do {
moel@363
   225
              created = NativeMethods.Shell_NotifyIcon(
moel@363
   226
                NativeMethods.NotifyIconMessage.Add, data);
moel@363
   227
              if (!created) {
moel@363
   228
                System.Threading.Thread.Sleep(200);
moel@363
   229
                i++;
moel@363
   230
              }
moel@363
   231
            } while (!created && i < 40);
moel@363
   232
          } else {
moel@363
   233
            NativeMethods.Shell_NotifyIcon(
moel@363
   234
              NativeMethods.NotifyIconMessage.Modify, data);
moel@363
   235
          }
moel@363
   236
        } else {
moel@363
   237
          if (created) {
moel@363
   238
            int i = 0;
moel@363
   239
            bool deleted = false;
moel@363
   240
            do {
moel@363
   241
              deleted = NativeMethods.Shell_NotifyIcon(
moel@363
   242
                NativeMethods.NotifyIconMessage.Delete, data);
moel@363
   243
              if (!deleted) {
moel@363
   244
                System.Threading.Thread.Sleep(200);
moel@363
   245
                i++;
moel@363
   246
              }
moel@363
   247
            } while (!deleted && i < 40);
moel@363
   248
            created = false;
moel@363
   249
          }
moel@363
   250
        }
moel@363
   251
      }
moel@363
   252
    }
moel@363
   253
moel@363
   254
    private void ProcessMouseDown(ref Message message, MouseButtons button, 
moel@363
   255
      bool doubleClick) 
moel@363
   256
    {
moel@363
   257
      if (doubleClick) {
moel@363
   258
        if (DoubleClick != null)
moel@363
   259
          DoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
moel@363
   260
moel@363
   261
        if (MouseDoubleClick != null)
moel@363
   262
          MouseDoubleClick(this, new MouseEventArgs(button, 2, 0, 0, 0));
moel@363
   263
moel@363
   264
        doubleClickDown = true;
moel@363
   265
      }
moel@363
   266
moel@363
   267
      if (MouseDown != null)
moel@363
   268
        MouseDown(this, 
moel@363
   269
          new MouseEventArgs(button, doubleClick ? 2 : 1, 0, 0, 0));      
moel@363
   270
    }
moel@363
   271
moel@363
   272
    private void ProcessMouseUp(ref Message message, MouseButtons button) {
moel@363
   273
      if (MouseUp != null)
moel@363
   274
        MouseUp(this, new MouseEventArgs(button, 0, 0, 0, 0));
moel@363
   275
moel@363
   276
      if (!doubleClickDown) {
moel@363
   277
        if (Click != null)
moel@363
   278
          Click(this, new MouseEventArgs(button, 0, 0, 0, 0));
moel@363
   279
moel@363
   280
        if (MouseClick != null)
moel@363
   281
          MouseClick(this, new MouseEventArgs(button, 0, 0, 0, 0));
moel@363
   282
      }
moel@363
   283
      doubleClickDown = false;
moel@363
   284
    }
moel@363
   285
moel@363
   286
    private void ProcessInitMenuPopup(ref Message message) {
moel@363
   287
      if (ContextMenu != null &&
moel@363
   288
        (bool)ContextMenu.GetType().InvokeMember("ProcessInitMenuPopup",
moel@363
   289
          BindingFlags.NonPublic | BindingFlags.InvokeMethod |
moel@363
   290
          BindingFlags.Instance, null, ContextMenu,
moel@363
   291
          new Object[] { message.WParam })) {
moel@363
   292
        return;
moel@363
   293
      }
moel@363
   294
      window.DefWndProc(ref message);
moel@363
   295
    }
moel@363
   296
moel@363
   297
    private void WndProc(ref Message message) {
moel@363
   298
      switch (message.Msg) {
moel@363
   299
        case WM_DESTROY:
moel@363
   300
          UpdateNotifyIcon(false);
moel@363
   301
          return;
moel@363
   302
        case WM_COMMAND:
moel@363
   303
          if (message.LParam != IntPtr.Zero) {
moel@363
   304
            window.DefWndProc(ref message);
moel@363
   305
            return;
moel@363
   306
          }
moel@363
   307
          commandDispatch.Invoke(null, new object[] { 
moel@363
   308
            message.WParam.ToInt32() & 0xFFFF });
moel@363
   309
          return;
moel@363
   310
        case WM_INITMENUPOPUP:
moel@363
   311
          ProcessInitMenuPopup(ref message);
moel@363
   312
          return;
moel@363
   313
        case WM_TRAYMOUSEMESSAGE:
moel@363
   314
          switch ((int)message.LParam) {
moel@363
   315
            case WM_MOUSEMOVE:
moel@363
   316
              if (MouseMove != null)
moel@363
   317
                MouseMove(this, 
moel@363
   318
                  new MouseEventArgs(Control.MouseButtons, 0, 0, 0, 0));              
moel@363
   319
              return;
moel@363
   320
            case WM_LBUTTONDOWN:
moel@363
   321
              ProcessMouseDown(ref message, MouseButtons.Left, false);
moel@363
   322
              return;
moel@363
   323
            case WM_LBUTTONUP:
moel@363
   324
              ProcessMouseUp(ref message, MouseButtons.Left);
moel@363
   325
              return;
moel@363
   326
            case WM_LBUTTONDBLCLK:
moel@363
   327
              ProcessMouseDown(ref message, MouseButtons.Left, true);
moel@363
   328
              return;
moel@363
   329
            case WM_RBUTTONDOWN:
moel@363
   330
              ProcessMouseDown(ref message, MouseButtons.Right, false);
moel@363
   331
              return;
moel@363
   332
            case WM_RBUTTONUP:
moel@363
   333
              if (ContextMenu != null || ContextMenuStrip != null)
moel@363
   334
                ShowContextMenu();
moel@363
   335
              ProcessMouseUp(ref message, MouseButtons.Right);
moel@363
   336
              return;
moel@363
   337
            case WM_RBUTTONDBLCLK:
moel@363
   338
              ProcessMouseDown(ref message, MouseButtons.Right, true);
moel@363
   339
              return;
moel@363
   340
            case WM_MBUTTONDOWN:
moel@363
   341
              ProcessMouseDown(ref message, MouseButtons.Middle, false);
moel@363
   342
              return;
moel@363
   343
            case WM_MBUTTONUP:
moel@363
   344
              ProcessMouseUp(ref message, MouseButtons.Middle);
moel@363
   345
              return;
moel@363
   346
            case WM_MBUTTONDBLCLK:
moel@363
   347
              ProcessMouseDown(ref message, MouseButtons.Middle, true);
moel@363
   348
              return;
moel@363
   349
            case NIN_BALLOONSHOW:
moel@363
   350
              if (BalloonTipShown != null)
moel@363
   351
                BalloonTipShown(this, EventArgs.Empty);
moel@363
   352
              return;
moel@363
   353
            case NIN_BALLOONHIDE:
moel@363
   354
            case NIN_BALLOONTIMEOUT:
moel@363
   355
              if (BalloonTipClosed != null)
moel@363
   356
                BalloonTipClosed(this, EventArgs.Empty);
moel@363
   357
              return;
moel@363
   358
            case NIN_BALLOONUSERCLICK:
moel@363
   359
              if (BalloonTipClicked != null)
moel@363
   360
                BalloonTipClicked(this, EventArgs.Empty);
moel@363
   361
              return;
moel@363
   362
            default:
moel@363
   363
              return;
moel@363
   364
          }
moel@363
   365
      }
moel@363
   366
moel@363
   367
      if (message.Msg == NotifyIconAdv.WM_TASKBARCREATED) {
moel@363
   368
        lock (syncObj) {
moel@363
   369
          created = false;
moel@363
   370
        }
moel@363
   371
        UpdateNotifyIcon(visible);
moel@363
   372
      }
moel@363
   373
moel@363
   374
      window.DefWndProc(ref message);
moel@363
   375
    }
moel@363
   376
moel@363
   377
    private class NotifyIconNativeWindow : NativeWindow {
moel@363
   378
      private NotifyIconAdv reference;
moel@363
   379
      private GCHandle referenceHandle;
moel@363
   380
moel@363
   381
      internal NotifyIconNativeWindow(NotifyIconAdv component) {
moel@363
   382
        this.reference = component;
moel@363
   383
      }
moel@363
   384
moel@363
   385
      ~NotifyIconNativeWindow() {
moel@363
   386
        if (base.Handle != IntPtr.Zero)
moel@363
   387
          NativeMethods.PostMessage(
moel@363
   388
            new HandleRef(this, base.Handle), WM_CLOSE, 0, 0);
moel@363
   389
      }
moel@363
   390
moel@363
   391
      public void LockReference(bool locked) {
moel@363
   392
        if (locked) {
moel@363
   393
          if (!referenceHandle.IsAllocated) {
moel@363
   394
            referenceHandle = GCHandle.Alloc(reference, GCHandleType.Normal);
moel@363
   395
            return;
moel@363
   396
          }
moel@363
   397
        } else {
moel@363
   398
          if (referenceHandle.IsAllocated)
moel@363
   399
            referenceHandle.Free();
moel@363
   400
        }
moel@363
   401
      }
moel@363
   402
moel@363
   403
      protected override void OnThreadException(Exception e) {
moel@363
   404
        Application.OnThreadException(e);
moel@363
   405
      }
moel@363
   406
moel@363
   407
      protected override void WndProc(ref Message m) {
moel@363
   408
        reference.WndProc(ref m);
moel@363
   409
      }
moel@363
   410
    }    
moel@363
   411
moel@363
   412
    private const int WM_NULL = 0x00;
moel@363
   413
    private const int WM_DESTROY = 0x02;
moel@363
   414
    private const int WM_CLOSE = 0x10;
moel@363
   415
    private const int WM_COMMAND = 0x111;
moel@363
   416
    private const int WM_INITMENUPOPUP = 0x117;
moel@363
   417
    private const int WM_MOUSEMOVE = 0x200;
moel@363
   418
    private const int WM_LBUTTONDOWN = 0x201;
moel@363
   419
    private const int WM_LBUTTONUP = 0x202;
moel@363
   420
    private const int WM_LBUTTONDBLCLK = 0x203;
moel@363
   421
    private const int WM_RBUTTONDOWN = 0x204;
moel@363
   422
    private const int WM_RBUTTONUP = 0x205;
moel@363
   423
    private const int WM_RBUTTONDBLCLK = 0x206;
moel@363
   424
    private const int WM_MBUTTONDOWN = 0x207;
moel@363
   425
    private const int WM_MBUTTONUP = 0x208;
moel@363
   426
    private const int WM_MBUTTONDBLCLK = 0x209;
moel@363
   427
    private const int WM_TRAYMOUSEMESSAGE = 0x800;
moel@363
   428
moel@363
   429
    private const int NIN_BALLOONSHOW = 0x402;
moel@363
   430
    private const int NIN_BALLOONHIDE = 0x403;
moel@363
   431
    private const int NIN_BALLOONTIMEOUT = 0x404;
moel@363
   432
    private const int NIN_BALLOONUSERCLICK = 0x405;
moel@363
   433
moel@363
   434
    private static int WM_TASKBARCREATED =
moel@363
   435
      NativeMethods.RegisterWindowMessage("TaskbarCreated");
moel@363
   436
moel@363
   437
    private static class NativeMethods {
moel@363
   438
      [DllImport("user32.dll", CharSet = CharSet.Auto)]
moel@363
   439
      public static extern IntPtr PostMessage(HandleRef hwnd, int msg,
moel@363
   440
        int wparam, int lparam);
moel@363
   441
moel@363
   442
      [DllImport("user32.dll", CharSet = CharSet.Auto)]
moel@363
   443
      public static extern int RegisterWindowMessage(string msg);
moel@363
   444
moel@363
   445
      [Flags]
moel@363
   446
      public enum NotifyIconDataFlags : int {
moel@363
   447
        Message = 0x1,
moel@363
   448
        Icon = 0x2,
moel@363
   449
        Tip = 0x4,
moel@363
   450
        State = 0x8,
moel@363
   451
        Info = 0x10
moel@363
   452
      }
moel@363
   453
moel@363
   454
      [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
moel@363
   455
      public class NotifyIconData {
moel@363
   456
        private int Size = Marshal.SizeOf(typeof(NotifyIconData));
moel@363
   457
        public IntPtr Window;
moel@363
   458
        public int ID;
moel@363
   459
        public NotifyIconDataFlags Flags;
moel@363
   460
        public int CallbackMessage;
moel@363
   461
        public IntPtr Icon;
moel@363
   462
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
moel@363
   463
        public string Tip;
moel@363
   464
        public int State;
moel@363
   465
        public int StateMask;
moel@363
   466
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
moel@363
   467
        public string Info;
moel@363
   468
        public int TimeoutOrVersion;
moel@363
   469
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
moel@363
   470
        public string InfoTitle;
moel@363
   471
        public int InfoFlags;
moel@363
   472
      }
moel@363
   473
moel@363
   474
      public enum NotifyIconMessage : int {
moel@363
   475
        Add = 0x0,
moel@363
   476
        Modify = 0x1,
moel@363
   477
        Delete = 0x2
moel@363
   478
      }
moel@363
   479
moel@363
   480
      [DllImport("shell32.dll", CharSet = CharSet.Auto)]
moel@363
   481
      [return: MarshalAs(UnmanagedType.Bool)]
moel@363
   482
      public static extern bool Shell_NotifyIcon(NotifyIconMessage message,
moel@363
   483
        NotifyIconData pnid);
moel@363
   484
moel@363
   485
      [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
moel@363
   486
      public static extern bool TrackPopupMenuEx(HandleRef hmenu, int fuFlags,
moel@363
   487
        int x, int y, HandleRef hwnd, IntPtr tpm);
moel@363
   488
moel@363
   489
      [StructLayout(LayoutKind.Sequential)]
moel@363
   490
      public struct Point {
moel@363
   491
        public int x;
moel@363
   492
        public int y;
moel@363
   493
      }
moel@363
   494
moel@363
   495
      [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
moel@363
   496
      public static extern bool GetCursorPos(ref Point point);
moel@363
   497
moel@363
   498
      [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
moel@363
   499
      public static extern bool SetForegroundWindow(HandleRef hWnd);
moel@363
   500
    }
moel@363
   501
  }
moel@363
   502
}