写了个在wpf中使用Windows API实现系统托盘图标的类
本帖最后由 shiy720 于 2025-3-5 19:47 编辑在WPF中通过Windows API实现系统托盘图标需调用Shell_NotifyIcon及相关Win32函数,以下是具体步骤
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Wxapp.Common.win32
{
public class TrayIcon
{
private const int WM_USER = 0x0400;
private const int WM_LBUTTONDBLCLK = 0x0203;
private const int WM_RBUTTONUP = 0x0205;
private const int NIM_ADD = 0x00000000;
private const int NIM_MODIFY = 0x00000001;
private const int NIM_DELETE = 0x00000002;
private const int NIF_MESSAGE = 0x00000001;
private const int NIF_ICON = 0x00000002;
private const int NIF_TIP = 0x00000004;
private struct NOTIFYICONDATA
{
public int cbSize;
public IntPtr hWnd;
public int uID;
public int uFlags;
public int uCallbackMessage;
public IntPtr hIcon;
public string szTip;
}
private static extern bool Shell_NotifyIcon(int dwMessage, ref NOTIFYICONDATA lpData);
private static extern IntPtr LoadIcon(IntPtr hInstance, IntPtr lpIconName);
private static extern bool DestroyIcon(IntPtr hIcon);
#region 创建右键菜单
private static extern IntPtr CreatePopupMenu();
public static extern bool AppendMenu(IntPtr hMenu, int uFlags, int uIDNewItem, string lpNewItem);
private static extern int TrackPopupMenuEx(IntPtr hMenu, uint uFlags, int x, int y, IntPtr hwnd, IntPtr lptpm);
private static extern bool DestroyMenu(IntPtr hMenu);
#endregion
#region 获取鼠标右键位置
// 定义 POINT 结构体
public struct POINT
{
public int X;
public int Y;
}
// 定义 Win32 API 函数
private static extern bool GetCursorPos(out POINT lpPoint);
#endregion
#region 定义事件 与 保护方法
public event Action OnShowWindow;
protected virtual void ShowWindow() => OnShowWindow?.Invoke();
public event Action OnCloseWindow;
protected virtual void CloseWindow() => OnCloseWindow?.Invoke();
public event Action<Exception> Error;
protected virtual void OnError(Exception ex) => Error?.Invoke(ex);
#endregion
private NOTIFYICONDATA notifyIconData;
private IntPtr hIcon;
private IntPtr popupMenu;
private nint wHandle;
public TrayIcon(nint _wHandle)
{
this.wHandle = _wHandle;
}
/// <summary>
/// 初始化托盘图标结构 :ml-citation{ref="1" data="citationList"}
/// </summary>
/// <param name="Title"></param>
public void InitializeTrayIcon(string Title= "My Application")
{
notifyIconData = new NOTIFYICONDATA();
notifyIconData.cbSize = Marshal.SizeOf(notifyIconData);
notifyIconData.hWnd = wHandle;
notifyIconData.uID = 0;
notifyIconData.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
notifyIconData.uCallbackMessage = WM_USER + 1;
hIcon = LoadIcon(IntPtr.Zero, new IntPtr(32512)); // 使用默认图标
notifyIconData.hIcon = hIcon;
notifyIconData.szTip = Title;
Shell_NotifyIcon(NIM_ADD, ref notifyIconData);
}
public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == notifyIconData.uCallbackMessage)
{
switch ((int)lParam)
{
case WM_LBUTTONDBLCLK:
this.ShowWindow();
break;
case WM_RBUTTONUP:
this.showPopupMenu(hwnd);
break;
}
}
return IntPtr.Zero;
}
public void createMenu()
{
popupMenu = CreatePopupMenu();
AppendMenu(popupMenu, 0x00000000, 1, "展示");
AppendMenu(popupMenu, 0x00000000, 2, "退出");
}
private void showPopupMenu(IntPtr hwnd) {
POINT point;
GetCursorPos(out point);
// 显示右键菜单
int command = TrackPopupMenuEx(popupMenu, 0x00000100, point.X, point.Y, hwnd, IntPtr.Zero);
Debug.WriteLine($">>>>>>> : {command}");
if (command > 0)
CloseWindow();
}
/// <summary>
/// 销毁菜单和图潘图标
/// </summary>
/// <param name="e"></param>
public void Destroy(EventArgs e)
{
DestroyMenu(popupMenu);
Shell_NotifyIcon(NIM_DELETE, ref notifyIconData);
}
}
}
调用方法
var windowHandle = new WindowInteropHelper(this).Handle;
trayIcon = new TrayIcon(windowHandle);
HwndSource source = HwndSource.FromHwnd(windowHandle);
source.AddHook(trayIcon.WndProc);
trayIcon.InitializeTrayIcon( );
trayIcon.OnShowWindow += () => {
MessageBox.Show("haha");
};
trayIcon.createMenu();
页:
[1]