2020年11月20日星期五

C# WinForm调用Shell_NotifyIcon

 1  public class InnerClass: Form 2  { 3   private Shell_NotifyIconEx servicesClass = null; // 接受主CLASS 的实例句柄 4   internal InnerClass(Shell_NotifyIconEx _servicesClass) 5   { 6    servicesClass = _servicesClass; 7   } 8  9   private const int WM_LBUTTONDOWN = 0x0201; // 左键10   private const int WM_RBUTTONDOWN = 0x204; // 右键11   private const int WM_MBUTTONDOWN = 0x207; // 中键12 13   [DllImport("user32.dll", EntryPoint = "TrackPopupMenu")]14   private static extern int TrackPopupMenu( // c# 和vb.net 好象没有了随地popup 了,只要请它老人家出马了15    IntPtr hMenu,16   int wFlags,17   int x,18   int y,19   int nReserved,20    IntPtr hwnd,21   ref RECT lprc22    );23 24   [StructLayout(LayoutKind.Sequential)]25   private struct RECT26   { // 上面那位用的结构,表示前弹出菜单可用的一个范围大小(一般是全屏幕都让它用,留着搞游戏或视频对话之类的朋友指定菜单可用的范围)27    internal int Left;28    internal int Top;29    internal int Right;30    internal int Bottom;31   }32 33   protected override void WndProc(ref Message msg)34   {35    if (msg.Msg == servicesClass.WM_NOTIFY_TRAY)36    { // 如果消息相符37     if ((int)msg.WParam == servicesClass.uID)38     { // 并且消息的WParam 相符39     MouseButtons mb =MouseButtons.None;40      if ((int)msg.LParam == WM_LBUTTONDOWN)41      { //如果点击的是左键42       mb =MouseButtons.Left;43      }44      else if ((int)msg.LParam == WM_MBUTTONDOWN)45      { //中键46       mb =MouseButtons.Middle;47      }48      else if ((int)msg.LParam == WM_RBUTTONDOWN)49      { //右键50       if (servicesClass.contextMenuHwnd != IntPtr.Zero)51       { //如果有定义过菜单关联52        RECT r = new RECT();53        r.Left = Screen.PrimaryScreen.WorkingArea.Left;54        r.Right =Screen.PrimaryScreen.WorkingArea.Right;55        r.Top =Screen.PrimaryScreen.WorkingArea.Top;56        r.Bottom =Screen.PrimaryScreen.WorkingArea.Right;57 58        TrackPopupMenu(59         servicesClass.contextMenuHwnd,60        2,61        Cursor.Position.X,62        Cursor.Position.Y,63        0,64         servicesClass.formHwnd,65        ref r66         );67       }68       else69       { //如果没有定义过菜单关联70        mb =MouseButtons.Right;71       }72      }73 74      if (mb !=MouseButtons.None && servicesClass._delegateOfCallBack != null)75      {76       servicesClass._delegateOfCallBack(mb); // 执行回调77       return;78      }79     }80    }81 82    base.WndProc(ref msg);83   }84  }
 1 public class Shell_NotifyIconEx 2  { 3   /// <summary> 4   /// ArLi, last fix: 2003.9.12, reference: ArLi.CommonPrj Lib @  5   /// </summary> 6   public static readonly System.Version myVersion = new System.Version(1, 2); //版本声明 7  8   private readonly InnerClass formTmp = null; // 这个很重要,不能放在构造里,因为它必须和此实例同等生存期才不会被中止消息循环 9   private readonly IntPtr formTmpHwnd = IntPtr.Zero; // 这是上一行的句柄 10   private readonly bool VersionOk = false; // 这是一个由VersionPass 返回的属性,它允许开发者检测当前机子的Shell32.dll(可能在win95 或未知平台上版本) 合适此组,不符则用.net 自己的notifyicon 11   private bool forgetDelNotifyBox = false; // 这是一个私有标志,它允许开发者在程序退出时忘记调用DelNotifyBox 来清除图标时会自动在析构里清掉它。 12  13   internal IntPtr formHwnd = IntPtr.Zero; // 这是调用此组件的主窗口句柄(当前实例有效,可多个icon 不冲突) 14   internal IntPtr contextMenuHwnd = IntPtr.Zero; // 这是菜单的句柄(当前实例有效,可多个icon 不冲突) 15  16   internal delegate void delegateOfCallBack(System.Windows.Forms.MouseButtons mb); 17   internal delegateOfCallBack _delegateOfCallBack = null; 18  19   public Shell_NotifyIconEx() // 构造 20   { 21    WM_NOTIFY_TRAY += 1; // 消息ID +1,避免多个ICON 消息处理冲突 22    uID += 1; // 同上 23    formTmp = new InnerClass(this); // 新实例一个消息循环 24    formTmpHwnd = formTmp.Handle; // 新实例句柄 25    VersionOk = this.GetShell32VersionInfo() >= 5; // 版本是否合适,此组件由于重点在气泡提示,它要求Shell32.dll 5.0(ie 5.0) 以上 26   } 27  28   ~Shell_NotifyIconEx() 29   { // 析构 30    if (forgetDelNotifyBox) this.DelNotifyBox(); //如果开发者忘记则清理icon 31   } 32  33   #region API_Consts 34   internal readonly int WM_NOTIFY_TRAY = 0x0400 + 2001; //readonly 表示只在构造可付值 35   internal readonly int uID = 5000; 36  37   // 常数定义,有VC 的可以参见 shellapi.h 38   private const int NIIF_NONE = 0x00; 39   private const int NIIF_INFO = 0x01; 40   private const int NIIF_WARNING = 0x02; 41   private const int NIIF_ERROR = 0x03; 42  43   private const int NIF_MESSAGE = 0x01; 44   private const int NIF_ICON = 0x02; 45   private const int NIF_TIP = 0x04; 46   private const int NIF_STATE = 0x08; 47   private const int NIF_INFO = 0x10; 48  49   private const int NIM_ADD = 0x00; 50   private const int NIM_MODIFY = 0x01; 51   private const int NIM_DELETE = 0x02; 52   private const int NIM_SETFOCUS = 0x03; 53   private const int NIM_SETVERSION = 0x04; 54  55   private const int NIS_HIDDEN = 0x01; 56   private const int NIS_SHAREDICON = 0x02; 57  58   private const int NOTIFYICON_OLDVERSION = 0x00; 59   private const int NOTIFYICON_VERSION = 0x03; 60  61   [DllImport("shell32.dll", EntryPoint = "Shell_NotifyIcon")] 62   private static extern bool Shell_NotifyIcon( // 这位是主角 63    int dwMessage, 64    ref NOTIFYICONDATA lpData 65   ); 66  67   /// <summary> 68   /// 此API 的作用是当 this.focus() 无效时可以考虑使用,效果很好 69   /// </summary> 70   /// <param name="hwnd">this.Handle, 当前窗体句柄</param> 71   [DllImport("user32.dll", EntryPoint = "SetForegroundWindow")] 72   public static extern int SetForegroundWindow( 73    IntPtr hwnd 74   ); 75  76   [StructLayout(LayoutKind.Sequential)] 77   private struct NOTIFYICONDATA 78   { // 主角用的结构 79    internal int cbSize; 80    internal IntPtr hwnd; 81    internal int uID; 82    internal int uFlags; 83    internal int uCallbackMessage; 84    internal IntPtr hIcon; 85    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x80)] 86    internal string szTip; 87    internal int dwState; // 这里往下几个是 5.0 的精华 88    internal int dwStateMask; 89    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0xFF)] 90    internal string szInfo; 91    internal int uTimeoutAndVersion; 92    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x40)] 93    internal string szInfoTitle; 94    internal int dwInfoFlags; 95   } 96   

没有评论:

发表评论