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时间

第06章 定时器

版权所有 © 中山市飞娥软件工作室 证书:粤ICP备09170368号