C# WinForm调用Shell_NotifyIcon的示例代码
作者:正在缓冲 发布时间:2021-07-17 16:04:41
标签: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);
}
来源:https://www.cnblogs.com/zhangliang2008/p/14010248.html


猜你喜欢
- 前言在Android开发过程中,Bitmap往往会给开发者带来一些困扰,因为对Bitmap操作不慎,就容易造成OOM(Java.lang.O
- 效果图如下: Recyclerview 实现多选,单选,全选,反选,批量删除的步骤1.在Recyclerview布局中
- 项目初始流程:首先说一下pom.xml文件的依赖: <dependencies><!-- junit 测试 -->
- disruptor不过多介绍了,描述下当前的业务场景,两个应用A,B,应用 A 向应用 B 传递数据 . 数据传送比较快,如果用http直接
- 本文是利用SharpPcap实现网络包的捕获的小例子,实现了端口监控,数据包捕获等功能,主要用于学习分享。什么是SharpPcap?Shar
- 问题描述:输入:两个日期输出:两个日期相差的天数具体代码实现方法1:通过Calendar类的日期比较。注意:这里需要考虑一下:日期是跨年份的
- Scala异常处理Scala是一种多范式的编程语言,支持面向对象和函数式编程。Scala也支持异常处理,即在程序运行过程中发生意外或错误时,
- 使用RNGCryptoServiceProvider类创建唯一的最多8位数字符串,再在前面拼接上年月日时分秒产生的字符串,最大限度的保证生成
- mybatis在持久层框架中还是比较火的,一般项目都是基于ssm。虽然mybatis可以直接在xml中通过SQL语句操作数据库,很是灵活。但
- 适配器模式是一种重要的设计模式,在 Android 中得到了广泛的应用。适配器类似于现实世界里面的插头,通过适配器,我们可以将分属于不同类的
- 重载,继承,重写和多态的区别:1)继承是子类获得父类的成员。2)重写是继承后重新实现父类的方法。 3)重载是在一个类里一系列参数不同名字相同
- 一,简介Feign使得 Java HTTP 客户端编写更方便。Feign 灵感来源于Retrofit、JAXRS-2.0和WebSocket
- 测试环境为Adnroid 2.1以上。 1.AndroidManifest.xml 权限配置: 添加互联网访问权限: <uses-pe
- 1)首先启动hadoop2个进程,进入hadoop/sbin目录下,依次启动如下命令[root@node02 sbin]# pwd/usr/
- json是种常用的数据传输格式,在android开发中,如何借助java语言实现对json数组对象的解析呢,请参阅下面的关键代码:impor
- 被覆盖比较好理解,类似于多态的实现,访问时通过类方法表来访问,你实际是什么类型,访问的方法就是那个类型的方法而不会是你的父类的方法。被隐藏是
- 前言:上篇C#进阶系列——WebApi接口传参不再困惑:传参详解介绍了WebApi参数的传递,这篇来看看WebApi里面异常的处理。关于异常
- 目录前言if-thenif-then-elseswitch使用 Stringwhiledo-whileforbreakcontinueret
- 前面聊了布隆过滤器,回归认识一下位图BitMap,阅读前文的同学应该发现了布隆过滤器本身就是基于位图,是位图的一种改进。位图先看一个问题,
- 本文实例讲述了C#使用HttpDownLoadHelper下载文件的方法。分享给大家供大家参考。具体实现方法如下:using System;