平時創建定時器使用的是WINAPI SetTimer,不過該函數一般用於有界面的時候。無界面的情況下,可以選擇微軟提供的CreateWaitableTimer和SetWaitableTimer API。
HANDLE WINAPI CreateWaitableTimer( _In_opt_ LPSECURITY_ATTRIBUTES lpTimerAttributes, _In_ BOOL bManualReset, _In_opt_ LPCTSTR lpTimerName ); BOOL WINAPI SetWaitableTimer( _In_ HANDLE hTimer, _In_ const LARGE_INTEGER *pDueTime, _In_ LONG lPeriod, _In_opt_ PTIMERAPCROUTINE pfnCompletionRoutine, _In_opt_ LPVOID lpArgToCompletionRoutine, _In_ BOOL fResume );
詳細介紹可以查看MSDN( http://msdn.microsoft.com/en-us/library/windows/desktop/ms682492(v=vs.85).aspx )
一、應用實例
我自己在使用的時候,封裝了一個類,用來創建了一個線程,並定時調用我提供的函數。類代碼如下:

1 #ifndef APLAYER_TIMERTHREAD_H 2 #define APLAYER_TIMERTHREAD_H 3 #include <Windows.h> 4 class CTimerThread 5 { 6 public: 7 CTimerThread() : 8 _hThread(NULL), _hEvent(NULL), 9 _bRunning(false), _nInterval(10) 10 {} 11 ~CTimerThread() 12 { 13 KillTimer(); 14 } 15 public: 16 int CreateTimer(unsigned int interval, PTIMERAPCROUTINE func, void* lpParam); 17 void KillTimer(); 18 private: 19 static DWORD WINAPI timerThread(LPVOID lpParam); 20 21 private: 22 HANDLE _hTimer; 23 int _nInterval; 24 HANDLE _hEvent; 25 void* _lpParam; 26 27 PTIMERAPCROUTINE _callbackFunc; 28 HANDLE _hThread; 29 DWORD _dwThread; 30 bool _bRunning; 31 }; 32 33 #endif

1 #include "TimerThread.h" 2 3 void CTimerThread::KillTimer() 4 { 5 if (_hTimer != NULL) { 6 CancelWaitableTimer(_hTimer); 7 CloseHandle(_hTimer); 8 _hTimer = NULL; 9 } 10 _bRunning = false; 11 } 12 int CTimerThread::CreateTimer(unsigned int interval, PTIMERAPCROUTINE func, void* lpParam) 13 { 14 if (_bRunning) return TRUE; 15 _nInterval = interval; 16 _callbackFunc = func; 17 _lpParam = lpParam; 18 _bRunning = true; 19 _hThread = CreateThread( 20 NULL, 21 0, 22 timerThread, 23 this, 24 0, 25 &_dwThread 26 ); 27 if (_hThread == NULL) { 28 _bRunning = false; 29 return FALSE; 30 } 31 CloseHandle(_hThread); 32 return TRUE; 33 } 34 35 DWORD CTimerThread::timerThread(LPVOID lpParam) 36 { 37 CTimerThread* pThis = (CTimerThread*)lpParam; 38 do { 39 pThis->_hTimer = CreateWaitableTimer(NULL, FALSE, NULL); 40 if (pThis->_hTimer == NULL) break; 41 42 LARGE_INTEGER liDueTime; 43 liDueTime.QuadPart = 0; 44 BOOL bRet = SetWaitableTimer( 45 pThis->_hTimer, 46 &liDueTime, 47 pThis->_nInterval, 48 pThis->_callbackFunc, 49 pThis->_lpParam, 50 FALSE); 51 do { 52 SleepEx(30000, TRUE); 53 } while (pThis->_bRunning); 54 return bRet; 55 } while (0); 56 return 0; 57 }
TimerThread.h/cpp實現了一個可以定時調用函數的類。使用的時候也很簡單。首先定義一個要被調用的函數
void __stdcall DoSomething(void *lpParam, DWORD, DWORD)
{
//to do
}
void *lpParam;
CTimerThread _timer;
_timer.CreateTimer(50, DoSomething, lpParam);
//
some code
....
//
_timer.KillTimer();
DoSomething函數在_timer.CreateTimer 和_timer.KillTimer之間會每隔50ms調用一次。
二、詳細說明
下面根據我自己的理解介紹下這兩個函數。
1.CreateWaitableTimer
1 HANDLE WINAPI CreateWaitableTimer( 2 _In_opt_ LPSECURITY_ATTRIBUTES lpTimerAttributes, 3 _In_ BOOL bManualReset, 4 _In_opt_ LPCTSTR lpTimerName 5 );
用來創建一個timer對象。首先翻譯下MSDN對各參數的介紹(個人理解):
lpTimerAttributes
略過,具體可以查看MSDN或《Windows核心編程》,一般設置為NULL。
bManualReset
If this parameter is TRUE, the timer is a manual-reset notification timer. Otherwise, the timer is a synchronization timer.
(此處不知道如何翻譯才能清晰的傳達意思,故抄錄原文。用我的語言解釋就是,如果為TRUE,則該timer到時間時,需要手動重置才能有下一次;FALSE則每次到時后自動進行下一次計時)
lpTimerName
該timer對象的名稱。最大MAX_PATH個字母,區分大小寫。
傳遞NULL則創建一個沒有名字的timer對象。
如果名稱和現有的event,semaphore,mutex,job or file-mapping對象名稱沖突,則該函數失敗,調用GetLastError會返回ERROR_INVALID_HANDLE錯誤。原因是這些對象共享相同的命名空間。
返回值(return value)
如果函數調用成功,則返回指向timer對象的handle。如果和現有的已命名timer同名,則返回指向該timer的handle。
2.SetWaitableTimer
1 BOOL WINAPI SetWaitableTimer( 2 _In_ HANDLE hTimer, 3 _In_ const LARGE_INTEGER *pDueTime, 4 _In_ LONG lPeriod, 5 _In_opt_ PTIMERAPCROUTINE pfnCompletionRoutine, 6 _In_opt_ LPVOID lpArgToCompletionRoutine, 7 _In_ BOOL fResume 8 );
啟動timer對象。首先翻譯下MSDN對各參數的介紹(個人理解):
hTimer
指向timer對象的handle。顯然可以是CreateWaitableTimer函數返回的handle。
pDueTime
該時間之后的timer會signaled(意會下..),間隔為100納秒(應該就是此值的單位吧?)
正值的話,就是基於UTC的絕對時間。負值的話就是相對現在的時間了。
例如-10 000 000表示1s后。
lPeriod
嗯,這個就是我比較關心的參數,signaled間隔。類似於SetTimer里那個間隔。單位毫秒(ms)
為0則只signaled一次。
pfnCompletionRoutine
每次signaled都會調用此處的函數了,傳遞一個函數指針。原型為:
typedef VOID (APIENTRY *PTIMERAPCROUTINE)( _In_opt_ LPVOID lpArgToCompletionRoutine, \\SetWaitableTimer傳入的參數lpArgToCompletionRoutine _In_ DWORD dwTimerLowValue, _In_ DWORD dwTimerHighValue );
lpArgToCompletionRoutine
傳入的參數,往上看:-)
fResume
懶得介紹,自己看msdn,一般設置為FALSE。
返回值(return value)
成功返回非零值。