写VC程序时碰到一个定时器的问题,说明一下。
SetTimer函数用于创建一个计时器,KillTimer函数用于销毁一个计时器。计时器属于系统资源,使用完应及时销毁。
SetTimer的函数原型如下:
UINT_PTR SetTimer( HWND hWnd, UINT_PTR nIDEvent, UINT uElapse,
UINT_PTR SetTimer( HWND hWnd, UINT_PTR nIDEvent, UINT uElapse,
TIMERPROC lpTimerFunc ) ;
其中
hWnd是和timer关联的窗口句柄,此窗口必须为调用SetTimer的线程所有;如果hWnd为NULL,没有窗口和timer相关联并且nIDEvent参数被忽略
nIDEvent是timer的标识,为非零值;如果hWnd为NULL则被忽略;如果hWnd非NULL而且与timer相关联的窗口已经存在一个为此 标识的timer,则此次SetTimer调用将用新的timer代替原来的timer。timer标识和窗口相关,两个不同的窗口可以拥有 nIDEvent相同的tiemr
uElapse是以毫秒指定的计时间隔值,范围为1毫秒到4,294,967,295毫秒(将近50天),这个值指示Windows每隔多久时间给程序发送WM_TIMER消息。
lpTimerFunc是一个回调函数的指针,俗称TimerFunc;如果lpTimerFunc为NULL,系统将向应用程序队列发送 WM_TIMER消息;如果lpTimerFunc指定了一个值,DefWindowProc将在处理WM_TIMER消息时调用这个 lpTimerFunc所指向的回调函数,因此即使使用TimerProc代替处理WM_TIMER也需要向窗口分发消息。
关于SetTimer的返回值:如果hWnd为NULL,返回值为新建立的timer的ID,如果hWnd非NULL,返回一个非0整数,如果SetTimer调用失败则返回0 。
我们一般用要是是CWnd::SetTimer,然后在响应WM_TIMER消息的OnTimer函数中实现定时器的操作就可以了。但是在非MFC的程序 中,用上述的::SetTimer定时调用类自身的函数该怎么办呢?由于CALLBACK函数是static的,不能在其中直接调用类成员函数。一般给出 的方法是利用::SetTimer的第二个参数UINT_PTR nIDEvent传入this指针,第四个参数传入CALLBACK回调函数的地址;然后在CALLBACK函数中利用this调用自身的成员函数。
例:
假设有类 class TimerEg , 在头文件中定义如下函数
void timer_fun( HWND hwnd, UINT message, UINT_PTR idTimer,
DWORD dwTime );
static VOID CALLBACK timer_proc( HWND hwnd, UINT message,
static VOID CALLBACK timer_proc( HWND hwnd, UINT message,
UINT_PTR idTimer, DWORD dwTime );
在cpp文件中添加如下代码
{
UINT nTimer = ::SetTimer( NULL,
( UINT_PTR )this,
time_interval * 100,
( TIMERPROC )&timer_proc);
}
VOID TimerEg::timer_proc( HWND hwnd, UINT message,
UINT_PTR idTimer,DWORD dwTime)
{
TimerEg * pthis = (TimerEg * )dwUser;
pthis->timer_fun(…… );
}
{
TimerEg * pthis = (TimerEg * )dwUser;
pthis->timer_fun(…… );
}
void TimerEg::timer_fun(HWND hwnd, UINT message,
UINT_PTR idTimer, DWORD dwTime )
{}
{}
注意,这样做理论上是成立,可我试过很多次就是不调用timer_proc函数!!!最后,没办法了,换了两个实现定时器的函数,以
timeSetEvent和
timeKillEnent来代替SetTimer及KillTimer,关于这两个函数的定义大家可去MSDN中去查找,这里不详述了;下面给出改动后的例子,注意各函数的参数变化及this指针的传递:
在头文件中定义如下函数
void timer_fun( UINT uTimerID, UINT uMsg, DWORD_PTR dwUser,
DWORD_PTR dw1,DWORD_PTR dw2 );
static VOID CALLBACK timer_proc( UINT uTimerID, UINT uMsg,
DWORD_PTR dwUser,DWORD_PTR dw1, DWORD_PTR dw2 );
在cpp文件中添加如下代码
{
UINT nTimer =
::timeSetEvent( time_interval * 1000, 100,
( LPTIMECALLBACK )
timer_proc,
( DWORD_PTR )this, TIME_PERIODIC );
}
VOID TimerEg::timer_proc( UINT uTimerID, UINT uMsg,
DWORD_PTR dwUser, DWORD_PTR dw1,
DWORD_PTR dw2 )
{
TimerEg * pthis = (TimerEg * )dwUser;
pthis->timer_fun( uTimerID, uMsg, dwUser, dw1, dw2 );
}
TimerEg * pthis = (TimerEg * )dwUser;
pthis->timer_fun( uTimerID, uMsg, dwUser, dw1, dw2 );
}
void TimerEg::timer_fun( UINT uTimerID, UINT uMsg, DWORD_PTR dwUser,
DWORD_PTR dw1, DWORD_PTR dw2 )
{}
{
::timeKillEvent( nTiimer );
}