Win32编程点滴7 - SetTimer的使用

SetTimer函数和WM_TIMER消息是Win32 api中最基本的玩意儿了,任何初学Win32 api编程的人都应该对此很熟悉吧。在这篇文章中,让我们来深入了解一下和SetTimer相关的使用和应用。

UINT_PTR SetTimer(      

    HWND hWnd,
    UINT_PTR nIDEvent,
    UINT uElapse,
    TIMERPROC lpTimerFunc
);
我们经常使用的情况是hWnd不为NULL,lpTimerFunc为NULL,在这种情况下系统每隔nIDEvent毫秒会向hWnd窗口投递WM_TIMER消息。唯一需要注意的是:
  1. 自2000起,uElapse范围是USER_TIMER_MINIMUM到USER_TIMER_MAXIMUM。超出得话,uElapse设置为1。
  2. WM_TIMER消息其实是在DispatchMessage函数中直接调用hWnd的窗口过程,并且优先级很低,只有在消息队列中没有其它消息的情况下,DispatchMessage才会考虑WM_TIMER。
  3. 使用相同的nIDEvent可以重置这个Timer,并且KillTimer(hWnd,nIDEvent)来销毁这个Timer。

我们再来考虑hWnd为NULL的情况:

  1. 首先,最重要的是KillTimer时,传入的Timer Id必须是SetTimer的返回值,而不是调用SetTimer时传入的nIDEvent参数。
  2. 调用SetTimer时,如果nIDEvent为0或者是其它没有被使用的Timer Id,则SetTimer会返回一个新的Timer Id。否则,就是重新设置这个Timer。
  3. 如果有lpTimerFunc的话,则lpTimerFunc的参数nIDEvent是SetTimer返回的值,而不是你调用SetTimer时传入的值。

最后看一下lpTimerFunc不为NULL的情况:lpTimerFunc会在DispatchMessage函数中被直接调用,而不会去调用hWnd的窗口过程(也就是说收不到这个消息),无论hWnd是不是NULL。(这里,msdn中貌似有点问题,SetTimer的Remark部分说lpTimerFunc会在默认窗口中被调用,而WM_TIMER中说lpTimerFunc在DispatchMessage中被调用)

应用1

使用lpTimerFunc可以做一个延时的操作,或者把某些操作推迟到下一个消息循环,而不需要为窗口定义一个新的Timer Id。

例如,我很喜欢这样写:

struct _DATA
{
//....
};
void CALLBACK TimerProc(HWND hwnd,
UINT uMsg,
UINT_PTR idEvent,
DWORD dwTime)
{
_DATA * data = (_DATA*)idEvent;
KillTimer(hwnd,idEvent);
//do something
free(data);
}

_DATA * data = (_DATA*)malloc(sizeof(_DATA));
SetTimer(AfxGetMainWindow()->m_hWnd,(UINT_PTR)data,10,&TimerProc);

首先,使用了TimerProc,不会使窗口收到WM_TIMER消息,那样可以使用idEvent来传递自定义数据而不会和窗口自己使用的Timer id冲突。

其次,第一个参数hWnd不能为NULL,否则TimerProc的idEvent参数就不是你传入的自定义数据了。

最后,msdn说SetTimer不能跨线程使用,所以最好不要用这样的方法在向ui线程来插入代码,还是老老实实的发消息吧。

应用2

这个应用,大家看这个页面吧http://blogs.msdn.com/oldnewthing/archive/2005/03/01/382380.aspx

使用SetTimer和PostQuitMessage来做timed MessageBox,做一个会自动关闭的MessageBox。我想,你直接看这篇文章的话,会学到更多关于win32 api的知识的。

你可能感兴趣的:(timer)