手动刷新托盘图标
[toc]
背景
程序崩溃结束后,创建的系统托盘区图标并不能被刷新掉,重启客户端程序后,托盘区会有两个一样的图标。
解决方案
方案一
调用以下代码模拟鼠标hover操作遍历系统托盘区图标
#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
方案二
重新启动进程的时候先删除再创建,但是需要通过添加 uID 和 guidItem 来识别已创建的托盘图标
// 设置 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);