转贴:
Win32 API函数库中已经为用户提供了一组用于高精度计时的底层函数,如果用户使用得当,计时精度可到1ms。这个计时精度,对于一般的实时系统控制完全可以满足要求。现将由BCB提供的重新封装后的一组与时间相关的主要接口函数(函数名、参数、功能与Win32API基本相同)说明如下: 1.DWORD timeGetTime(void)
返回从Windows启动开始经过的毫秒数。最大值为2的32次方,约49.71天。
2.MMRESULT timeSetEvent(UINT uDelay,UINT uResolution,LPTIMECALLBACK
lpTimeProc,DWORD dwUser,UINTfuEvent) 该函数设置一个定时回调事件,此事件可以是一个一次性事件或周期性事件。事件一旦被激活,便调用指定的回调函数,成功后返回事件的标识代码,否则返回NULL.参数说明如下:
uDelay:以毫秒制定事件的周期。 UResolution:以毫秒指定延时的精度,数值越小定时器事件分辩率越高。缺省值为1ms.
LpTimeProc:指向一个回调函数。 DwUser:存放用户提供的回调数据。 FuEvent:指定定时器事件类型:TIME_ONESHOT:uDelay毫秒后只产生一次事件。
TIME_PERIODIC:每隔uDelay毫秒周期性地产生事件。 3.MMRESULT timeKillEvent(UINT uTimerID)
该函数取消一个指定的定时器回调事件。uTimerID标识要取消的事件(由timeSetEvent函数返回的标识符)。如果定时器时间不存在则返回MMSYSERR_INVALPARAM。
void CALLBACK TimeProc(UINT uID,UINT uMsg,DWORD dwUser,DWORD dw1,DWORD dw2); 该函数是一个应用程序定义的回调函数,出现定时器事件时该函数被调用。TimeProc是应用程序定义的函数名的占位符。使用该函数时要注意的是,它只能调用以下有限的几组API函数:PostMessage,
timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg,
midiOutLongMsg, OutputDebugString。同时也不要使用完成时间很长的API函数,程序尽可能简短。
使用以上一组函数就可以完成毫秒级精度的计时和控制(在BCB使用时要将头文件mmsystem.h加到程序中)。由于将定时控制精确到几毫秒,定时器事件将占用大量的CPU时间和系统资源,所以在满足控制要求的前提下,应尽量将参数uResolution的数值增大。而且定时器实时控制功能完成后要尽快释放。
二、Windows
95中的定时器的应用(李振) 在windows95编程中有时要用到定时器的功能,大家常用的是通过SetTimer函数设置一个定时器,在事件WM_TIMER响应函数中处理,然后用KillTimer 函数取消此定时器。但此种方式的定时器只能精确到大约55毫秒,对于55毫秒以下的时间精度便无能为力。 笔者在这里向大家提供一个可以精确到1毫秒的定时器——多媒体定
时器。它主要通过以下函数来实现: ---- timeBeginPeriod——建立应用程序使用的定时器分辨率;
---- timeEndPeriod——清除前面用timeBeginPeriod函数建立的最小定时器分
辨率; ---- timeSetEvent——产生一个在指定的时间或时间周期间隔内执行的定时器事
件;
---- timeKillEvent——删除前面用timeSetEvent产生的定时器事件;
---- timeGetDevCaps——返回关于定时器服务能力的信息。
----下面就结合一段程序来具体说明它的用法。这段程序的主要功能是:设置两个时钟定时器,一个间隔是1毫秒,一个间隔是2秒,每执行一次,输出当前系统时钟值到文件“cure.out”,以比较此定时器的精确度。(此程序在中文windows95及Microsoft VC5.0
编译通过。只节取与定时器有关的部分程序。)
#include < stdio.h >
//包含所用系统函数的头文件,如果编译有问题,可调整此语句的位置
#include < mmsystem.h >
//定义1毫秒和2秒时钟间隔,以毫秒为单位
#define ONE_MILLI_SECOND 1
#define TWO_SECOND 2000
//定义时钟分辨率,以毫秒为单位
#define TIMER_ACCURACY 1
UINT wTimerRes_1ms,wTimerRes_2s; //定义时间间隔
UINT wAccuracy;//定义分辨率
UINT TimerID_1ms,TimerID_2s;//定义定时器句柄
CCureApp::CCureApp(): fout("cure.out", ios::out)//打开输出文件“cure.out”
{
// TODO: add construction code here,
// Place all significant
initialization in InitInstance
//给时间间隔变量赋值
wTimerRes_1ms = ONE_MILLI_SECOND
;
wTimerRes_2s = TWO_SECOND;
TIMECAPS tc;
//通过函数timeGetDevCaps取出系统的分辨率取值范围(对intel系统,
1~16毫秒),//如果无错则继续
if(timeGetDevCaps(&tc, sizeof(TIMECAPS))== TIMERR_NOERROR)
{
//分辨率的值不能超出系统的取值范围
wAccuracy = min(max(tc.wPeriodMin,
TIMER_ACCURACY),tc.wPeriodMax);
//调用timeBeginPeriod函数设置定时器的分辨率,类似于for循环的步长
timeBeginPeriod(wAccuracy);
//设置定时器
InitializeTimer();
}
}
CCureApp::~CCureApp()
{
//结束时钟
fout < < "结束时钟" < < endl;
//删除两个定时器
timeKillEvent(TimerID_1ms);
timeKillEvent(TimerID_2s);
//删除设置的分辨率
timeEndPeriod(wAccuracy);
}
注:使用完的定时器及分辨率一定要删除,否则系统会越来越慢。
void CCureApp::InitializeTimer()
{
StartOneMilliSecondTimer();
StartTwoSecondTimer();
}
//一毫秒定时器的回调函数,类似于中断处理程序
voidPASCAL//一定要声明为全局PASCAL函数,否则编译会有问题
OneMilliSecondProc(UINT wTimerID, UINT msg,
DWORD dwUser, DWORD dw1, DWORD dw2)
{
static int ms = 0;//定义计数器
CCureApp *app = (CCureApp *)dwUser;
//取得系统时间以毫秒为单位
DWORD osBinaryTime = GetTickCount();
//输出计数器值和当前系统时间到文件
app- >fout < < ++ms < < ": 1ms : "
< < osBinaryTime < < endl;
}
//加装1毫秒定时器
void CCureApp::StartOneMilliSecondTimer()
{
if((TimerID_1ms = timeSetEvent(wTimerRes_1ms, wAccuracy,
(LPTIMECALLBACK) OneMilliSecondProc,//回调函数
(DWORD)this,//用户自传送到回调函数的数据
/*周期调用,只使用一次用TIME_ONESHOT*/
TIME_PERIODIC)) == 0)
{
AfxMessageBox("不能计时", MB_OK | MB_ICONASTERISK);
}
else//不等于0表明加装成功,返回此定时器的句柄
fout < < "16ms计时:" < < endl;
}
以下为2秒定时器的回调函数和加装函数,与1毫秒的类似;
void PASCAL TwoSecondProc(UINT
wTimerID, UINT msg,
DWORD dwUser, DWORD dw1, DWORD dw2)
{
static int s = 0;
CCureApp *app = (CCureApp *)dwUser;
DWORD osBinaryTime = GetTickCount();
app- >fout < < "***********************" < <
endl;
app- >fout < < ++s < < ": 2s : " < <
osBinaryTime < < endl;
}
void CCureApp::StartTwoSecondTimer()
{
if((TimerID_2s = timeSetEvent(wTimerRes_2s, wAccuracy,
(LPTIMECALLBACK) TwoSecondProc, (DWORD)this,
TIME_PERIODIC)) == 0)
{
AfxMessageBox("不能计时", MB_OK | MB_ICONASTERISK);
}
else
fout < < "2s计时:" < < endl;
}
Win32 API函数库中已经为用户提供了一组用于高精度计时的底层函数,如果用户使用得当,计时精度可到1ms。这个计时精度,对于一般的实时系统控制完全可以满足要求。现将由BCB提供的重新封装后的一组与时间相关的主要接口函数(函数名、参数、功能与Win32API基本相同)说明如下: 1.DWORD timeGetTime(void)
返回从Windows启动开始经过的毫秒数。最大值为2的32次方,约49.71天。
2.MMRESULT timeSetEvent(UINT uDelay,UINT uResolution,LPTIMECALLBACK
lpTimeProc,DWORD dwUser,UINTfuEvent) 该函数设置一个定时回调事件,此事件可以是一个一次性事件或周期性事件。事件一旦被激活,便调用指定的回调函数,成功后返回事件的标识代码,否则返回NULL.参数说明如下:
uDelay:以毫秒制定事件的周期。 UResolution:以毫秒指定延时的精度,数值越小定时器事件分辩率越高。缺省值为1ms.
LpTimeProc:指向一个回调函数。 DwUser:存放用户提供的回调数据。 FuEvent:指定定时器事件类型:TIME_ONESHOT:uDelay毫秒后只产生一次事件。
TIME_PERIODIC:每隔uDelay毫秒周期性地产生事件。 3.MMRESULT timeKillEvent(UINT uTimerID)
该函数取消一个指定的定时器回调事件。uTimerID标识要取消的事件(由timeSetEvent函数返回的标识符)。如果定时器时间不存在则返回MMSYSERR_INVALPARAM。
void CALLBACK TimeProc(UINT uID,UINT uMsg,DWORD dwUser,DWORD dw1,DWORD dw2); 该函数是一个应用程序定义的回调函数,出现定时器事件时该函数被调用。TimeProc是应用程序定义的函数名的占位符。使用该函数时要注意的是,它只能调用以下有限的几组API函数:PostMessage,
timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg,
midiOutLongMsg, OutputDebugString。同时也不要使用完成时间很长的API函数,程序尽可能简短。
使用以上一组函数就可以完成毫秒级精度的计时和控制(在BCB使用时要将头文件mmsystem.h加到程序中)。由于将定时控制精确到几毫秒,定时器事件将占用大量的CPU时间和系统资源,所以在满足控制要求的前提下,应尽量将参数uResolution的数值增大。而且定时器实时控制功能完成后要尽快释放。
二、Windows
95中的定时器的应用(李振) 在windows95编程中有时要用到定时器的功能,大家常用的是通过SetTimer函数设置一个定时器,在事件WM_TIMER响应函数中处理,然后用KillTimer 函数取消此定时器。但此种方式的定时器只能精确到大约55毫秒,对于55毫秒以下的时间精度便无能为力。 笔者在这里向大家提供一个可以精确到1毫秒的定时器——多媒体定
时器。它主要通过以下函数来实现: ---- timeBeginPeriod——建立应用程序使用的定时器分辨率;
---- timeEndPeriod——清除前面用timeBeginPeriod函数建立的最小定时器分
辨率; ---- timeSetEvent——产生一个在指定的时间或时间周期间隔内执行的定时器事
件;
---- timeKillEvent——删除前面用timeSetEvent产生的定时器事件;
---- timeGetDevCaps——返回关于定时器服务能力的信息。
----下面就结合一段程序来具体说明它的用法。这段程序的主要功能是:设置两个时钟定时器,一个间隔是1毫秒,一个间隔是2秒,每执行一次,输出当前系统时钟值到文件“cure.out”,以比较此定时器的精确度。(此程序在中文windows95及Microsoft VC5.0
编译通过。只节取与定时器有关的部分程序。)
#include < stdio.h >
//包含所用系统函数的头文件,如果编译有问题,可调整此语句的位置
#include < mmsystem.h >
//定义1毫秒和2秒时钟间隔,以毫秒为单位
#define ONE_MILLI_SECOND 1
#define TWO_SECOND 2000
//定义时钟分辨率,以毫秒为单位
#define TIMER_ACCURACY 1
UINT wTimerRes_1ms,wTimerRes_2s; //定义时间间隔
UINT wAccuracy;//定义分辨率
UINT TimerID_1ms,TimerID_2s;//定义定时器句柄
CCureApp::CCureApp(): fout("cure.out", ios::out)//打开输出文件“cure.out”
{
// TODO: add construction code here,
// Place all significant
initialization in InitInstance
//给时间间隔变量赋值
wTimerRes_1ms = ONE_MILLI_SECOND
;
wTimerRes_2s = TWO_SECOND;
TIMECAPS tc;
//通过函数timeGetDevCaps取出系统的分辨率取值范围(对intel系统,
1~16毫秒),//如果无错则继续
if(timeGetDevCaps(&tc, sizeof(TIMECAPS))== TIMERR_NOERROR)
{
//分辨率的值不能超出系统的取值范围
wAccuracy = min(max(tc.wPeriodMin,
TIMER_ACCURACY),tc.wPeriodMax);
//调用timeBeginPeriod函数设置定时器的分辨率,类似于for循环的步长
timeBeginPeriod(wAccuracy);
//设置定时器
InitializeTimer();
}
}
CCureApp::~CCureApp()
{
//结束时钟
fout < < "结束时钟" < < endl;
//删除两个定时器
timeKillEvent(TimerID_1ms);
timeKillEvent(TimerID_2s);
//删除设置的分辨率
timeEndPeriod(wAccuracy);
}
注:使用完的定时器及分辨率一定要删除,否则系统会越来越慢。
void CCureApp::InitializeTimer()
{
StartOneMilliSecondTimer();
StartTwoSecondTimer();
}
//一毫秒定时器的回调函数,类似于中断处理程序
voidPASCAL//一定要声明为全局PASCAL函数,否则编译会有问题
OneMilliSecondProc(UINT wTimerID, UINT msg,
DWORD dwUser, DWORD dw1, DWORD dw2)
{
static int ms = 0;//定义计数器
CCureApp *app = (CCureApp *)dwUser;
//取得系统时间以毫秒为单位
DWORD osBinaryTime = GetTickCount();
//输出计数器值和当前系统时间到文件
app- >fout < < ++ms < < ": 1ms : "
< < osBinaryTime < < endl;
}
//加装1毫秒定时器
void CCureApp::StartOneMilliSecondTimer()
{
if((TimerID_1ms = timeSetEvent(wTimerRes_1ms, wAccuracy,
(LPTIMECALLBACK) OneMilliSecondProc,//回调函数
(DWORD)this,//用户自传送到回调函数的数据
/*周期调用,只使用一次用TIME_ONESHOT*/
TIME_PERIODIC)) == 0)
{
AfxMessageBox("不能计时", MB_OK | MB_ICONASTERISK);
}
else//不等于0表明加装成功,返回此定时器的句柄
fout < < "16ms计时:" < < endl;
}
以下为2秒定时器的回调函数和加装函数,与1毫秒的类似;
void PASCAL TwoSecondProc(UINT
wTimerID, UINT msg,
DWORD dwUser, DWORD dw1, DWORD dw2)
{
static int s = 0;
CCureApp *app = (CCureApp *)dwUser;
DWORD osBinaryTime = GetTickCount();
app- >fout < < "***********************" < <
endl;
app- >fout < < ++s < < ": 2s : " < <
osBinaryTime < < endl;
}
void CCureApp::StartTwoSecondTimer()
{
if((TimerID_2s = timeSetEvent(wTimerRes_2s, wAccuracy,
(LPTIMECALLBACK) TwoSecondProc, (DWORD)this,
TIME_PERIODIC)) == 0)
{
AfxMessageBox("不能计时", MB_OK | MB_ICONASTERISK);
}
else
fout < < "2s计时:" < < endl;
}
解决方案 »
- Edit Control判断长度问题
- 使用VC调用默认浏览器打开网页,怎么判断加载完毕
- 关于键盘钩子获得的值传递给dialog
- 用mfc创建的activex控件中, 想引用另一个activex控件, 改怎么做
- PPERF_DATA_BLOCK是一种什么样的数据类型?
- 我用vc写一个标准c的程序,debug版正确,但release版一运行就保内存读错误,请问是怎么回事?该怎样调试?
- 怎样hook某个程序的键盘按键
- 什么时候用ACTIVEX,什么时候用LIB
- 资源管理器的右边应该是什么控件窗口?我用的是dialog风格,左边的tree已做完
- 怎样知道应用程序已经启动过一次了,谢谢!
- ADO初学者的疑惑!!
- 我做了个记时器响应的程序,再特定的时间里做一些操作,怎么把他放到后台里去?
---- Returns the system time, in milliseconds。 这个API函数可以返回系统的时钟,同时你要尝试通过重定义 CWinApp::OnIdle( ) 这个虚函数,在里边获得时间间隔(两次时间采样的差值)来做你所需的判断与操作,做动画一般用这个方法。