WIN32汇编语言教程:第06章 定时器 · 6.2 定时器的使用(2)
.if eax == WM_TIMER mov eax,wParam .if eax == ID_TIMER1 inc dwCount mov eax,dwCount and eax,1 inc eax invoke LoadIcon,hInstance,eax invoke SendDlgItemMessage,hWnd,IDC_SETICON,\ STM_SETIMAGE,IMAGE_ICON,eax .elseif eax == ID_TIMER2 invoke MessageBeep,-1 .endif ;******************************************************************** .elseif eax == WM_INITDIALOG push hWnd pop hWinMain invoke SetTimer,hWnd,ID_TIMER1,250,NULL invoke SetTimer,hWnd,ID_TIMER2,2000,NULL invoke SetTimer,NULL,NULL,1000,addr _ProcTimer mov idTimer,eax ;******************************************************************** .elseif eax == WM_CLOSE invoke KillTimer,hWnd,ID_TIMER1 invoke KillTimer,hWnd,ID_TIMER2 invoke KillTimer,NULL,idTimer invoke EndDialog,hWnd,NULL ;******************************************************************** .else mov eax,FALSE ret .endif mov eax,TRUE ret _ProcDlgMain endp ;#################################################################### start: invoke GetModuleHandle,NULL mov hInstance,eax invoke DialogBoxParam,hInstance,DLG_MAIN,\ NULL,offset _ProcDlgMain,NULL invoke ExitProcess,NULL ;#################################################################### end start
这个程序的基本结构非常简单,就是一个标准的对话框程序而已,在WM_INITDIALOG中用SetTimer申请了3个定时器,并在WM_CLOSE消息中用KillTimer撤销这3个定时器。
申请一个定时器使用SetTimer函数,函数的使用方法如下:
invoke SetTimer,hWnd,nIDEvent,uElapse,lpTimerFunc
hWnd参数是WM_TIMER消息发往的窗口句柄;nIDEvent参数是一个用户指定的任意整数,用来标识一个程序中的多个定时器;uElapse是时间周期,以ms为单位,这个参数是必须指定的;lpTimerFunc是定时器过程,在下面的内容中有详细介绍。如果定时器建立成功的话,函数的返回值是定时器的标识符。
撤销定时器的函数是KillTimer,该函数的使用方法是:
invoke KillTimer,hWnd,uIDEvent
参数hWnd和uIDEvent就是建立定时器时使用的数值。
使用SetTimer函数的方法有两种,第一种方法是要求Windows将WM_TIMER消息发往指定的窗口过程,这时候lpTimerFunc必须为NULL,如例子中的:
invoke SetTimer,hWnd,ID_TIMER1,250,NULL (例1) invoke SetTimer,hWnd,ID_TIMER2,2000,NULL
这两个句子设置了两个标识分别为ID_TIMER1和ID_TIMER2的定时器,定时周期分别为250 ms和2 s。在窗口过程收到WM_TIMER消息的时候,wParam中是用SetTimer建立定时器时使用的标识uIDEvent,所以程序可以建立一个分支,通过判断wParam来处理不同的定时器引起的WM_TIMER消息。在例子中,当wParam是ID_TIMER1的时候更换图标框中的图标,是ID_TIMER2的时候用MessageBeep函数来发出一声“嘟”的声音。如果要撤销用这种方法建立的定时器,那么只需要用建立时的hWnd和uIDEvent参数简单地调用KillTimer就可以了。
还有一种使用定时器的方法,那就是要求Windows在时间到的时候调用指定的定时器过程,而不是某个窗口过程,那么只需要指定lpTimerFunc参数,如例子中的:
invoke SetTimer,NULL,NULL,1000,addr _ProcTimer (例2)
这句语句要求系统把定时器消息发送到_ProcTimer定时器过程中去,但是,这时候没有参数用来指定定时器标识,到最后如何用KillTimer撤销这个定时器呢?答案是SetTimer函数会返回一个标识,程序可以保存这个标识并在KillTimer函数中使用。
当然,这种用法中的定时器标识也可以自己指定,但这时候一定要同时指定hWnd,虽然这个hWnd没有实际的用途,如果hWnd为NULL,那么即使指定了定时器标识,这个标识也会被忽略,如:
invoke SetTimer,hWnd,ID_TIMER3,1000,addr _ProcTimer (例3)
这个语句定义了一个标识为ID_TIMER3、消息发往_ProcTimer子程序的定时器。
定时器过程是如下定义的:
TimerProc proc hwnd,uMsg,idEvent,dwTime
Windows回调定时器过程的时候会有4个参数,uMsg总是WM_TIMER,hwnd和idEvent是例3用法中指定的hWnd和定时器标识,如果是例2的用法,那么hwnd就是NULL,而idEvent就是SetTimer返回的由Windows定义的定时器标识。由于有idEvent参数,所以我们同样可以把多个定时器消息指向同一个定时器过程中,并且根据idEvent参数构建一个分支来处理不同定时器引发的消息。
程序中还可能遇到一种情况:当在SetTimer中指定的定时器标识已经存在会怎样呢?答案是Windows会用新的参数代替老的定时器参数,函数执行以后,这个标识的定时器消息将以新的时间周期发送。
读者可能注意到,例子程序的窗口过程中把WM_TIMER的消息的处理代码放在第一个分支上,这是对程序的简单优化,把频繁发生的消息放到前面可以使程序少执行一系列的比较指令,像WM_CREATE和WM_DESTROY等仅发生一次的消息可以放到分支的最后面。
上页:第06章 定时器 · 6.1 定时器简介/6.2 定时器的使用(1) 下页:第06章 定时器 · 6.3 取Windows时间