WIN32汇编语言教程:第06章 定时器 · 6.1 定时器简介/6.2 定时器的使用(1)

在应用程序需要使用定时器时,可以用SetTimer函数向Windows申请一个定时器,要求系统在指定的时间以后“通知”应用程序,如果申请成功的话,系统会以指定的时间周期调用SetTimer函数指定的回调函数,或者向指定的窗口过程发送WM_TIMER消息,和DOS操作系统固定以55 ms的间隔触发中断服务程序相比,SetTimer函数可以指定的时间间隔更为灵活——以ms为单位,可以指定的时间周期为一个32位的整数,也就是从1~4 294 967 295 ms,这可是一个将近50天的范围!

但是在具体的使用中不要被这个参数所迷惑:由于Windows的定时器同样是基于时钟中断的,所以虽然参数的单位是ms,但精度还是55 ms,如果指定一个小于55 ms的周期,不管是1 ms还是54 ms,Windows最快也只能在每个时钟中断的时候触发这个定时器,也就是说,实际上这个定时器是以55 ms为触发周期的;另外,当指定一个时间间隔的时候,Windows以和这个间隔最接近的55 ms的整数倍时间来触发定时器,假定建立一个周期为1 000 ms的定时器,定时器的触发周期实际上不是1 s而是989 ms(55 ms×18)。

使用定时器时还有一个要点就是定时器消息是一个低级别的消息,这表现在两个方面:首先就是Windows只有在消息队列中没有其他消息的情况下才会发送WM_TIMER消息,如果窗口过程忙于处理某个消息没有返回,使消息队列中有消息积累起来,那么WM_TIMER消息就会被丢弃,在消息队列再度空闲的时候,被丢弃的WM_TIMER消息不会被补发(用一句经典的话来描述就是:“过去的就让它过去吧!”);其次,消息队列中不会有多条WM_TIMER消息,如果消息队列中已经有一条WM_TIMER消息,还没来得及处理,又到了定时的时刻,那么两条WM_TIMER消息会被合并成一条。

所以,应用程序不能依靠定时器来保证某件事情必须在规定的时刻被处理,另外,也不能依赖对定时器消息计数来确定已经过去了多少时间。

读者可以在所附光盘的Chapter06\Timer目录中找到一个例子,运行Timer.exe以后出现的界面如图6.1所示。

这个例子程序中共定义了3个定时器,第1个以250 ms为周期更换对话框上的图标;第2个以1s为单位进行计数并把结果显示在对话框上;第3个以2s为单位驱动扬声器发出“嘟嘟”的响声。为了验证WM_TIMER消息的级别,读者可以在运行中按住标题栏的“关闭”按钮不放,就可以发现3个定时器全部停止了,然后将鼠标移出“关闭”按钮并释放,定时器会重新工作,但对话框上的计数结果在定时器停止的期间并没有补上去,也就是说,在这期间,WM_TIMER消息被全部丢弃了。

6.2 定时器的使用

下面以Timer程序为例说明定时器的使用方法,这个程序的资源脚本文件定义如下:

#include       <resource.h>
#define DLG_MAIN           1
#define ICO_1          1
#define ICO_2          2
#define IDC_SETICON    100
#define IDC_COUNT      101
//##################################################################
ICO_1  ICON       "1.ico"
ICO_2  ICON       "2.ico"
//##################################################################
DLG_MAIN DIALOG 50, 50, 113, 40
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "定时器例子"
FONT 9, "宋体"
{
 ICON ICO_1, IDC_SETICON, 8, 9, 18, 21
 LTEXT "计数:", -1, 35, 16, 25, 10
 LTEXT "", IDC_COUNT, 62, 16, 40, 10
}

对资源的定义读者现在一定不会陌生了,这个文件中定义了两个图标和一个对话框,对话框中定义了一个图标框和两个文本框,其中的一个文本框中的文字为空,这是以后显示每秒一次的计数值用的。

Timer.asm源程序如下:

               .386
               .model flat,stdcall
               option casemap:none
;####################################################################
; Include 文件定义
;####################################################################
include        windows.inc
include        user32.inc
includelib     user32.lib
include        kernel32.inc
includelib     kernel32.lib
;####################################################################
ID_TIMER1      equ    1
ID_TIMER2      equ    2
ICO_1          equ    1
ICO_2          equ    2
DLG_MAIN          equ    1
IDC_SETICON    equ    100
IDC_COUNT      equ    101
;####################################################################
; 数据段
;####################################################################
                .data?
hInstance      dd     ?
hWinMain         dd     ?
dwCount        dd     ?
idTimer        dd     ?
;####################################################################
; 代码段
;####################################################################
              .code
;####################################################################
; 定时器过程
;####################################################################
_ProcTimer     proc       _hWnd,uMsg,_idEvent,_dwTime
 
                 pushad
                 invoke     GetDlgItemInt,hWinMain,IDC_COUNT,NULL,FALSE
                 inc        eax
                 invoke     SetDlgItemInt,hWinMain,IDC_COUNT,eax,FALSE
                  popad
                 ret
 
_ProcTimer     endp
;####################################################################
; 窗口过程
;####################################################################
_ProcDlgMain      proc           uses ebx edi esi,hWnd,uMsg,wParam,lParam
 
                  mov eax,uMsg
;********************************************************************

上页:第05章 使用资源 · 5.7 二进制资源和自定义资源 下页:第06章 定时器 · 6.2 定时器的使用(2)

第06章 定时器

版权所有 © 云南伯恩科技 证书:粤ICP备09170368号