首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Win32 API 實作系統托盤圖示完整教學

     編輯:關於C語言

前言

系統托盤圖示是 Windows 桌面應用常見功能,讓程式常駐背景執行並提供快速互動入口。本文透過完整的 Win32 API 範例,詳細解析托盤圖示的建立、訊息處理、右鍵選單、雙擊退出與任務列重建容錯等核心機制。

核心資料結構

NOTIFYICONDATA nid;  // 托盤圖示資訊結構
HMENU hmenu;         // 右鍵彈出選單控制代碼
UINT WM_TASKBARCREATED; // 任務列重建自訂訊息

關鍵實作步驟

1. 視窗建立時註冊托盤圖示 (WM_CREATE)

nid.cbSize = sizeof(nid);
nid.hWnd = hwnd;
nid.uID = 0;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = WM_USER;  // 自訂回呼訊息
nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);
lstrcpy(nid.szTip, szAppName);
Shell_NotifyIcon(NIM_ADD, &nid);  // 加入托盤區

/* 建立右鍵選單 */
hmenu = CreatePopupMenu();
AppendMenu(hmenu, MF_STRING, IDR_PAUSE, TEXT("暫停服務"));
AppendMenu(hmenu, MF_STRING, IDR_START, TEXT("恢復服務"));

2. 處理滑鼠互動 (WM_USER)

case WM_USER:
    if (lParam == WM_LBUTTONDOWN) {
        MessageBox(hwnd, TEXT("雙擊托盤可退出!"), szAppName, MB_OK);
    }
    if (lParam == WM_LBUTTONDBLCLK) {  // 雙擊退出
        SendMessage(hwnd, WM_CLOSE, wParam, lParam);
    }
    if (lParam == WM_RBUTTONDOWN) {    // 右鍵顯示選單
        GetCursorPos(&pt);
        SetForegroundWindow(hwnd);     // 解決選單焦點問題
        EnableMenuItem(hmenu, IDR_PAUSE, MF_GRAYED); // 動態啟用/停用項目
        int cmd = TrackPopupMenu(hmenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL);
        if (cmd == IDR_PAUSE) MessageBox(hwnd, TEXT("111"), szAppName, MB_OK);
        if (cmd == IDR_START) MessageBox(hwnd, TEXT("222"), szAppName, MB_OK);
    }
    break;

3. 視窗銷毀時移除圖示 (WM_DESTROY)

Shell_NotifyIcon(NIM_DELETE, &nid);
PostQuitMessage(0);

4. 任務列重建容錯 (WM_TASKBARCREATED)

WM_TASKBARCREATED = RegisterWindowMessage(TEXT("TaskbarCreated"));

/* 在預設訊息處理中攔截 */
if (message == WM_TASKBARCREATED)
    SendMessage(hwnd, WM_CREATE, wParam, lParam);  // 重新註冊圖示

原理:Explorer.exe 崩潰重啟後會重建任務列,並向所有頂層視窗廣播 TaskbarCreated 訊息。捕捉此訊息並重新呼叫 NIM_ADD 即可恢復圖示。

完整程式架構

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR szCmdLine, int iCmdShow) {
    /* 單一實例檢查 */
    HWND handle = FindWindow(NULL, szWndName);
    if (handle) { MessageBox(...); return 0; }

    /* 註冊視窗類別 */
    WNDCLASS wc = { CS_HREDRAW|CS_VREDRAW, WndProc, 0, 0, hInstance,
                    LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
                    (HBRUSH)GetStockObject(WHITE_BRUSH), NULL, szAppName };
    RegisterClass(&wc);

    /* 建立隱藏視窗 (WS_EX_TOOLWINDOW 不顯示在工作列) */
    hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, szAppName, szWndName,
                          WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

    /* 訊息迴圈 */
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

實務注意事項

現代替代方案

Windows 7+ 建議使用 Shell_NotifyIconEx 搭配 NOTIFYICONDATA 擴展版本(cbSize = sizeof(NOTIFYICONDATA) 設為較大結構),支援豐富提示、氣球通知、觸控友善等新特性。若採用 MFC/WTL/Qt 等框架,可直接使用封裝好的 CSystemTray / QSystemTrayIcon 簡化開發。

總結

Win32 API 實作托盤圖示的核心在於:Shell_NotifyIcon 管理圖示生命週期、自訂回呼訊息處理滑鼠事件、TrackPopupMenu 顯示右鍵選單、攔截 TaskbarCreated 實現容錯。掌握這套機制,不僅能開發托盤應用,更能深入理解 Windows 訊息驅動架構。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
項目說明
圖示資源實際專案應用 LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MYICON)) 載入自訂 .ico
Unicode 相容全程使用 TEXT() / _T() 宏與 TCHAR 類型
選單狀態動態 EnableMenuItem/CheckMenuItem 反映程式狀態
資源釋放結束前必須 DestroyMenu(hmenu)、Shell_NotifyIcon(NIM_DELETE)
高 DPIVista+ 應用 NIF_HIGHRES 或提供多尺寸圖示