天天看点

多媒体定时器(timeSetEvent)及使用pDlg->UpdateData()错误

之前一直使用SetTimer和OnTimer来定时,知道今天碰到了一个应用,运行结果反应SetTimer定时不准,研究了timeSetEvent/timeKillEvent的使用,其可以实现1ms的定时精度。

  1. 使用这两个函数时,需要在头部添加如下语句:

        #include <MMSystem.h>

        #pragma comment(lib, “Winmm.lib”)

  2. timeSetEvent的函数声明如下:

      MMRESULT timeSetEvent(UINT uDelay, UINT uResolution, LPTIMECALLBACK lpTimeProc, WORD dwUser, UINT fuEvent);

    参数说明:

        uDelay:指定定时的时间,单位是毫秒;

        uResolution:以毫秒指定延时的精度,数值越小,定时器事件的分辨率越高,缺省值为1ms;

        lpTimeProc:指向一个回调函数,该回调函数包含需要定时执行的代码;

        dwUser:存放用户提供的回调数据;

        fuEvent:指定定时器事件的类型:TIME_ONESHOT表示uDelay毫秒后只产生一次事件,TIME_PERIODIC表示每隔uDelay毫秒周期性地产生事件。

  3. 回调函数的形式如下:

    void CALLBACK CXXXDlg::MMTimeProc(UINT uID, UINT uMsg, DWORD dwUsers, DWORD dw1, DWORD dw2)

    {

      CXXXDlg pDlg = (CXXXDlg)(dwUsers);

      //添加你的处理代码

      …

    }

    当回调函数是类里面的函数时,一定要声明为静态函数。

  4. 例子:

    MMRESULT timer_id = timeSetEvent(100, 1, (LPTIMECALLBACK)MMTimeProc, (DWORD)this, TIME_PERIODIC);

      这条语句设定了一个定时器事件,定时精度是1ms,每隔100ms执行一次MMTimeProc指定的回调函数。

      timer_id标识该定时器事件,当不再使用时,可以使用timeKillEvent结束该定时器事件,即timeKillEvent(timer_id)。

  5. 对回调函数的编写需要注意,如果不是类的成员函数,则可以直接这样定义

    void CALLBACK MMTimeProc(UINT uID, UINT uMsg, DWORD dwUsers, DWORD dw1, DWORD dw2)

    {

      //添加你的处理代码

      …

    }

    但是由于在MFC中使用,声明为外部函数会导致访问类成员的困难。因此可以将其定义为类的成员函数,但是需要将其定义为静态成员函数,如此一来,仍旧无法直接访问类的其他成员函数,因为对非静态成员函数的访问需要类对象。

    注意到timeSetEvent的第四个参数,为用户提供的回调数据,因此可以将当前对象的this指针传递给回调函数,然后从回调函数的第三个参数dwUsers解析出来。这样,不论将其声明为外部函数还是类的静态成员函数,均可以对其中的成员数据或函数进行访问。

  6. pDlg->UpdateData()报错

    当我将回调函数声明为类的静态成员函数,并将this指针传递给回调函数时,发现在回调函数内pDlg->UpdateData(TRUE)的执行出现如下图所示错误

    多媒体定时器(timeSetEvent)及使用pDlg-&gt;UpdateData()错误
    针对这一错误,存在两种较为简单的解决方式:
  • 使用control变量或直接获取控件指针对控件的变量进行更新:

    pDlg->m_editCtrl.SetWindowText(pDlg->m_value2);

    pDlg->GetDlgItem(IDC_EDIT2)->SetWindowText(pDlg->m_value2);

  • 最简单的办法,将Debug改为Release即可正常运行。