延續前兩篇(基本托盤圖示、TaskbarCreated 自動重建),本篇聚焦 Windows 2000/XP 引入的氣球提示。不同於傳統 ToolTip(滑鼠懸停才顯示),氣球提示由程式主動觸發、支援標題/圖示/自動超時關閉,適合非打斷式通知(新郵件、網路狀態變更、下載完成等)。
typedef struct _NOTIFYICONDATA {
DWORD cbSize;
HWND hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
HICON hIcon;
WCHAR szTip[128]; // 傳統 ToolTip
// --- 以下為 0x0500 新增 ---
DWORD dwState;
DWORD dwStateMask;
WCHAR szInfo[256]; // 氣球提示內文
union { UINT uTimeout; UINT uVersion; } DUMMYUNIONNAME;
WCHAR szInfoTitle[64]; // 氣球標題
DWORD dwInfoFlags; // 圖示類型:NIIF_INFO/WARNING/ERROR/NONE
} NOTIFYICONDATA;
編譯時需包含新版 shellapi.h 並連結 shell32.lib,部署需確保目標機 shell32.dll 版本 >= 5.0(Win2000 內建)。
關鍵旗標:uFlags = NIF_INFO。szInfo 內文、szInfoTitle 標題、uTimeout 毫秒數(10~30 秒,系統會限制範圍)、dwInfoFlags 圖示。
BOOL CTrayIcon::ShowBalloonTip(LPCTSTR szMsg, LPCTSTR szTitle,
UINT uTimeout, DWORD dwInfoFlags)
{
m_nid.cbSize = sizeof(NOTIFYICONDATA);
m_nid.uFlags = NIF_INFO;
m_nid.uTimeout = uTimeout;
m_nid.dwInfoFlags = dwInfoFlags;
_tcscpy_s(m_nid.szInfo, szMsg ? szMsg : _T(""));
_tcscpy_s(m_nid.szInfoTitle, szTitle ? szTitle : _T(""));
return Shell_NotifyIcon(NIM_MODIFY, &m_nid);
}
預設 dwInfoFlags = NIIF_INFO(藍色資訊圖示),亦可用 NIIF_WARNING(黃色驚嘆號)、NIIF_ERROR(紅色叉叉)、NIIF_NONE(無圖示)。
托盤建立時指定 uCallbackMessage,Windows 會傳送下列通知:
| 通知訊息 | 觸發時機 |
|---|---|
| NIN_BALLOONSHOW | 氣球顯示瞬間 |
| NIN_BALLOONHIDE | 氣球消失(圖示被刪除時);超時/點關閉不送此訊息 |
| NIN_BALLOONTIMEOUT | 超時自動關閉 或 使用者點右上角關閉鈕 |
| NIN_BALLOONUSERCLICK | 使用者點擊氣球本體(非關閉鈕) |
⚠️ 無法區分「超時」與「點關閉鈕」,兩者皆送 NIN_BALLOONTIMEOUT。
實測發現:XP 上,若托盤程式擁有前景焦點,氣球不會超時自動關閉。必須切換到其他視窗才會啟動計時器。Win2000 無此行為。此為 XP 設計決策,避免使用者正在操作時通知被強制關閉。
ShowBalloonTip。CTrayIcon::ShowBalloonTip 兩個多載(字串/資源 ID)CMainFrame::OnTrayNotification 處理 NIN_BALLOON* 並記錄 Log#define _WIN32_IE 0x0500 確保結構定義正確Shell_NotifyIcon 基礎、CTrayIcon 封裝、右鍵選單、雙擊預設命令、SetForegroundWindow 修正選單焦點問題。TaskbarCreated 廣播訊息、CSubclassWnd 攔截最上層視窗程序、自動重建托盤圖示。NIF_INFO 氣球提示、超時/點擊事件、XP 焦點行為差異、使用建議。三篇結合,涵蓋托盤程式設計 90% 以上實務需求。完整原始碼請下載附件。