Win32 計時器以 SetTimer/KillTimer 成對操作,透過 WM_TIMER 訊息或回呼函式通知。本文解析兩種模式差異、低優先級特性與閃爍視窗實作範例。
UINT_PTR SetTimer(
HWND hWnd, // 關聯視窗(NULL 為執行緒計時器)
UINT_PTR nIDEvent, // 計時器 ID(自訂,非 0)
UINT uElapse, // 間隔毫秒(系統最小約 10-15ms)
TIMERPROC lpTimerFunc // 回呼函式(NULL 表示用 WM_TIMER 訊息)
);
BOOL KillTimer(HWND hWnd, UINT_PTR uIDEvent); // 必須配對 ID 銷毀
| 特性 | lpTimerFunc == NULL (WM_TIMER) | lpTimerFunc != NULL (回呼) |
|---|---|---|
| 處理位置 | 視窗程序 WndProc | 獨立回呼函式(系統執行緒池) |
| 優先級 | 低(訊息佇列中最後處理) | 較高(直接由系統呼叫) |
| 精確度 | 受訊息迴圈擁塞影響 | 相對精確,但非即時 |
| 適用場景 | UI 更新、動畫、輪詢 | 非 UI 邏輯、資料採樣 |
| 參數傳遞 | 透過 wParam 取得 ID | 參數直接傳遞 |
WM_TIMER。WM_TIMER)。QueryPerformanceCounter、CreateTimerQueueTimer 或多媒體計時器 timeSetEvent。BOOL isRed = FALSE;
VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) {
isRed = !isRed; // 切換狀態
RECT rc;
GetClientRect(hwnd, &rc);
InvalidateRect(hwnd, &rc, TRUE); // 觸發 WM_PAINT
}
// WndProc 中
case WM_CREATE:
SetTimer(hWnd, 1, 1000, TimerProc); // 1秒間隔,使用回呼
return 0;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT rc;
GetClientRect(hWnd, &rc);
if (isRed) {
HBRUSH brush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &rc, brush);
DeleteObject(brush);
}
EndPaint(hWnd, &ps);
return 0;
}
case WM_DESTROY:
KillTimer(hWnd, 1); // 必須清理
PostQuitMessage(0);
return 0;
case WM_CREATE:
SetTimer(hWnd, 1, 1000, NULL); // 無回呼,用 WM_TIMER
return 0;
case WM_TIMER:
if (wParam == 1) {
isRed = !isRed;
InvalidateRect(hWnd, NULL, TRUE);
}
return 0;


視窗客戶區每秒在紅色填充與背景色之間切換。
| 需求 | 推薦方案 | 精度 |
|---|---|---|
| UI 動畫、週期性更新 | SetTimer (WM_TIMER) | ~15ms |
| 背景工作排程 | SetTimer (回呼) / CreateTimerQueueTimer | ~1ms |
| 高精度測量、多媒體同步 | timeSetEvent / QueryPerformanceCounter 迴圈 | ~1ms / 奈秒級 |
| 系統級排程、跨進程 | 任務排程器 / Waitable Timer | 秒級 |
KillTimer 導致資源洩漏、視窗銷毀後仍觸發回呼。SetTimer 相同 ID 會**替換**舊計時器(間隔、模式皆更新)。WM_TIMER 執行耗時操作阻塞 UI 執行緒 → 改用回呼或背景執行緒。