如何使用多媒体定时器

来源:互联网 发布:淘宝店铺宝贝素材图片 编辑:程序博客网 时间:2024/05/21 09:01

目前,Windows软件一般使用Timer定时器进行定时。Timer定时器是由应用程序响应定时消息WM_TIMER实现定时。Timer定时器是IBM PC硬件和ROM BIOS构造的定时器的简单扩充。PCROM初始化8253定时器来产生硬件中断08H,而08H中断的频率为18.2Hz,即至少每隔54.925 ms中断一次。此外,这个定时消息的优先权太低,只有在除WM_PAINT外的所有消息被处理完后,才能得到处理。多媒体定时器也是利用系统定时器工作的,但它的工作机理和普通定时器有所不同。首先,多媒体定时器可以按精度要求设置8253T/C0通道的计数初值,使定时器不存在54.945ms的限制;其次,多媒体定时器不依赖于消息机制,而是用函数产生一个独立的线程,在一定的中断次数到达后,直接调用预先设置好的回调函数进行处理,不必等到应用程序的消息队列为空,从而切实保障了定时中断得到实时响应,使其定时精度可达1ms

调用timeGetDevCaps可以获得定时服务参数。

timeGetDevCaps函数的定义如下:

MMRESULT timeGetDevCaps(LPTIMECAPS ptc, UINT cbtc);

调用timeBeginPeriod函数可以设置定时的最小分辨率。

timeBeginPeriod函数的定义如下:

MMRESULT timeBeginPeriod(UINT uPeriod);

调用timeSetEvent设置并启动定时器。

timeSetEvent函数的定义如下:

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

调用timeKillEvent函数可以取消定时器。

timeKillEvent函数的定义如下:

MMRESULT timeKillEvent(UINT uTimerID);

 

1)创建一个基于对话框的应用程序,名称为Demo

2)在IDD_DEMO_DIALOG对话框资源中添加控件,如表所示。

类型

ID

标题

Edit

IDC_TIME

 

Button

IDC_TEST1

设置定时器

Button

IDC_TEST2

取消定时器

3)创建1个基类为CWinThread的类CTimerThread

4)在TimerThread.h文件中定义宏,代码如下:

#define WM_THREADMSG WM_USER+1

5)在TimerThread.h文件中定义数据结构,代码如下:

typedef struct THREAD_PARAM

{

         HWND hWnd;

         int nTime;

         HANDLE hTimerEvent;

         HANDLE hExitEvent;

}_THREAD_PARAM;

6)在CWinThread类中添加成员变量,代码如下:

public:

         THREAD_PARAM* m_pThreadParam;

7)在CTimerThread类中重载CWinThread::Run函数,代码如下:

// TimerThread.cpp

int CTimerThread::Run()

{       

         while (TRUE)

         {

                   //等待定时事件

                  while (WAIT_TIMEOUT ==

                            WaitForSingleObject(m_pThreadParam->hTimerEvent, 200))

                   {

                            //等待退出事件

                            if (WaitForSingleObject(m_pThreadParam->hExitEvent, 0) == WAIT_OBJECT_0)

                            {

                                     ::AfxEndThread(0);

                            }

                   }

                  m_pThreadParam->nTime += 100;

                   //向主线程窗口发送消息

                  ::PostMessage(m_pThreadParam->hWnd, WM_THREADMSG, 0, 0);

                   //复位定时事件

                  ResetEvent(m_pThreadParam->hTimerEvent);     

         }

}

8)在CDemoDlg类中添加成员变量,代码如下:

// DemoDlg.cpp

private:

         UINT m_nTimerID;

         CTimerThread* m_pTimerThread;

         THREAD_PARAM m_ThreadParam;

9)在CDemoDlg类的构造函数和析构函数中添加如下代码:

// DemoDlg.cpp

CDemoDlg::CDemoDlg(CWnd* pParent /*=NULL*/)

         : CDialog(CDemoDlg::IDD, pParent)

{

         // …

         m_nTimerID = 0;

         m_pTimerThread = NULL;

         m_ThreadParam.nTime = 0;

         m_ThreadParam.hTimerEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

         m_ThreadParam.hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

}

