1、定时器实现 |
---|
windows定时器通过一个称为“时间滴答”的硬件中断实现。windows为每一个定时器维护一个计数值,时间滴答中断出现时,计数值减1。当计数值为0时,windows把WM_TIMER消息插入到窗口消息队列中,同时计数值复位。
前面提到,windows是以同步的方式处理消息的,定时器实现依赖于消息,所以定时器也是同步的,定时器不会中断当前程序的运行。
另外,windows不会在消息队列中插入多条WM_TIMER消息。
2、定时器使用 |
---|
当需要一个定时器时,使用SetTimer可以设置定时器:
UINT_PTR
WINAPI
SetTimer(
_In_opt_ HWND hWnd, // 窗口句柄,指向接收WM_TIMER的窗口过程,窗口必须属于调用SetTimer的线程
_In_ UINT_PTR nIDEvent, // 定时器ID,标识定时器,非0无符号数
_In_ UINT uElapse, // 定时器时间间隔(毫秒)
_In_opt_ TIMERPROC lpTimerFunc); // 定时器处理函数
设置成功后,SetTimer返回定时器ID,并且每过去uElapse毫秒,windows把WM_TIMER消息插入消息队列中。WM_TIMER消息的wParam参数是定时器ID,lParam参数为回调函数指针。
当不再需要定时器了,使用KillTimer可以取消定时器,同时会把消息队列中待处理的WM_TIMER消息删除。
BOOL
WINAPI
KillTimer(
_In_opt_ HWND hWnd, // 窗口句柄
_In_ UINT_PTR uIDEvent); // 定时器ID
-
在窗口过程中处理定时器逻辑
SetTimer(hwnd, id, elapse, NULL);
这种方法,需要在窗口过程中处理WM_TIMER消息,利用wParam参数区分不同的定时器。
-
在回调函数中处理定时器逻辑
SetTimer(hwnd, id, elapse, TimerProc);
调用SetTimer时指定了回调函数,就不需要在窗口过程中处理WM_TIMER消息,DispatchMessage发现WM_TIMER的lParam参数不为空时,就不会调用窗口过程,而是调用设定的回调函数。
MSDN中关于DispatchMessage的原话:
If the lpmsg parameter points to a WM_TIMER message and the lParam parameter of the WM_TIMER message is not NULL, lParam points to a function that is called instead of the window procedure.
回调函数声明为:
VOID CALLBACK TIMERPROC(HWND hwnd, // SetTimer中设定的hwnd UINT message, // WM_TIMER UINT_PTR id, // 定时器id DWORD time); // GetTickCount返回的值
-
不指定定时器ID
id = SetTimer(NULL, 0, elpase, TimerProc);
当hwnd传参为NULL时,SetTimer会忽略第二传参id,并生成一个定时器ID返回。