應用程式異常終止時,托盤區(Notification Area)的圖示常殘留,直到滑鼠移過才消失。本文提供一個無需重啟 Explorer 的程式化清理解決方案。
Shell_TrayWnd → TrayNotifyWnd。SM_CXSMICON, SM_CYSMICON)。Sleep(0) 讓出時間片,觸發系統重繪檢測。void __fastcall RemoveDeadIcons()
{
HWND hTrayWindow;
RECT rctTrayIcon;
int nIconWidth, nIconHeight;
TPoint CursorPos;
int nRow, nCol;
// 1. 取得托盤視窗句柄
hTrayWindow = FindWindowEx(
FindWindow("Shell_TrayWnd", NULL),
0, "TrayNotifyWnd", NULL);
if (!hTrayWindow) return;
if (!GetWindowRect(hTrayWindow, &rctTrayIcon)) return;
// 2. 系統小圖示度量
nIconWidth = GetSystemMetrics(SM_CXSMICON);
nIconHeight = GetSystemMetrics(SM_CYSMICON);
// 3. 保存當前滑鼠位置
GetCursorPos(&CursorPos);
// 4. 雙層迴圈掃描每個圖示格
for (nRow = 0; nRow < (rctTrayIcon.bottom - rctTrayIcon.top) / nIconHeight; nRow++) {
for (nCol = 0; nCol < (rctTrayIcon.right - rctTrayIcon.left) / nIconWidth; nCol++) {
SetCursorPos(
rctTrayIcon.left + nCol * nIconWidth + 5,
rctTrayIcon.top + nRow * nIconHeight + 5);
Sleep(0); // 關鍵:讓系統處理訊息
}
}
// 5. 還原滑鼠
SetCursorPos(CursorPos.x, CursorPos.y);
// 6. 強制重繪修正多行托盤殘影
RedrawWindow(hTrayWindow, NULL, 0,
RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW);
}
| 步驟 | API | 說明 |
|---|---|---|
| 尋找托盤 | FindWindow/FindWindowEx | 層級:Shell_TrayWnd → TrayNotifyWnd |
| 圖示尺寸 | GetSystemMetrics | SM_CXSMICON/SM_CYSMICON 隨 DPI 變化 |
| 掃描策略 | 雙層 for + SetCursorPos | +5px 偏移避免落在格線邊緣 |
| 觸發重繪 | Sleep(0) | 讓出時間片,系統處理 WM_MOUSEMOVE 等 |
| 收尾 | RedrawWindow | RDW_UPDATENOW 立即更新,修正多行 bug |
ITrayNotify 新架構,可能需改用 Shell_NotifyIcon(NIM_SETVERSION) 配合 NOTIFYICONDATA 正規清理。ShowCursor(FALSE))。若目標為自家程式殘留圖示,優先在程式退出處呼叫:
NOTIFYICONDATA nid = { sizeof(nid) };
nid.hWnd = hWnd;
nid.uID = MY_TRAY_ID;
Shell_NotifyIcon(NIM_DELETE, &nid);

模擬滑鼠掃描法雖屬「暴力美學」,但在無法修改第三方程式碼時,是快速清除殭屍圖示的實用利器。