CDemoDlg::~CDemoDlg()

{

         //取消定时器

         if (m_nTimerID != 0)

         {

                  timeKillEvent(m_nTimerID);

         }

         //结束定时线程

         if (m_pTimerThread != NULL)

         {

                   //设置退出事件

                  SetEvent(m_ThreadParam.hExitEvent);

                   //等待定时线程结束

                  ::WaitForSingleObject(m_pTimerThread->m_hThread, INFINITE);

                  delete m_pTimerThread;

                  m_pTimerThread = NULL;

         }

         CloseHandle(m_ThreadParam.hTimerEvent);

         CloseHandle(m_ThreadParam.hExitEvent);

}

10)在CDemoDlg类中为重载CDialog::OnInitDialog函数,代码如下:

// DemoDlg.cpp

BOOL CDemoDlg::OnInitDialog()

{

         CDialog::OnInitDialog();

         // …

         SetDlgItemInt(IDC_TIME, 0);

         return TRUE;

}

11)在CDemoDlg类中为WM_THREADMSG添加消息处理函数,代码如下:

// DemoDlg.cpp

BEGIN_MESSAGE_MAP(CDemoDlg, CDialog)

         //{{AFX_MSG_MAP(CDemoDlg)

         // …

         ON_MESSAGE(WM_THREADMSG, OnMsgFunc)

         //}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

LRESULT CDemoDlg::OnMsgFunc()

{

         SetDlgItemInt(IDC_TIME, m_ThreadParam.nTime);

         return 1;

}

12)在CDemoDlg类中为Button控件添加BN_CLICKED消息处理函数,代码如下:

// DemoDlg.cpp

void CDemoDlg::OnTest1()

{

         //取消定时器

         if (m_nTimerID != 0)

         {

                  timeKillEvent(m_nTimerID);

         }

         //结束定时线程

         if (m_pTimerThread != NULL)

         {

                   //设置退出事件

                  SetEvent(m_ThreadParam.hExitEvent);

                   //等待定时线程结束

                  ::WaitForSingleObject(m_pTimerThread->m_hThread, INFINITE);

                  delete m_pTimerThread;

                  m_pTimerThread = NULL;

         }

         m_ThreadParam.hWnd = GetSafeHwnd();

         m_ThreadParam.nTime = 0;

         SetDlgItemInt(IDC_TIME, 0);

         TIMECAPS tc;

         //获得定时器分辨率

         if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)

         {

                  return;

         }

         UINT nResolution = min(max(tc.wPeriodMin, 1), tc.wPeriodMax);

         UINT nInterval = 100;

         if (nInterval < nResolution)

         {

                  nInterval = nResolution;

         }

         //设置定时最小分辨率

         timeBeginPeriod(nResolution);

         //设置定时器

         m_nTimerID = timeSetEvent(nInterval, nResolution,

                  (LPTIMECALLBACK)m_ThreadParam.hTimerEvent,

                  (DWORD)this, TIME_PERIODIC | TIME_CALLBACK_EVENT_SET);

         //创建定时线程

         m_pTimerThread = (CTimerThread*)AfxBeginThread(RUNTIME_CLASS(CTimerThread),

                  THREAD_PRIORITY_ABOVE_NORMAL, 0, CREATE_SUSPENDED);

         m_pTimerThread->m_bAutoDelete = FALSE;

         m_pTimerThread->m_pThreadParam = &m_ThreadParam;

         m_pTimerThread->ResumeThread();

}

void CDemoDlg::OnTest2()

{

         //取消定时器

         if (m_nTimerID != 0)

         {

                  timeKillEvent(m_nTimerID);

         }

         //结束定时线程

         if (m_pTimerThread != NULL)

         {

                   //设置退出事件

                  SetEvent(m_ThreadParam.hExitEvent);

                   //等待定时线程结束

                  ::WaitForSingleObject(m_pTimerThread->m_hThread, INFINITE);

                  delete m_pTimerThread;

                  m_pTimerThread = NULL;

         }

}