C# WinForm调用Shell_NotifyIcon的示例代码

2022-07-27,,,

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
 }

用法示例:

 private void button2_click (object sender, system.eventargs e) {
  shell_notifyiconex ().addnotifybox (this.icon.handle, this.text, "这是标题", "单击这里开始,我将带你畅游api 世界");
 }
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);
 }

以上就是c# winform调用shell_notifyicon的示例代码的详细内容,更多关于c# winform调用shell_notifyicon的资料请关注其它相关文章!

《C# WinForm调用Shell_NotifyIcon的示例代码.doc》

下载本文的Word格式文档,以方便收藏与打印。