C# WinForm调用Shell_NotifyIcon的示例代码

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的资料请关注我们其它相关文章!

(0)

相关推荐

  • C# WinForm实现图片浏览器

    C#WinForm程序设计之图片浏览器,这次我们一起做一个图片查看器,这个图片查看器的原始图如下: 我们首先来介绍一下这个原始图的构成: 左边上面是一个 TextBox 和 一个 Button,分别用来显示当前路径以及返回上一个路径.左边下面是一个浏览文件的文件路径树状图(TreeView),用来显示当前路径下的文件和文件夹.右边是一个pictureBox,用来展示选中的图片. 接下来我们一步一步实现这个图片查看器! 首先大家应该看到了左边的TreeView上面已经有显示当前PC的所有路径信息,

  • C#在Winform开发中使用Grid++报表

    之前一直使用各种报表工具,如RDLC.DevExpress套件的XtraReport报表,在之前一些随笔也有介绍,最近接触锐浪的Grid++报表,做了一些测试例子和辅助类来处理报表内容,觉得还是很不错的,特别是它的作者提供了很多报表的设计模板案例,功能还是非常强大的.试着用来做一些简单的报表,测试下功能,发现常规的二维表.套打.条形码二维码等我关注的功能都有,是一个比较强大的报表控件,本篇随笔主要介绍在Winform开发中使用Grid++报表设计报表模板,以及绑定数据的处理过程. 1.报表模板设

  • C# Winform调用百度接口实现人脸识别教程(附源码)

    百度是个好东西,这篇调用了百度的接口(当然大牛也可以自己写),人脸检测技术,所以使用的前提是有网的情况下.当然大家也可以去参考百度的文档. 话不多说,我们开始: 第一步,在百度创建你的人脸识别应用 打开百度AI开放平台链接: 点击跳转百度人脸检测链接,创建新应用 创建成功成功之后.进行第二步 第二步,使用API Key和Secret Key,获取 AssetToken 平台会分配给你相关凭证,拿到API Key和Secret Key,获取 AssetToken 接下来我们创建一个AccessTo

  • C# Winform中如何绘制动画示例详解

    前言 这里介绍一个.net自身携带的类ImageAnimator,这个类类似于控制动画的时间轴,使用ImageAnimator.CanAnimate可以判断一个图片是否为动画,调用ImageAnimator.Animate可以开始播放动画,即每经过一帧的时间触发一次OnFrameChanged委托,我们只要在该委托中将Image的活动帧选至下一帧再迫使界面重绘就可以实现动画效果了. 为了方便以后的使用,我将这些代码整合到了一起,形成一个AnimateImage类,该类提供了CanAnimate.

  • c# Winform自定义控件-仪表盘功能

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:https://gitee.com/kwwwvagaa/net_winform_custom_control.git NuGet Install-Package HZH_Controls 目录 https://www.cnblogs.com/bfyx/p/11364884.html 用处及效果 准备工作

  • c# winform异步不卡界面的实现方法

    快速阅读 如何在winform程序中,让界面不再卡死. 关于委托和AsyncCallback的使用. 界面卡死的原因是因为耗时任务的计算占用了主线程,导致主界面没有办法进行其它操作,比如拖动.造成界面卡死的现象.我们只需要把耗时任务放在子线程中执行就可以了. 子线程的计算结果 要更新到界面中,怎么更新呢,因为不能操作主线程 ,所以要用委托来实现 . 我们来看个例子. 场景 界面上一个按钮加一人richbox , 点击以后获得当前所在年份 代码实现 定义一个委托实现子线程更新主线程 public

  • c# WinForm 窗体之间传值的几种方式(小结)

    前言 小编最近维护一个Winfrom窗体,是项目中CS端的主窗体,很多子窗体需要从主窗体获取值,同时子窗体还需要给主窗体回传值,下面来给大家介绍一下. 正文 本文中以主窗体为frmMain,子窗体为frmGroup ,两窗体之间的传值来做示例. 方式一: 使用公共静态变量传值 主窗体frmMain中代码 public partial class frmMain : Form { //声明工位ID 为公共静态变量 public static string terminalID = "";

  • C# winform主界面打开并关闭登录界面的方法

    在winform 界面编程中,我们有时候要在主界面打开之前先显示登录界面,当登录界面用户信息校验正确后才打开主界面,而这时登陆界面也完成使命该功成身退了. 目前有两种方法可实现: 方法1. 隐藏登录界面 Program.cs 中代码如下: /// <summary> /// 应用程序的主入口点. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.

  • C# winForm实现的气泡提示窗口功能示例

    本文实例讲述了C# winForm实现的气泡提示窗口功能.分享给大家供大家参考,具体如下: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace WindowsFormsApplication60 { p

  • C# Winform实现导入和导出Excel文件

    本文实例为大家分享了Winform实现导入导出Excel文件的具体代码,供大家参考,具体内容如下 /// <summary> /// 导出Excel文件 /// </summary> /// /// <param name="dataSet"></param> /// <param name="dataTable">数据集</param> /// <param name="isS

  • C# winform程序实现开机自启动并且识别是开机启动还是双击启动

    开机启动程序,在很多场合都会用到,尤其是那种在后台运行的程序. 效果图: 以上两幅图都用到了命令行启动程序,为了模拟开机启动或者其他程序调用此程序. 第一幅图:程序启动可以根据不同参数,执行不同的操作.如果是双击启动,就自动运行逻辑代码,如果是带特定参数启动,就自动运行逻辑代码. 第二幅图:winform 程序设置开机启动,模拟双击启动和开机启动的不同效果. 开机启动并自动运行方法:其实思路很简单,就是将程序添加到注册表中,这设置值的时候,加一个参数就可以了.然后程序在入口函数处判断启动参数,如

  • C#Winform窗口移动方法

    在我们将Winform自带的边框隐藏之后,我们需要自己编写窗口的移动. 思路就是 1.获得点击左键时当前鼠标的坐标 2.获得移动后鼠标的坐标 3.窗体的坐标=移动后的鼠标坐标-移动前的鼠标坐标 private Point mouseOff;//鼠标移动位置变量 private bool leftFlag;//鼠标是否为左键 private void Form1_MouseDown(object sender, MouseEventArgs e) { if(e.Button == MouseBut

随机推荐