C# WinForm调用Shell_NotifyIcon

  • A+
所属分类:.NET技术
摘要

用法示例:本文来自:http://blog.sina.com.cn/s/blog_6c0affba0100pi0e.html

 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