关键词搜索

源码搜索 ×
×

C# WinForm调用Shell_NotifyIcon的示例代码

发布2021-05-12浏览508次

详情内容

public class InnerClass: Form
 {
  private Shell_NotifyIconEx servicesClass = null; // 接受主CLASS 的实例句柄
  internal InnerClass(Shell_NotifyIconEx _servicesClass)
  {
   servicesClass = _servicesClass;
  }
 
  private const int WM_LBUTTONDOWN = 0x0201; // 左键
  private const int WM_RBUTTONDOWN = 0x204; // 右键
  private const int WM_MBUTTONDOWN = 0x207; // 中键
 
  [DllImport("user32.dll", EntryPoint = "TrackPopupMenu")]
  private static extern int TrackPopupMenu( // c# 和vb.net 好象没有了随地popup 了,只要请它老人家出马了
   IntPtr hMenu,
   int wFlags,
   int x,
   int y,
   int nReserved,
   IntPtr hwnd,
   ref RECT lprc
   );
 
  [StructLayout(LayoutKind.Sequential)]
  private struct RECT
  { // 上面那位用的结构,表示前弹出菜单可用的一个范围大小(一般是全屏幕都让它用,留着搞游戏或视频对话之类的朋友指定菜单可用的范围)
   internal int Left;
   internal int Top;
   internal int Right;
   internal int Bottom;
  }
 
  protected override void WndProc(ref Message msg)
  {
   if (msg.Msg == servicesClass.WM_NOTIFY_TRAY)
   { // 如果消息相符
    if ((int)msg.WParam == servicesClass.uID)
    { // 并且消息的WParam 相符
     MouseButtons mb =MouseButtons.None;
     if ((int)msg.LParam == WM_LBUTTONDOWN)
     { //如果点击的是左键
      mb =MouseButtons.Left;
     }
     else if ((int)msg.LParam == WM_MBUTTONDOWN)
     { //中键
      mb =MouseButtons.Middle;
     }
     else if ((int)msg.LParam == WM_RBUTTONDOWN)
     { //右键
      if (servicesClass.contextMenuHwnd != IntPtr.Zero)
      { //如果有定义过菜单关联
       RECT r = new RECT();
       r.Left = Screen.PrimaryScreen.WorkingArea.Left;
       r.Right =Screen.PrimaryScreen.WorkingArea.Right;
       r.Top =Screen.PrimaryScreen.WorkingArea.Top;
       r.Bottom =Screen.PrimaryScreen.WorkingArea.Right;
 
       TrackPopupMenu(
        servicesClass.contextMenuHwnd,
        2,
       Cursor.Position.X,
       Cursor.Position.Y,
        0,
        servicesClass.formHwnd,
        ref r
        );
      }
      else
      { //如果没有定义过菜单关联
       mb =MouseButtons.Right;
      }
     }
 
     if (mb !=MouseButtons.None && servicesClass._delegateOfCallBack != null)
     {
      servicesClass._delegateOfCallBack(mb); // 执行回调
      return;
     }
    }
   }
 
   base.WndProc(ref msg);
  }
 }
    public class Shell_NotifyIconEx
     {
      /// <summary>
      /// ArLi, last fix: 2003.9.12, reference: ArLi.CommonPrj Lib @ http://zpcity.com/arli/
      /// </summary>
      public static readonly System.Version myVersion = new System.Version(1, 2); //版本声明
     
      private readonly InnerClass formTmp = null; // 这个很重要,不能放在构造里,因为它必须和此实例同等生存期才不会被中止消息循环
      private readonly IntPtr formTmpHwnd = IntPtr.Zero; // 这是上一行的句柄
      private readonly bool VersionOk = false; // 这是一个由VersionPass 返回的属性,它允许开发者检测当前机子的Shell32.dll(可能在win95 或未知平台上版本) 合适此组,不符则用.net 自己的notifyicon
      private bool forgetDelNotifyBox = false; // 这是一个私有标志,它允许开发者在程序退出时忘记调用DelNotifyBox 来清除图标时会自动在析构里清掉它。
     
      internal IntPtr formHwnd = IntPtr.Zero; // 这是调用此组件的主窗口句柄(当前实例有效,可多个icon 不冲突)
      internal IntPtr contextMenuHwnd = IntPtr.Zero; // 这是菜单的句柄(当前实例有效,可多个icon 不冲突)
     
      internal delegate void delegateOfCallBack(System.Windows.Forms.MouseButtons mb);
      internal delegateOfCallBack _delegateOfCallBack = null;
     
      public Shell_NotifyIconEx() // 构造
      {
       WM_NOTIFY_TRAY += 1; // 消息ID +1,避免多个ICON 消息处理冲突
       uID += 1; // 同上
       formTmp = new InnerClass(this); // 新实例一个消息循环
       formTmpHwnd = formTmp.Handle; // 新实例句柄
       VersionOk = this.GetShell32VersionInfo() >= 5; // 版本是否合适,此组件由于重点在气泡提示,它要求Shell32.dll 5.0(ie 5.0) 以上
      }
     
      ~Shell_NotifyIconEx()
      { // 析构
       if (forgetDelNotifyBox) this.DelNotifyBox(); //如果开发者忘记则清理icon
      }
     
      #region API_Consts
      internal readonly int WM_NOTIFY_TRAY = 0x0400 + 2001; //readonly 表示只在构造可付值
      internal readonly int uID = 5000;
     
      // 常数定义,有VC 的可以参见 shellapi.h
      private const int NIIF_NONE = 0x00;
      private const int NIIF_INFO = 0x01;
      private const int NIIF_WARNING = 0x02;
      private const int NIIF_ERROR = 0x03;
     
      private const int NIF_MESSAGE = 0x01;
      private const int NIF_ICON = 0x02;
      private const int NIF_TIP = 0x04;
      private const int NIF_STATE = 0x08;
      private const int NIF_INFO = 0x10;
     
      private const int NIM_ADD = 0x00;
      private const int NIM_MODIFY = 0x01;
      private const int NIM_DELETE = 0x02;
      private const int NIM_SETFOCUS = 0x03;
      private const int NIM_SETVERSION = 0x04;
     
      private const int NIS_HIDDEN = 0x01;
      private const int NIS_SHAREDICON = 0x02;
     
      private const int NOTIFYICON_OLDVERSION = 0x00;
      private const int NOTIFYICON_VERSION = 0x03;
     
      [DllImport("shell32.dll", EntryPoint = "Shell_NotifyIcon")]
      private static extern bool Shell_NotifyIcon( // 这位是主角
       int dwMessage,
       ref NOTIFYICONDATA lpData
      );
     
      /// <summary>
      /// 此API 的作用是当 this.focus() 无效时可以考虑使用,效果很好
      /// </summary>
      /// <param name="hwnd">this.Handle, 当前窗体句柄</param>
      [DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
      public static extern int SetForegroundWindow(
       IntPtr hwnd
      );
     
      [StructLayout(LayoutKind.Sequential)]
      private struct NOTIFYICONDATA
      { // 主角用的结构
       internal int cbSize;
       internal IntPtr hwnd;
       internal int uID;
       internal int uFlags;
       internal int uCallbackMessage;
       internal IntPtr hIcon;
       [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x80)]
       internal string szTip;
       internal int dwState; // 这里往下几个是 5.0 的精华
       internal int dwStateMask;
       [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0xFF)]
       internal string szInfo;
       internal int uTimeoutAndVersion;
       [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x40)]
       internal string szInfoTitle;
       internal int dwInfoFlags;
      }
      #endregion
     
      /// <summary>
      /// 建一个结构
      /// </summary>
      private NOTIFYICONDATA GetNOTIFYICONDATA(IntPtr iconHwnd, string sTip, string boxTitle, string boxText)
      {
       NOTIFYICONDATA nData = new NOTIFYICONDATA();
     
       nData.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(nData); // 结构的大小
       nData.hwnd = formTmpHwnd; // 处理消息循环的窗体句柄,可以移成主窗体
       nData.uID = uID; // 消息的 WParam,回调时用
       nData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO; // 标志,表示由消息、图标、提示、信息组成
       nData.uCallbackMessage = WM_NOTIFY_TRAY; // 消息ID,回调用
       nData.hIcon = iconHwnd; // 图标的句柄,有兴趣的话可以定时改变它变成动画ICON
       nData.uTimeoutAndVersion = 10 * 1000 | NOTIFYICON_VERSION; // 提示的超时值(几秒后自动消失)和版本
       nData.dwInfoFlags = NIIF_INFO; // 类型标志,有INFO、WARNING、ERROR,更改此值将影响气泡提示框的图标类型
     
       nData.szTip = sTip; // 图标的提示信息
       nData.szInfoTitle = boxTitle; // 气泡提示框的标题
       nData.szInfo = boxText; // 气泡提示框的提示内容
     
       return nData; // 这个嘛。。。
      }
     
      private int GetShell32VersionInfo()
      { // 返回shell32 的版本
       FileInfo fi = new FileInfo(Path.Combine(System.Environment.SystemDirectory, "shell32.dll")); //将来的平台shell32 放哪目前不得而知,碰到再改
       if (fi.Exists)
       {
        FileVersionInfo theVersion = FileVersionInfo.GetVersionInfo(fi.FullName);
        int i = theVersion.FileVersion.IndexOf('.');
        if (i > 0)
        {
         try
         {
          return int.Parse(theVersion.FileVersion.Substring(0, i));
         }
         catch { }
        }
       }
       return 0;
      }
     
      /// <summary>
      /// 加一个新图标
      /// </summary>
      /// <param name="iconHwnd">图标句柄</param>
      /// <param name="sTip">提示, 5.0 最大: 128 char</param>
      /// <param name="boxTitle">气泡标题, 最大: 64 char</param>
      /// <param name="boxText">气泡内容, 最大: 256 char</param>
      /// <returns>成功、失败或错误(-1)</returns>
      public int AddNotifyBox(IntPtr iconHwnd, string sTip, string boxTitle, string boxText)
      {
       if (!this.VersionOk) return -1;
     
       NOTIFYICONDATA nData = GetNOTIFYICONDATA(iconHwnd, sTip, boxTitle, boxText);
       if (Shell_NotifyIcon(NIM_ADD, ref nData))
       {
        this.forgetDelNotifyBox = true;
        return 1;
       }
       else
       {
        return 0;
       }
      }
     
      /// <summary>
      /// 和add 差不多,不重复了
      /// </summary>
      public int DelNotifyBox()
      {
       if (!this.VersionOk) return -1;
     
       NOTIFYICONDATA nData = GetNOTIFYICONDATA(IntPtr.Zero, null, null, null);
       if (Shell_NotifyIcon(NIM_DELETE, ref nData))
       {
        this.forgetDelNotifyBox = false;
        return 1;
       }
       else
       {
        return 0;
       }
      }
     
      public int ModiNotifyBox(IntPtr iconHwnd, string sTip, string boxTitle, string boxText)
      {
       if (!this.VersionOk) return -1;
     
       NOTIFYICONDATA nData = GetNOTIFYICONDATA(iconHwnd, sTip, boxTitle, boxText);
       return Shell_NotifyIcon(NIM_MODIFY, ref nData) ? 1 : 0;
      }
     
      #region Optional Module //这里是可选方法
      /// <summary>
      /// 连接一个已存在的 contextMenu
      /// </summary>
      /// <param name="_formHwnd">窗体句柄,用来处理菜单的消息</param>
      /// <param name="_contextMenuHwnd">菜单的句柄</param>
      public void ConnectMyMenu(IntPtr _formHwnd, IntPtr _contextMenuHwnd)
      {
       formHwnd = _formHwnd;
       contextMenuHwnd = _contextMenuHwnd;
      }
     
      /// <summary>
      /// 立即清理掉图标、委托和formtmp 资源(好象没什么资源,考虑到可能二次开发挂接就开了这个东东)
      /// </summary>
      public void Dispose()
      {
       _delegateOfCallBack = null;
       this.formTmp.Dispose();
      }
     
      /// <summary>
      /// 版本适合
      /// </summary>
      public bool VersionPass
      {
       get
       {
        return this.VersionOk;
       }
      }
      #endregion
     }
    
      85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223

    用法示例:

    private void button2_Click (object sender, System.EventArgs e) {
     Shell_NotifyIconEx ().AddNotifyBox (this.Icon.Handle, this.Text, "这是标题", "单击这里开始,我将带你畅游API 世界");
    }
    
    • 1
    • 2
    • 3
    private void GetPoc1 (MouseButtons mb) { // 回调处理
     if (mb == MouseButtons.Left) {
      MessageBox.Show ("来自菜单1");
     }
    }
    privateShell_NotifyIconEx o1 = newShell_NotifyIconEx (); //这个放外面是用在 o.DelNotifyBox
    private void button1_Click (object sender, System.EventArgs e) {
     o1.AddNotifyBox (this.Icon.Handle, this.Text, "菜单1", "单击这里开始,我将带你畅游API 世界");
     o1.ConnectMyMenu (this.Handle, this.contextMenu1.Handle); // 挂上菜单,可选
     o1._delegateOfCallBack = newShell_NotifyIconEx.delegateOfCallBack (GetPoc1); //定义回调
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    private void GetPoc1(MouseButtons mb) { // 回调处理
     if (mb == MouseButtons.Left) {
     MessageBox.Show("来自菜单1");
     }
     }
     private Shell_NotifyIconEx o1 = new Shell_NotifyIconEx(); //这个放外面是用在 o.DelNotifyBox
     private void button1_Click(object sender, System.EventArgs e) {
     o1.AddNotifyBox(this.Icon.Handle,this.Text,"菜单1","单击这里开始,我将带你畅游API 世界"); 
     o1.ConnectMyMenu(this.Handle,this.contextMenu1.Handle); // 挂上菜单,可选
     o1._delegateOfCallBack = new Shell_NotifyIconEx.delegateOfCallBack(GetPoc1); //定义回调
     }
     private void GetPoc2(MouseButtons mb) {
     if (mb == MouseButtons.Left) {
     MessageBox.Show("来自菜单2");
     }
     }
     private Shell_NotifyIconEx o2 = new Shell_NotifyIconEx(); //第二个nofityicon 和上面一样
     private void button2_Click(object sender, System.EventArgs e) {
     o2.AddNotifyBox(this.Icon.Handle,this.Text,"菜单2","单击这里开始,我将带你畅游API 世界"); 
     o2.ConnectMyMenu(this.Handle,this.contextMenu2.Handle);
     o2._delegateOfCallBack = new Shell_NotifyIconEx.delegateOfCallBack(GetPoc2);
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    以上就是C# WinForm调用Shell_NotifyIcon的示例代码vb.net教程的详细内容

    相关技术文章

    点击QQ咨询
    开通会员
    返回顶部
    ×
    微信扫码支付
    微信扫码支付
    确定支付下载
    请使用微信描二维码支付
    ×

    提示信息

    ×

    选择支付方式

    • 微信支付
    • 支付宝付款
    确定支付下载