[toc]

背景

程序崩溃结束后,创建的系统托盘区图标并不能被刷新掉,重启客户端程序后,托盘区会有两个一样的图标。

解决方案

方案一

调用以下代码模拟鼠标hover操作遍历系统托盘区图标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

#ifdef Q_OS_WIN
//刷新托盘图标
auto RefreshTrayIcon = []()
{
//任务栏窗口
HWND hShellTrayWnd = ::FindWindow(L"Shell_TrayWnd", NULL);
//任务栏右边托盘图标+时间区
HWND hTrayNotifyWnd = ::FindWindowEx(hShellTrayWnd, 0, L"TrayNotifyWnd", NULL);
//不同系统可能有可能没有这层
HWND hSysPager = ::FindWindowEx(hTrayNotifyWnd, 0, L"SysPager", NULL);
//托盘图标窗口
HWND hToolbarWindow32;
if (hSysPager)
{
hToolbarWindow32 = ::FindWindowEx(hSysPager, 0, L"ToolbarWindow32", NULL);
}
else
{
hToolbarWindow32 = ::FindWindowEx(hTrayNotifyWnd, 0, L"ToolbarWindow32", NULL);
}
if (hToolbarWindow32)
{
RECT r;
::GetWindowRect(hToolbarWindow32, &r);
int width = r.right - r.left;
int height = r.bottom - r.top;

int iconWidth = GetSystemMetrics(SM_CXSMICON); // 图标基准宽度
int iconHeight = GetSystemMetrics(SM_CYSMICON); // 图标基准高度

//从任务栏中间从左到右 MOUSEMOVE一遍,所有图标状态会被更新
for (int x = 1; x < width; x+=iconWidth)
{
for (int y = 1; y < height; y+=iconHeight)
{
::SendMessage(hToolbarWindow32, WM_MOUSEMOVE, 0, MAKELPARAM(x, y));
}
}
}
};

// RefreshTrayIcon();

#endif // Q_OS_WIN

方案二

重新启动进程的时候先删除再创建,但是需要通过添加 uIDguidItem 来识别已创建的托盘图标

1
2
3
4
5
6
7
8
9
10
11
   // 设置 uid 和 guiditem
m_nid.uID = GUID_TrayIcon.Data2;
if (QSysInfo::WindowsVersion >= QSysInfo::WV_WINDOWS7)
{
m_nid.uFlags |= NIF_GUID;

m_nid.guidItem = GUID_TrayIcon;
}

// 删除
Shell_NotifyIcon(NIM_DELETE, &m_nid);