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

SDK 程式設計筆記:Windows 計時器完整指南

     編輯:VC 教學

核心 API

  • SetTimer:建立計時器
  • KillTimer:銷毀計時器(計時器屬系統資源,用畢必須釋放)

SetTimer 詳細原型

UINT_PTR SetTimer(
    HWND hWnd,           // 關聯視窗控制代碼,必須屬於呼叫執行緒;NULL 表示無視窗關聯
    UINT_PTR nIDEvent,   // 計時器識別碼(非零);hWnd 為 NULL 時被忽略
    UINT uElapse,        // 間隔毫秒數(1 ~ 4,294,967,295,近 50 天)
    TIMERPROC lpTimerFunc // 回呼函式指標;NULL 時發送 WM_TIMER 至訊息佇列
);

關鍵行為

  • hWnd 非 NULL 且已有相同 nIDEvent 計時器時,新呼叫會取代舊計時器。
  • 計時器識別碼與視窗關聯,不同視窗可擁有相同 ID 的計時器。
  • 回傳值:hWnd 為 NULL 時回傳新計時器 ID;非 NULL 時回傳非零整數;失敗回傳 0。

KillTimer 與 WM_TIMER 訊息佇列爭議

MSDN:KillTimer 不會 移除已佇列的 WM_TIMER 訊息。
Petzold《Windows 程式設計》:KillTimer 會 清除佇列中待處理的 WM_TIMER,呼叫後程式不會收到「流浪」的 WM_TIMER。
實務上建議自行在訊息處理中加入防呆邏輯。

WM_TIMER 訊息參數

  • wParam:計時器 ID
  • lParam:指向 TimerProc 的指標;若 SetTimer 時 lpTimerFunc 為 NULL,則為 0

三種使用計時器的方法

方法一:視窗關聯 + WM_TIMER 處理

#define ID_TIMER 1
SetTimer(hWnd, ID_TIMER, 1000, NULL);
KillTimer(hWnd, ID_TIMER);
// 在視窗程式中處理 WM_TIMER

方法二:視窗關聯 + TimerProc 回呼

VOID CALLBACK TimerProc(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
{
    // 處理 WM_TIMER
}
SetTimer(hWnd, ID_TIMER, 1000, TimerProc);
KillTimer(hWnd, ID_TIMER);

方法三:無視窗關聯 + TimerProc(系統自動分配 ID)

UINT_PTR iTimerID;
iTimerID = SetTimer(NULL, 0, 1000, TimerProc);
KillTimer(NULL, iTimerID);

優點:無須自行管理計時器 ID,避免 ID 衝突。

多計時器管理

#define TIMER_SEC 1
#define TIMER_MIN 2
SetTimer(hwnd, TIMER_SEC, 1000, NULL);
SetTimer(hwnd, TIMER_MIN, 60000, NULL);

case WM_TIMER:
    switch (wParam) {
        case TIMER_SEC: /* 每秒處理 */ break;
        case TIMER_MIN: /* 每分處理 */ break;
    }
    return 0;

變更計時間隔

直接以新間隔值再次呼叫 SetTimer 即可覆蓋現有計時器。

計時器精度分析

原因一:硬體時脈解析度限制

  • Windows 98:55ms 解析度(約 18.2 Hz)
  • Windows NT/2000/XP:10ms 解析度(100 Hz)
  • 指定間隔會被截尾為時脈整數倍(如 1000ms 實際為 989ms)

原因二:訊息佇列排程延遲

  • WM_TIMER 為低優先級訊息,僅在佇列無其他訊息時處理。
  • 若其他程式佔用 CPU 超過一秒,將收不到 WM_TIMER。
  • 多個 WM_TIMER 會合併為一個,導致「遺漏」觸發,無法得知遺漏次數。

正確計時策略

勿使用計數 WM_TIMER 來計時。時鐘程式應呼叫 GetLocalTime 等系統時間函式取得真實時間,計時器僅用於定時觸發畫面重繪(間隔 ≤ 1 秒)。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved