• 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 lprc
    22          );
    23 
    24         [StructLayout(LayoutKind.Sequential)]
    25         private struct RECT
    26         { // 上面那位用的结构,表示前弹出菜单可用的一个范围大小(一般是全屏幕都让它用,留着搞游戏或视频对话之类的朋友指定菜单可用的范围)
    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 r
    66                              );
    67                         }
    68                         else
    69                         { //如果没有定义过菜单关联
    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 @ http://zpcity.com/arli/
      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         #endregion
     97 
     98         /// <summary>
     99         /// 建一个结构
    100         /// </summary>
    101         private NOTIFYICONDATA GetNOTIFYICONDATA(IntPtr iconHwnd, string sTip, string boxTitle, string boxText)
    102         {
    103             NOTIFYICONDATA nData = new NOTIFYICONDATA();
    104 
    105             nData.cbSize = System.Runtime.InteropServices.Marshal.SizeOf(nData); // 结构的大小
    106             nData.hwnd = formTmpHwnd; // 处理消息循环的窗体句柄,可以移成主窗体
    107             nData.uID = uID; // 消息的 WParam,回调时用
    108             nData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP | NIF_INFO; // 标志,表示由消息、图标、提示、信息组成
    109             nData.uCallbackMessage = WM_NOTIFY_TRAY; // 消息ID,回调用
    110             nData.hIcon = iconHwnd; // 图标的句柄,有兴趣的话可以定时改变它变成动画ICON
    111             nData.uTimeoutAndVersion = 10 * 1000 | NOTIFYICON_VERSION; // 提示的超时值(几秒后自动消失)和版本
    112             nData.dwInfoFlags = NIIF_INFO; // 类型标志,有INFO、WARNING、ERROR,更改此值将影响气泡提示框的图标类型
    113 
    114             nData.szTip = sTip; // 图标的提示信息
    115             nData.szInfoTitle = boxTitle; // 气泡提示框的标题
    116             nData.szInfo = boxText; // 气泡提示框的提示内容
    117 
    118             return nData; // 这个嘛。。。
    119         }
    120 
    121         private int GetShell32VersionInfo()
    122         { // 返回shell32 的版本
    123             FileInfo fi = new FileInfo(Path.Combine(System.Environment.SystemDirectory, "shell32.dll")); //将来的平台shell32 放哪目前不得而知,碰到再改
    124             if (fi.Exists)
    125             {
    126                 FileVersionInfo theVersion = FileVersionInfo.GetVersionInfo(fi.FullName);
    127                 int i = theVersion.FileVersion.IndexOf('.');
    128                 if (i > 0)
    129                 {
    130                     try
    131                     {
    132                         return int.Parse(theVersion.FileVersion.Substring(0, i));
    133                     }
    134                     catch { }
    135                 }
    136             }
    137             return 0;
    138         }
    139 
    140         /// <summary>
    141         /// 加一个新图标
    142         /// </summary>
    143         /// <param name="iconHwnd">图标句柄</param>
    144         /// <param name="sTip">提示, 5.0 最大: 128 char</param>
    145         /// <param name="boxTitle">气泡标题, 最大: 64 char</param>
    146         /// <param name="boxText">气泡内容, 最大: 256 char</param>
    147         /// <returns>成功、失败或错误(-1)</returns>
    148         public int AddNotifyBox(IntPtr iconHwnd, string sTip, string boxTitle, string boxText)
    149         {
    150             if (!this.VersionOk) return -1;
    151 
    152             NOTIFYICONDATA nData = GetNOTIFYICONDATA(iconHwnd, sTip, boxTitle, boxText);
    153             if (Shell_NotifyIcon(NIM_ADD, ref nData))
    154             {
    155                 this.forgetDelNotifyBox = true;
    156                 return 1;
    157             }
    158             else
    159             {
    160                 return 0;
    161             }
    162         }
    163 
    164         /// <summary>
    165         /// 和add 差不多,不重复了
    166         /// </summary>
    167         public int DelNotifyBox()
    168         {
    169             if (!this.VersionOk) return -1;
    170 
    171             NOTIFYICONDATA nData = GetNOTIFYICONDATA(IntPtr.Zero, null, null, null);
    172             if (Shell_NotifyIcon(NIM_DELETE, ref nData))
    173             {
    174                 this.forgetDelNotifyBox = false;
    175                 return 1;
    176             }
    177             else
    178             {
    179                 return 0;
    180             }
    181         }
    182 
    183         public int ModiNotifyBox(IntPtr iconHwnd, string sTip, string boxTitle, string boxText)
    184         {
    185             if (!this.VersionOk) return -1;
    186 
    187             NOTIFYICONDATA nData = GetNOTIFYICONDATA(iconHwnd, sTip, boxTitle, boxText);
    188             return Shell_NotifyIcon(NIM_MODIFY, ref nData) ? 1 : 0;
    189         }
    190 
    191         #region Optional Module //这里是可选方法
    192         /// <summary>
    193         /// 连接一个已存在的 contextMenu
    194         /// </summary>
    195         /// <param name="_formHwnd">窗体句柄,用来处理菜单的消息</param>
    196         /// <param name="_contextMenuHwnd">菜单的句柄</param>
    197         public void ConnectMyMenu(IntPtr _formHwnd, IntPtr _contextMenuHwnd)
    198         {
    199             formHwnd = _formHwnd;
    200             contextMenuHwnd = _contextMenuHwnd;
    201         }
    202 
    203         /// <summary>
    204         /// 立即清理掉图标、委托和formtmp 资源(好象没什么资源,考虑到可能二次开发挂接就开了这个东东)
    205         /// </summary>
    206         public void Dispose()
    207         {
    208             _delegateOfCallBack = null;
    209             this.formTmp.Dispose();
    210         }
    211 
    212         /// <summary>
    213         /// 版本适合
    214         /// </summary>
    215         public bool VersionPass
    216         {
    217             get
    218             {
    219                 return this.VersionOk;
    220             }
    221         }
    222         #endregion
    223     }

    用法示例:

    1 private void button2_Click (object sender, System.EventArgs e) {
    2     Shell_NotifyIconEx ().AddNotifyBox (this.Icon.Handle, this.Text, "这是标题", "单击这里开始,我将带你畅游API 世界");
    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); //定义回调
    }
    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);
      }

    本文来自:http://blog.sina.com.cn/s/blog_6c0affba0100pi0e.html

  • 相关阅读:
    Node.js安装及环境配置之Windows篇
    盘点.NET JIT在Release下由循环体优化所产生的不确定性Bug
    开源!一款功能强大的高性能二进制序列化器Bssom.Net
    开源 , KoobooJson一款高性能且轻量的JSON框架
    通俗易懂,什么是.NET?什么是.NET Framework?什么是.NET Core?
    .Net Web开发技术栈
    web安全:通俗易懂,以实例讲述破解网站的原理及如何进行防护!如何让网站变得更安全。
    .Net高级进阶,教你如何构建企业模型数据拦截层,动态控制字段验证
    .Net 如何模拟会话级别的信号量,对http接口调用频率进行限制(有demo)
    .Net高级进阶,在复杂的业务逻辑下,如何以最简练的代码,最直观的编写事务代码?
  • 原文地址:https://www.cnblogs.com/zhangliang2008/p/14010248.html
Copyright © 2020-2023  润新知