typedef struct _NOTIFYICONDATA {
DWORD cbSize; // 結構大小
HWND hWnd; // 接收回調訊息的視窗
UINT uID; // 圖標識別碼
UINT uFlags; // 有效欄位標誌:NIF_ICON | NIF_MESSAGE | NIF_TIP
UINT uCallbackMessage; // 自訂回調訊息 (如 WM_USER+1)
HICON hIcon; // 圖標句柄
char szTip[64]; // 滑鼠懸停提示文字
} NOTIFYICONDATA;
BOOL Shell_NotifyIcon(DWORD dwMessage, PNOTIFYICONDATA pnid);
// dwMessage: NIM_ADD (新增), NIM_DELETE (刪除), NIM_MODIFY (修改)
在 CWinApp::InitInstance 或主框架 OnCreate 註解:
// pFrame->ActivateFrame();
// pFrame->ShowWindow(SW_SHOW);
// MainFrm.h
protected:
NOTIFYICONDATA m_tnid;
#define MYWM_NOTIFYICON (WM_USER + 1)
// MainFrm.cpp OnCreate 尾部
m_tnid.cbSize = sizeof(NOTIFYICONDATA);
m_tnid.hWnd = m_hWnd;
m_tnid.uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
m_tnid.uCallbackMessage = MYWM_NOTIFYICON;
m_tnid.uID = IDR_MAINFRAME;
_tcscpy_s(m_tnid.szTip, _T("托盤程式範例"));
m_tnid.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
Shell_NotifyIcon(NIM_ADD, &m_tnid);
// MainFrm.h
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
// MainFrm.cpp
LRESULT CMainFrame::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case MYWM_NOTIFYICON:
switch (lParam) { // lParam 為實際滑鼠訊息
case WM_LBUTTONDBLCLK: // 雙擊左鍵:顯示主視窗
AfxGetApp()->m_pMainWnd->ShowWindow(SW_SHOW);
break;
case WM_RBUTTONDOWN: { // 右鍵:彈出選單
CMenu menu; menu.LoadMenu(IDR_TRAY_MENU);
CMenu* pPopup = menu.GetSubMenu(0);
CPoint pt; GetCursorPos(&pt);
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this);
break;
}
}
break;
case WM_SYSCOMMAND:
if (wParam == SC_MINIMIZE) { // 最小化時隱藏主視窗,僅留托盤
ShowWindow(SW_HIDE);
return 0; // 不傳遞給基類,阻止預設最小化動畫
}
break;
case WM_DESTROY:
Shell_NotifyIcon(NIM_DELETE, &m_tnid); // 程式結束移除圖標
break;
}
return CFrameWnd::WindowProc(message, wParam, lParam);
}
資源檢視 → 選單 → 新增:項目「顯示主視窗」(ID_TRAY_SHOW)、「結束程式」(ID_TRAY_EXIT)。在主框架用 ClassWizard 為這兩個命令加入處理函數。
uCallbackMessage 必須在 WM_USER 以上避免衝突。TrackPopupMenu 需傳入 this (主框架) 作為擁有者,否則選單可能閃退。WM_SYSCOMMAND SC_MINIMIZE,非 WM_SIZE。