C#实现系统托盘(system tray)刷新

最近在写一个程序的时候需要刷新系统托盘里的图标,想了好久也没有思路,搜索一番之后在http://www.dotnetsurfers.com/blog/2011/02/16/refreshing-the-windows-system-tray-programmatically找到了一个不错的解决方案。这个方法思路很巧妙,就是在系统托盘位置发送一个鼠标事件,这样系统便会刷新系统托盘,就像我们把鼠标放到系统托盘上会引起它刷新一样。经过测试,这段代码在中文版Windows 7、Windows 8、Windows 10上都可以使用。

原始的代码在中文版Windows上不好用,还需要Microsoft.VisualStudio.OLE.Interop,所以我就简单做了一下修改,代码如下:

using System;
using System.Runtime.InteropServices;

public class TaskBarUtil
{
 struct RECT
 {
 public int left, top, right, bottom;
 }

 public static void RefreshNotificationArea()
 {
 var notificationAreaHandle = GetNotificationAreaHandle();
 if (notificationAreaHandle == IntPtr.Zero)
 return;
 RefreshWindow(notificationAreaHandle);
 }

 private static void RefreshWindow(IntPtr windowHandle)
 {
 const uint wmMousemove = 0x0200;
 RECT rect;
 GetClientRect(windowHandle, out rect);
 for (var x = 0; x < rect.right; x += 5)
 for (var y = 0; y < rect.bottom; y += 5)
 SendMessage(
 windowHandle,
 wmMousemove,
 0,
 (y << 16) + x);
 }

 private static IntPtr GetNotificationAreaHandle()
 {
 const string notificationAreaTitle = "Notification Area";
 //const string notificationAreaTitleInWindows7 = "User Promoted Notification Area";

 const string notificationAreaTitleInWindows7 = "用户显示的通知区域"; //for chinese version

 var systemTrayContainerHandle = FindWindowEx(IntPtr.Zero, IntPtr.Zero,
 "Shell_TrayWnd", string.Empty);
 var systemTrayHandle = FindWindowEx(systemTrayContainerHandle, IntPtr.Zero,
 "TrayNotifyWnd", string.Empty);
 var sysPagerHandle = FindWindowEx(systemTrayHandle, IntPtr.Zero, "SysPager",
 string.Empty);
 var notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero,
 "ToolbarWindow32",
 notificationAreaTitle);
 if (notificationAreaHandle == IntPtr.Zero)
 notificationAreaHandle = FindWindowEx(sysPagerHandle, IntPtr.Zero,
 "ToolbarWindow32",
 notificationAreaTitleInWindows7);
 return notificationAreaHandle;
 }

 [DllImport("user32.dll", SetLastError = true)]
 static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter,
 string className,
 string windowTitle);
 [DllImport("user32.dll")]
 static extern bool GetClientRect(IntPtr handle, out RECT rect);
 [DllImport("user32.dll", CharSet = CharSet.Auto)]
 static extern IntPtr SendMessage(IntPtr handle, UInt32 message, Int32 wParam,
 Int32 lParam);
}

使用时只需要调用TaskBarUtil.RefreshNotificationArea()即可,如果想在英文版Windows 7、8、10上使用,将notificationAreaTitleInWindows7改成英文的即可。

CC BY-NC 4.0 本作品使用基于以下许可授权:Creative Commons Attribution-NonCommercial 4.0 International License.

发表评论

电子邮件地址不会被公开。 必填项已用*标注