在 VC 開發中,CWnd::SetTimer 精度僅達 10~15 毫秒,且依賴視窗訊息循環,若類別無視窗(非 CWnd 衍生)便無法直接使用。為解決「精度不足」與「強制繼承視窗類」兩大痛點,本文封裝了基於 Windows Multimedia Timer API 的 CMMTimers 類,實現真正的毫秒級、無視窗依賴的高精度定時器。

圖一 毫秒定時器運行效果
多媒體定時器核心函數僅五個,封裝後對上層完全透明:
| API 函數 | 用途 |
|---|---|
timeGetDevCaps | 獲取系統定時器精度範圍 |
timeBeginPeriod | 設定期望精度(如 1ms) |
timeEndPeriod | 釋放精度資源 |
timeSetEvent | 啟動定時器,指定回調函數與週期 |
timeKillEvent | 停止定時器 |
註:實測發現即使不調用前三個精度管理函數,在現代系統上效果亦相近,但為規範建議保留。
為實現類似 MFC OnTimer 的響應機制,引入抽象介面 CTimerListener,採用 UML 設計:

圖二 類結構 UML 圖
class CTimerListener {
public:
virtual void OnMMTimer(UINT nTimerID) = 0; // 純虛函數,使用者需重寫
virtual ~CTimerListener() {}
};
bool startTimer(UINT period, CTimerListener* pListener, int nTimerID=1, bool oneShot=FALSE):啟動定時器,period 以毫秒為單位bool stopTimer(int nTimerID):停止指定 ID 定時器void stopTimer():停止所有定時器timerProc 自動轉發至 pListener->OnMMTimer()無需繼承 CWnd,任何類別(如 CStudent)實作 CTimerListener 即可:
class CMyClass : public CTimerListener {
CMMTimers m_timer;
public:
void Start() { m_timer.startTimer(10, this, 1); } // 10ms 週期
void Stop() { m_timer.stopTimer(1); }
virtual void OnMMTimer(UINT nID) override {
// 毫秒級精確回調邏輯
TRACE(_T("Timer %d fired at %d ms\n"), nID, GetTickCount());
}
};
CMMTimers 以約 100 行代碼封裝了複雜的多媒體定時器 API,提供類 MFC 體驗的毫秒級定時能力,完全脫離視窗依賴,適用於遊戲迴路、即時資料採集、多媒體同步等高精度場景。代碼已開源,歡迎指正與交流。