《Windows核心编程》の定时器

本文详细介绍了Windows操作系统下如何使用SetTimer函数实现定时器功能,包括两种使用方式:通过WM_TIMER消息处理和指定定时器回调函数处理。同时阐述了定时器的实际精度、限制以及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DOS操作系统中要用到定时器功能的时候一般有两种方法:一是用一个空循环来延时;一是截获时钟中断,计算机的硬件时钟中断会以每55ms一次的频率触发8号中断,而在默认的int 08h中断处理程序中有一句int 1ch的代码,所以截获int 08hint 1ch都可以达到定时的要求。

而在Windows操作系统中,用户程序不可能去截获时钟中断,而是使用定时器功能。

 

在应用程序中需要使用定时器时,可以用SetTimer函数向Windows申请一个定时器,要求系统在指定时间以后“通知”应用程序,如果申请成功,系统会以指定时间周期调用SetTimer函数指定的回调函数,或者向指定的窗口过程发送WM_TIMER消息,SetTimer函数可以指定的时间间隔以ms为单位,可以指定的时间周期为一个32位的整数,也就是从1~4294967295ms(232-1ms),这是一个将近50天的范围。

但在实际应用中,由于Windows的定时器是基于时钟中断的,所以虽然参数的单位ms,但精度是55ms,如果指定一个小于55ms的周期,Windows最快也只能在每个时钟中断的时候触发这个定时器,即实际上这个定时器是以55ms为触发周期的;另外,指定一个时间间隔时,Windows以与这个间隔最接近的55ms的整数倍时间来触发定时器。

 

由于定时器消息是一个低级别的消息,这表现在两方面:

1Windows只有在消息队列中没有其他消息的情况下才会发送WM_TIMER消息,如果窗口过程忙于处理这个消息没有返回,使消息队列中有消息积累起来,那么WM_TIMER消息就会被丢弃,在消息队列空闲时,被丢弃的WM_TIMER消息不会补发;

2)消息队列中不会有多条WM_TIMER消息,如果消息队列中已经有一条WM_TIMER消息,还没来得及处理,又到了定时时刻,那么两条WM_TIMER消息会被合并成一条。

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

 

申请一个定时器使用SetTimer函数:

UINT_PTR WINAPI SetTimer(

  __in_opt  HWND hWnd, //WM_TIMER消息发往的窗口句柄

  __in      UINT_PTR nIDEvent, //用户指定的任意整数,用来标识一个程序中的多个定时器

  __in      UINT uElapse, //时间周期,以ms为单位

  __in_opt  TIMERPROC lpTimerFunc //定时器过程

);

如果定时器创建成功,返回的是定时器的标识符。

当在SetTimer中指定的定时器标识已经存在,则Windows会用新的参数代替旧的定时器参数,函数执行后,这个标识的定时器消息将以新的时间周期发送。

 

定时器过程定义如下:

VOID CALLBACK TimerProc(

  __in  HWND hwnd, //与定时器关联的窗口句柄

  __in  UINT uMsg, //总是WM_TIMER

  __in  UINT_PTR idEvent, //SetTimer返回的定时器标识符

  __in  DWORD dwTime //系统启动至今经过的ms数,该值是由函数GetTickCount返回的

);

 

撤销定时器的函数是KillTimer

BOOL WINAPI KillTimer(

  __in_opt  HWND hWnd, // WM_TIMER消息发往的窗口句柄

  __in      UINT_PTR uIDEvent //用户指定的任意整数,用来标识一个程序中的多个定时器

);

 

使用SetTimer函数的方法有两种:

1)要求WindowsWM_TIMER消息发往指定的窗口过程,这时lpTimerProc必须为NULL

例如如下:

HICON hIcon1;               // icon handle

POINT ptOld;                // previous cursor location

UINT uResult;               // SetTimer's return value

HINSTANCE hinstance;        // handle to current instance

 

//

// Perform application initialization here.

//

 

wc.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(400));

wc.hCursor = LoadCursor(hinstance, MAKEINTRESOURCE(200));

 

// Record the initial cursor position.

 

GetCursorPos(&ptOld);

 

// Set the timer for the mousetrap.

 

