shiy720 发表于 2025-3-5 19:00:20

写了个在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]
查看完整版本: 写了个在wpf中使用Windows API实现系统托盘图标的类