SetTimer函數(shù)和WM_TIMER消息是Win32 api中最基本的玩意兒了,任何初學(xué)Win32 api編程的人都應(yīng)該對(duì)此很熟悉吧。在這篇文章中,讓我們來(lái)深入了解一下和SetTimer相關(guān)的使用和應(yīng)用。 UINT_PTR SetTimer( HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc ); 我們經(jīng)常使用的情況是hWnd不為NULL,lpTimerFunc為NULL,在這種情況下系統(tǒng)每隔nIDEvent毫秒會(huì)向hWnd窗口投遞WM_TIMER消息。唯一需要注意的是: 1.自2000起,uElapse范圍是USER_TIMER_MINIMUM到USER_TIMER_MAXIMUM。超出得話,uElapse設(shè)置為1。 2.WM_TIMER消息其實(shí)是在DispatchMessage函數(shù)中直接調(diào)用hWnd的窗口過(guò)程,并且優(yōu)先級(jí)很低,只有在消息隊(duì)列中沒(méi)有其它消息的情況下,DispatchMessage才會(huì)考慮WM_TIMER。 3.使用相同的nIDEvent可以重置這個(gè)Timer,并且KillTimer(hWnd,nIDEvent)來(lái)銷毀這個(gè)Timer。 我們?cè)賮?lái)考慮hWnd為NULL的情況: 1.首先,最重要的是KillTimer時(shí),傳入的Timer Id必須是SetTimer的返回值,而不是調(diào)用SetTimer時(shí)傳入的nIDEvent參數(shù)。 2.調(diào)用SetTimer時(shí),如果nIDEvent為0或者是其它沒(méi)有被使用的Timer Id,則SetTimer會(huì)返回一個(gè)新的Timer Id。否則,就是重新設(shè)置這個(gè)Timer。 3.如果有l(wèi)pTimerFunc的話,則lpTimerFunc的參數(shù)nIDEvent是SetTimer返回的值,而不是你調(diào)用SetTimer時(shí)傳入的值。 最后看一下lpTimerFunc不為NULL的情況:lpTimerFunc會(huì)在DispatchMessage函數(shù)中被直接調(diào)用,而不會(huì)去調(diào)用hWnd的窗口過(guò)程(也就是說(shuō)收不到這個(gè)消息),無(wú)論hWnd是不是NULL。(這里,msdn中貌似有點(diǎn)問(wèn)題,SetTimer的Remark部分說(shuō)lpTimerFunc會(huì)在默認(rèn)窗口中被調(diào)用,而WM_TIMER中說(shuō)lpTimerFunc在DispatchMessage中被調(diào)用) 應(yīng)用 使用lpTimerFunc可以做一個(gè)延時(shí)的操作,或者把某些操作推遲到下一個(gè)消息循環(huán),而不需要為窗口定義一個(gè)新的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,不會(huì)使窗口收到WM_TIMER消息,那樣可以使用idEvent來(lái)傳遞自定義數(shù)據(jù)而不會(huì)和窗口自己使用的Timer id沖突。 其次,第一個(gè)參數(shù)hWnd不能為NULL,否則TimerProc的idEvent參數(shù)就不是你傳入的自定義數(shù)據(jù)了。 最后,msdn說(shuō)SetTimer不能跨線程使用,所以最好不要用這樣的方法在向ui線程來(lái)插入代碼,還是老老實(shí)實(shí)的發(fā)消息吧。 |
|
來(lái)自: 筱肆 > 《網(wǎng)文收藏》