uResult = SetTimer(hwnd,             // handle to main window

    IDT_MOUSETRAP,                   // timer identifier

    10000,                           // 10-second interval

    (TIMERPROC) NULL);               // no timer callback

 

if (uResult == 0)

{

    ErrorHandler("No timer is available.");

}

 

LONG APIENTRY MainWndProc(

    HWND hwnd,          // handle to main window

    UINT message,       // type of message

    WPARAM  wParam,     // additional information

    LPARAM  lParam)     // additional information

{

 

    HDC hdc;        // handle to device context

    POINT pt;       // current cursor location

    RECT rc;        // location of minimized window

 

    switch (message)

    {

        //

        // Process other messages.

        //

 

        case WM_TIMER:

        // If the window is minimized, compare the current

        // cursor position with the one from 10 seconds

        // earlier. If the cursor position has not changed,

        // move the cursor to the icon.

 

            if (IsIconic(hwnd))

            {

                GetCursorPos(&pt);

 

                if ((pt.x == ptOld.x) && (pt.y == ptOld.y))

                {

                    GetWindowRect(hwnd, &rc);

                    SetCursorPos(rc.left, rc.top);

                }

                else

                {

                    ptOld.x = pt.x;

                    ptOld.y = pt.y;

                }

            }

 

            return 0;

 

        case WM_DESTROY:

 

        // Destroy the timer.

 

            KillTimer(hwnd, IDT_MOUSETRAP);

            PostQuitMessage(0);

            break;

 

        //

        // Process other messages.

        //

 

}

 

2)要求Windows在时间到的时候调用指定的定时器过程,而不是窗口过程,那么只需要指定lpTimerFunc参数即可。

例子如下:

UINT uResult;               // SetTimer's return value

HICON hIcon1;               // icon handle

POINT ptOld;                // previous cursor location

HINSTANCE hinstance;        // handle to current instance

 

//

// Perform application initialization here.

//

 

wc.hIcon = LoadIcon(hinstance, MAKEINTRESOURCE(400));

wc.hCursor = LoadCursor(hinstance, MAKEINTRESOURCE(200));

 

// Record the current cursor position.

 

GetCursorPos(&ptOld);

 

// Set the timer for the mousetrap.

 

uResult = SetTimer(hwnd,      // handle to main window

    IDT_MOUSETRAP,            // timer identifier

    10000,                    // 10-second interval

    (TIMERPROC) MyTimerProc); // timer callback

 

if (uResult == 0)

{

    ErrorHandler("No timer is available.");

}

 

LONG APIENTRY MainWndProc(

    HWND hwnd,          // handle to main window

    UINT message,       // type of message

    WPARAM  wParam,     // additional information

    LPARAM   lParam)    // additional information

{

 

    HDC hdc;            // handle to device context

 

    switch (message)

    {

    //

    // Process other messages.

    //

 

        case WM_DESTROY:

        // Destroy the timer.

 

            KillTimer(hwnd, IDT_MOUSETRAP);

            PostQuitMessage(0);

            break;

 

        //

        // Process other messages.

        //

 

}

 

// MyTimerProc is an application-defined callback function that

// processes WM_TIMER messages.

 

VOID CALLBACK MyTimerProc(

    HWND hwnd,        // handle to window for timer messages

    UINT message,     // WM_TIMER message

    UINT idTimer,     // timer identifier

    DWORD dwTime)     // current system time

{

 

    RECT rc;

    POINT pt;

 

    // If the window is minimized, compare the current

    // cursor position with the one from 10 seconds earlier.

    // If the cursor position has not changed, move the

    // cursor to the icon.

 

    if (IsIconic(hwnd))

    {

        GetCursorPos(&pt);

 

        if ((pt.x == ptOld.x) && (pt.y == ptOld.y))

        {

            GetWindowRect(hwnd, &rc);

            SetCursorPos(rc.left, rc.top);

        }

        else

        {

            ptOld.x = pt.x;

            ptOld.y = pt.y;

        }

    }

}

 

 

 

 

 

可等待定时器的相关内容见:http://blog.youkuaiyun.com/ACE1985/archive/2010/07/19/5746521.aspx

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值