手动刷新托盘图标

[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
 

方案二

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

    // 设置 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);