最近在写一个程序的时候需要刷新系统托盘里的图标,想了好久也没有思路,搜索一番之后在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改成英文的即可。
本作品使用基于以下许可授权:Creative Commons Attribution-NonCommercial 4.0 International License.