Platform SDK: Windows Multimedia中的timeSetEvent函数和timeKillEvent函数可以启动和停止一个精度达到1ms的高精度定时器。
原型:
MMRESULT timeSetEvent(
UINT uDelay,
UINT uResolution,
LPTIMECALLBACK lpTimeProc,
DWORD_PTR dwUser,
UINT fuEvent
);
Parameters
uDelay
Event delay, in milliseconds. If this value is not in the range of the minimum and maximum event delays supported by the timer, the function returns an error.
事件延迟,毫秒。如果这个值不在定时器支持的最小和最大延时之间的话,函数将返回一个错误。
uResolution
Resolution of the timer event, in milliseconds. The resolution increases with smaller values; a resolution of 0 indicates periodic events should occur with the greatest possible accuracy. To reduce system overhead, however, you should use the maximum value appropriate for your application.
定时器的分辨力,毫秒。小的数值表示高的分辨力;分辨力为0表示周期事件应该以允许的最高精度发生。尽管如此为减小系统开销,你应该使用适合你应用的最大值。
lpTimeProc
Pointer to a callback function that is called once upon expiration of a single event or periodically upon expiration of periodic events. If fuEvent specifies the TIME_CALLBACK_EVENT_SET or TIME_CALLBACK_EVENT_PULSE flag, then the lpTimeProc parameter is interpreted as a handle to an event object. The event will be set or pulsed upon completion of a single event or periodically upon completion of periodic events. For any other value of fuEvent, the lpTimeProc parameter is interpreted as a function pointer with the following signature: void (CALLBACK)(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2);
指向回调函数的指针。发生单次事件时它被调用一次,发生周期事件时,它被周期调用。如果fuEvent是TIME_CALLBACK_EVENT_SET或TIME_CALLBACK_EVENT_PULSE标识,这时lpTimeProc被翻译成事件的一个句柄。根据单个事件或周期事件的完成,事件会被设置或触发。对于fuEvent的其它值,lpTimeProc被翻译为一个函数指针,它具有下面的签名:void (CALLBACK)(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2);
dwUser
User-supplied callback data.
用户提供的回调函数数据
fuEvent
Timer event type. This parameter may include one of the following values.
定时事件类型。这个参数可能包含以下值的一个:
Value |
Meaning |
TIME_ONESHOT |
Event occurs once, after uDelay milliseconds. 事件在uDelay毫秒后发生一次 |
TIME_PERIODIC |
Event occurs every uDelay milliseconds. 事件每隔uDelay毫秒发生一次 |
The fuEvent parameter may also include one of the following values.
fuEvent也包含下面的值
Value |
Meaning |
TIME_CALLBACK_FUNCTION |
When the timer expires, Windows calls the function pointed to by the lpTimeProc parameter. This is the default. 当定时器超时,Windows调用lpTimeProc参数所指向的函数。这时默认的。 |
TIME_CALLBACK_EVENT_SET |
When the timer expires, Windows calls the SetEvent function to set the event pointed to by the lpTimeProc parameter. The dwUser parameter is ignored. 当定时器超时,Windows调用SetEvent函数来设置lpTimeProc参数所指向的事件。dwUser参数被忽略。 |
TIME_CALLBACK_EVENT_PULSE |
When the timer expires, Windows calls the PulseEvent function to pulse the event pointed to by the lpTimeProc parameter. The dwUser parameter is ignored. 当定时器超时,Windows调用PulseEvent函数来触发lpTimeProc参数所指向的事件。dwUser参数被忽略。 |
TIME_KILL_SYNCHRONOUS |
Passing this flag prevents an event from occurring after the timeKillEvent() function is called. 传递这个标识将在调用timeKillEvent()后阻止事件发生。 |
Return Values
Returns an identifier for the timer event if successful or an error otherwise. This function returns NULL if it fails and the timer event was not created. (This identifier is also passed to the callback function.)
如果成功返回定时器事件的一个标识符,否则返回一个错误。如果它失败了,这个函数返回NULL,定时器事件不会被创建。(这个标识符同样会被传递给回调函数)。
Remarks
Each call to timeSetEvent for periodic timer events requires a corresponding call to the timeKillEvent function.
Creating an event with the TIME_KILL_SYNCHRONOUS and the TIME_CALLBACK_FUNCTION flag prevents the event from occurring after the timeKillEvent function is called.
每个对timeSetEvent的周期性定时调用都需要一个相应的timeKillEvent函数的调用。
通过TIME_KILL_SYNCHRONOUS方式创建一个事件,TIME_CALLBACK_FUNCTION标识在timeKillEvent调用后将阻止事件的发生。
由于在VC++中,成员方法都有一个this指针,不能将成员方法直接作为回调函数使用。解决的方法是使用一个static的方法作为回调函数。但是如果仅仅这样的话,我们将不能使用实例中的成员变量和成员方法等。这意味着在很多情况下回调达不到我们的需求。参考网上的一些方法,注意到timeSetEvent有一个DWORD类型的用户提供的回调函数数据dwUser ,在此处如果将对象的this指针传入,然后在静态方法内通过this指针来调用成员方法。这样就可以间接的实现成员函数的回调了。这个方法是最简单的方法。但是它也存在明显的缺陷,那就是调用深度多了一级,可能引发执行效率的问题。网上也有很好的解决方法,但是会比较复杂。需要分析清成员函数调用的机制,甚至还需要编写一些汇编的代码,在这里就先不介绍了。
Example:
在类CTimerCallbackDlg中
protected:
virtual void OnMMTimer();//声明要回调的成员方法
//作为回调函数的静态方法
static void CALLBACK TimerCallBack(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
CTimerCallbackDlg * pThis=(CTimerCallbackDlg*)dwUser;//由this指针获得实例的指针
pThis->OnMMTimer();//调用要回调的成员方法
}
/***********************************/
//一个定时器的使能禁能按钮
void CTimerCallbackDlg::OnTimerEn()
{
// TODO: Add your control notification handler code here
if(!m_en)
{
//返回定时器的id,用于停止定时器,回调静态函数,传入this指针
m_timerId=timeSetEvent(100,100,&TimerCallBack,(DWORD)this,1);
m_en=true;
SetDlgItemText(IDC_TimerEn,"Stop");
}
else
{
//关闭定时器
timeKillEvent(m_timerId);
m_en=false;
SetDlgItemText(IDC_TimerEn,"Start");
}
}