您好,欢迎访问代理记账网站
移动应用 微信公众号 联系我们

咨询热线 -

电话 15988168888

联系客服
  • 价格透明
  • 信息保密
  • 进度掌控
  • 售后无忧

清除失效的托盘图标

如果自己开发的WPF或Winform程序,有显示托盘图标的话,当程序异常结束时(如因为未处理的异常而导致程序崩溃,或者直接使用VS的停止调试按钮结束程序),失效的托盘图标就会一直残留在托盘窗口中。虽然这些失效的托盘图标不会影响什么,但过多累积的失效图标,看起来也确实会给人不好的观感,尤其是对于有强迫症的同学。

那么有没有办法自动清除这些失效的托盘图标呢?答案是有的。实际上你会发现,当鼠标滑过这些失效图标时,它们会自动消失掉。所以我们的办法就是,通过代码的形式,模拟鼠标滑过的动作,从而达到自动清除失效图标的目的。

实际上,网上有现成的代码,不过很多都是抄来抄去,无法使用的代码。这些代码中可能只是存在一些小的问题,但它就是没法用。好了,废话不多说,下面直接上我自己运行OK且正在使用的代码,供大家参考/复制...

    //该类用于刷新托盘窗口(包括显示区域和溢出区域),达到清除残留图标的目的。
    //原理:在程序每次开启前,向托盘窗口发送鼠标滑过消息WM_MOUSEMOVE,使其刷新,在此过程中,无效的托盘图标即会消失。
    public class TrayArea
    {
        //只读字段,用于获取当前系统语言信息(是中文系统,还是英文系统)
        private static readonly System.Globalization.CultureInfo _CultureInfo = System.Globalization.CultureInfo.InstalledUICulture;

        //定义struct,用于存放托盘区域的位置信息
        private struct Rect
        {
            public int left, top, right, bottom;
        }

        [DllImport("user32.dll")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string className, string windowTitle);
        [DllImport("user32.dll")]
        private static extern bool GetClientRect(IntPtr handle, out Rect rect);
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr handle, uint message, int wParam, int lParam);

        /// <summary>
        /// 刷新托盘区域。
        /// </summary>
        /// <returns>Task</returns>
        public static Task RefreshAsync() //异步形式函数
        {
            return Task.Run(() => Refresh());
        }

        /// <summary>
        /// 刷新托盘区域。
        /// </summary>
        public static void Refresh()
        {
            //一层一层的父窗口的Handle
            IntPtr trayWndHandle = FindWindow("Shell_TrayWnd", null);
            IntPtr trayNotifyWndHandle = FindWindowEx(trayWndHandle, IntPtr.Zero, "TrayNotifyWnd", null);
            IntPtr sysPagerHandle = FindWindowEx(trayNotifyWndHandle, IntPtr.Zero, "SysPager", null);

            //刷新用户提示通知区域
            string windowTile_UserPromotedNotificationArea = _CultureInfo.Name == "zh-CN" ? "用户提示通知区域" : _CultureInfo.Name.StartsWith("en") ? "User Promoted Notification Area" : null; //窗口标题,目前仅支持简体中文和英文
            IntPtr windowHandle_UserPromotedNotificationArea = FindWindowEx(sysPagerHandle, IntPtr.Zero, "ToolbarWindow32", windowTile_UserPromotedNotificationArea); //目标窗口Handle
            Refresh(windowHandle_UserPromotedNotificationArea); //刷新

            //刷新溢出通知区域
            IntPtr notifyIconOverflowWindowHandle = FindWindow("NotifyIconOverflowWindow", null); //父窗口Handle
            string windowTile_OverflowNotificationArea = _CultureInfo.Name == "zh-CN" ? "溢出通知区域" : _CultureInfo.Name.StartsWith("en") ? "Overflow Notification Area" : null; //窗口标题,目前仅支持简体中文和英文
            IntPtr windowHandle_OverflowNotificationArea = FindWindowEx(notifyIconOverflowWindowHandle, IntPtr.Zero, "ToolbarWindow32", windowTile_OverflowNotificationArea); //目标窗口Handle
            Refresh(windowHandle_OverflowNotificationArea); //刷新
        }

        //刷新托盘区域中的所有图标(通过模拟鼠标滑过的方式)
        private static void Refresh(IntPtr windowHandle)
        {
            //Mouse Over消息常量
            const uint WM_MOUSEMOVE = 0x0200;
            //获取托盘区域(位置信息放在Rect变量中)
            GetClientRect(windowHandle, out Rect rect);
            //通过循环,从左到右,从上到下,(模拟鼠标)滑过托盘区域中的每个图标
            for (int x = 0; x < rect.right; x += 5) //图标之间的水平间距为5
            {
                for (int y = 0; y < rect.bottom; y += 5) //图标之间的垂直间距为5
                {
                    SendMessage(windowHandle, WM_MOUSEMOVE, 0, (y << 16) + x); //发送鼠标滑过(Mouse Over)消息
                }
            }
        }
    }


分享:

低价透明

统一报价,无隐形消费

金牌服务

一对一专属顾问7*24小时金牌服务

信息保密

个人信息安全有保障

售后无忧

服务出问题客服经理全程跟进