微软提供的SetTimer,KillTimer这样的函数设置定时器很简单。
但WM_TIMER这样的消息却是优先级很低。
很多情况下,如果你需要定时的去调用你的函数来实现功能。但是当系统繁忙的时候,你可能迟迟响应不到这样的消息。
我就有过这样的经历,需要定时的把视频流写入到文件。本来设置成1、2分钟,结果有时候竟然30分钟才响应。如果用CreateWaitableTimer之类的函数又太繁琐。要是设置很多定时器怎么办呢?
一怒之下,自己写了一组函数。
头文件:
TimerEx.h:
#pragma once
#include <list>
using namespace std;
class TimerParam
{
public:
HWND hWnd;
UINT nIDEvent;
UINT uElapse;
HANDLE hTimer;
CWinThread* pThread;
};
//list<TimerParam*> m_listpTimer;
UINT SetTimerEx(HWND hWnd, UINT nIDEvent,UINT uElapse);
BOOL KillTimerEx(HWND hWnd, UINT uIDEvent);
TimerEx.cpp
#include "StdAfx.h"
#include ".\timerex.h"
UINT SetTimerEx(HWND hWnd, UINT nIDEvent,UINT uElapse);
BOOL KillTimerEx(HWND hWnd, UINT uIDEvent);
UINT MyControllingTimerFunction( LPVOID pParam );
list<TimerParam*> m_listpTimer;
UINT MyControllingTimerFunction( LPVOID pParam )
{
TimerParam*pTimerParam=(TimerParam*)pParam;
int nSleep=0;
while(WaitForSingleObject(pTimerParam->hTimer,nSleep)==WAIT_TIMEOUT)
{
SendMessage(pTimerParam->hWnd,WM_TIMER,pTimerParam->nIDEvent,0);
nSleep=pTimerParam->uElapse;
}
return 0;
}
UINT SetTimerEx(HWND hWnd, UINT nIDEvent,UINT uElapse)
{
TimerParam*pParam=new TimerParam;
pParam->hWnd=hWnd;
pParam->nIDEvent=nIDEvent;
pParam->uElapse=uElapse;
pParam->hTimer=CreateEvent(NULL,TRUE,NULL,NULL);
pParam->pThread=AfxBeginThread(MyControllingTimerFunction,pParam);
m_listpTimer.push_back(pParam);
return 0;
}
BOOL KillTimerEx(HWND hWnd, UINT uIDEvent)
{
MSG msg;
for(list<TimerParam*>::iterator _Iter=m_listpTimer.begin();
_Iter!=m_listpTimer.end();_Iter++)
{
TimerParam*pTimer=*_Iter;
if(pTimer->hWnd==hWnd&&pTimer->nIDEvent==uIDEvent)
{
SetEvent(pTimer->hTimer);
Sleep(0);
PeekMessage(&msg,hWnd,0,0,PM_NOREMOVE);
Sleep(0);
WaitForSingleObject(pTimer->pThread->m_hThread,INFINITE);
CloseHandle(pTimer->hTimer);
delete pTimer;
m_listpTimer.erase(_Iter);
break;
}
}
return TRUE;
}
你可以在窗口类面,用向导加入WM_TIMER消息。
作为测试,你可以在OnCreate函数中加入:
for(int n=1;n<nMax;n++)
::SetTimerEx(m_hWnd,n,1000*n);
OnDestroy()加入:
for(int n=1;n<nMax;n++)
::KillTimerEx(m_hWnd,n);
OnTimer(UINT nIDEvent)中加入你想要的函数就可以了。
如果你想修改以前的代码,只需要
在SetTimer的地方改成::SetTimerEx,
KillTimer的地方::KillTimerEx就可以了。
但请注意参数。
====================
关于KillTimerEx里面的2个小地方稍微做下解释:
Sleep(0);表示切换到另外一个线程。
PeekMessage,表示处理一下SendMessage消息。
这点比较重要,如果万一线程正在SendMessage中,而你又在
WaitForSingleObject(pTimer->pThread->m_hThread,INFINITE);
可能会发生死在那里的情况。虽然这种可能性极小。
有什么疑问和问题或者任何建议都欢迎和我探讨。