69 计时器基础
计时器是一种输入设备,它周期性地每经过一个指定的时间间隔就用WM_TIMER消息通知应用程序一次。
可以通过调用SetTimer函数为Windows应用程序分配一个计时器。SetTimer有一个时间间隔范围为1~4294967295毫秒的整型参数,这个值指示Windows每隔多长时间给程序发送WM_TIMER消息。
当程序用完计时器时,就调用KillTimer函数停止计时器消息。
KillTimer调用清除消息队列中尚未被处理的WM_TIMER消息,从而使程序在调用KillTimer之后就不会再受到WM_TIMER消息。
70 系统和计时器
Windows计时器是PC的硬件和ROM BIOS构造的计时器逻辑的一种相对简单的扩展。
BIOS的“计时器滴答”中断约每54.915毫秒或者大约每秒18.2次。
在Microsoft Windows NT中,计时器的分辨率为10毫秒。
Windows应用程序不能以高于这个分辨率的速率接收WM_TIMER消息。在SetTimer调用中指定的时间间隔总是截尾为时钟滴答的整数倍。例如,1000毫秒的间隔除以54.925毫秒≈18.207个时钟滴答,截尾后为18个时钟滴答,它实际上是989毫秒。对每个小于55毫秒的间隔,每个时钟滴答都产生一个WM_TIMER消息。
71 计时器消息不是异步的
计时器是基于硬件计时器中断。但WM_TIMER消息却不是异步的。
WM_TIMER消息放在正常的消息队列之中,和其他消息一起参加排序,因此,如果在SetTimer调用中指定间隔为1000毫秒,那么不能保持程序每1000毫秒就会收到一个WM_TIMER消息。如果其他程序的运行事件超过一秒,在此期间,程序将不会收到任何WM_TIMER消息。
Windows不能持续向消息队列放入多个WM_TIMER消息,而是将多余的WM_TIMER消息合并成一个消息。
72 计时器的使用(方法一)
如果需要在整个程序期间使用计时器,那么可以在处理WM_CREATE消息时调用SetTimer,并在处理WM_DESTROY消息时调用KillTimer。
SetTimer函数如下所示:
SetTimer(hwnd, 1, uiMsecInterval, NULL);
第一个参数是其窗口过程将接收WM_TIMER消息的窗口的句柄;
第二个参数是计时器ID,只要是非0的整数就可以,如果设置多个计时器,那么各个计时器的ID应该不同。
第三个参数是一个32位无符号整数,以毫秒为单位指定一个时间间隔。
第四个参数是回调函数的地址,如果处理WM_TIMER消息不是回调函数,那么设置为NULL。
KillTimer函数调用如下:
KillTimer(hwnd, 1);
第一个参数是其窗口过程将接收WM_TIMER消息的窗口的句柄;
第二个参数是计时器ID。
KillTimer用于在任何时刻停止WM_TIMER消息。
当窗口过程收到一个WM_TIMER消息时,wParam参数等于计时器的ID值,lParam参数为0.如果需要设置多个计时器,那么对每个计时器都使用不同的计时器ID。wParam的值将随传递到窗口过程的WM_TIMER消息的不同而不同。
73 计时器的使用(方法二)
第一种方法是把WM_TIMER消息发送到通常的窗口过程。
第二种方法是让Windows直接将计时器消息发送给程序的另一个函数。
接收这些计时器消息的函数称为“回调函数”,这是一个在程序之中,但是由Windows而不是程序本身调用的函数。先告诉Windows这个函数的地址,然后Windows调用此函数。
窗口过程其实就是一种回调函数。
回调函数必须定义为CALLBACK,因为它是由Windows从程序的代码段调用的。回调函数的参数和回调函数的返回值依赖于回调函数的目的。同计时器相关的回调函数中,输入参数同窗口过程的输入参数一样。计时器回调函数不向Windows返回值,可以设置为VOID。
假设计时器回调函数称为TimerProc,那么可以定义如下:
VOID CALLBACK TimerProc(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
{
WM_TIMER消息的处理过程;
}
TimerProc的参数hwnd是在调用SetTimer时指定的窗口句柄。Windows只把WM_TIMER消息消息送过TimerProc,因此消息参数总是等于WM_TIMER。iTimerID值是计时器ID,dwTimer值是与从GetTickCount函数的返回值兼容的值,是反映Windows启动后所经过的毫秒数。
在使用回调函数处理WM_TIMER消息时,窗口过程中设置SetTimer的第4个参数由回调函数的地址取代,如下所示:
SetTimer(hwnd, iTimerID, iMsecInterval, TimerProc);
回调函数必须和窗口过程函数一样,一起被声明在程序的开始处,像TimerProc的函数声明如下:
VOID CALLBACK TimerProc(HWND, UINT, UINT, DWORD);
74计时器的使用(方法三)(少用)
设置计时器的第三种方法类似于第二种方法,只是传递给SetTimer的hwnd参数被设置为NULL,并且第二个参数计时器ID也被忽略,设置为0,最后才函数返回计时器ID。
iTimerID = SetTimer(NULL, 0, iMsecInterval, TimerProc);
如果没有可用的计时器,那么从SetTimer返回的iTimerID值将为NULL。
KillTimer的第一个参数也必须是NULL,计时器ID必须是SetTimer的返回值。
传递给TimerProc计时器函数的hwnd参数也必须是NULL。
75 获取当前时间
首先介绍下SYSTEMTIME结构,如下所示:
typedef struct _SYSTEMTIME {
WORD wYear;
WORD wMonth;
WORD wDayOfWeek;
WORD wDay;
WORD wHour;
WORD wMinute;
WORD wSecond;
WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;
SYSTEMTIME结构包含日期和时间。月份由1开始递增,星期由0开始递增(星期天是0)。wDay是本月的当前日子,从1开始递增。
SYSTEM主要用于GetLocalTime和GetSystemTime函数。
GetSystemTime函数返回当前的世界时间(格林尼治时间)
GetSystemTime函数返回当地时间。
76 WM_SETTINGCHANGE消息
如果用户改变了任何系统设置,Windows会产生WM_SETTINGCHANGE消息,并传送给所有的应用程序。