C# WinForm调用Shell_NotifyIcon的示例代码

  public class Shell_NotifyIconEx

  {

  ///

  /// ArLi, last fix: 2003.9.12, reference: ArLi.CommonPrj Lib @ http://zpcity.com/arli/

  ///

  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

  );

  ///

  /// 此API 的作用是当 this.focus() 无效时可以考虑使用,效果很好

  ///

  /// this.Handle, 当前窗体句柄

  [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

  ///

  /// 建一个结构

  ///

  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;

  }

  ///

  /// 加一个新图标

  ///

  /// 图标句柄

  /// 提示, 5.0 最大: 128 char

  /// 气泡标题, 最大: 64 char

  /// 气泡内容, 最大: 256 char

  /// 成功、失败或错误(-1)

  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;

  }

  }

  ///

  /// 和add 差不多,不重复了

  ///

  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 //这里是可选方法

  ///

  /// 连接一个已存在的 contextMenu

  ///

  /// 窗体句柄,用来处理菜单的消息

  /// 菜单的句柄

  public void ConnectMyMenu(IntPtr _formHwnd, IntPtr _contextMenuHwnd)

  {

  formHwnd = _formHwnd;

  contextMenuHwnd = _contextMenuHwnd;

  }

  ///

  /// 立即清理掉图标、委托和formtmp 资源(好象没什么资源,考虑到可能二次开发挂接就开了这个东东)

  ///

  public void Dispose()

  {

  _delegateOfCallBack = null;

  this.formTmp.Dispose();

  }

  ///

  /// 版本适合

  ///

  public bool VersionPass

  {

  get

  {

  return this.VersionOk;

  }

  }

  #endregion

  }