导读:
这是一个看似简单,但是很复杂的问题,因为windows使用WM_TIMER,但是console下没有Hwnd,没有消息分发器,不象unix下可以用alarm信号定时执行某个函数,不知道java是如何实现的。
想起masterz曾经给出过例子,自从做java后,再也没有见过他。其实这个也不难,但首先要保证你的定时器要在一个线程中设置,如果你用MFC,那么在控制台中你可以从CWinThread派生一个类,然后在这个类中设置定时器,但不像CWnd类中的定时器那么好用。
user timer in workthread of console app
#include
#include
#include
unsigned long WINAPI Thread(PVOID pvoid);
void main()
{
DWORD dwThreadId;
printf("use timer in workthread of console application/n");
HANDLE hThread = CreateThread(
NULL, // no security attributes
0, // use default stack size
Thread, // thread function
0, // argument to thread function
0, // use default creation flags
&dwThreadId);
DWORD dwwait=WaitForSingleObject(hThread,1000*30);
switch(dwwait)
{
case WAIT_ABANDONED:
printf("main thread WaitForSingleObject return WAIT_ABANDONED/n");
break;
case WAIT_OBJECT_0:
printf("main thread WaitForSingleObject return WAIT_OBJECT_0/n");
break;
case WAIT_TIMEOUT:
printf("main thread WaitForSingleObject return WAIT_TIMEOUT/n");
break;
}
CloseHandle(hThread);
_getch();
}
unsigned long WINAPI Thread(PVOID pvoid)
{
MSG msg;
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
UINT timerid=SetTimer(NULL,111,3000,NULL);
BOOL bRet;
int count =0;
while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
if(msg.message==WM_TIMER)
{
count++;
printf("WM_TIMER in work thread count=%d/n",count);
if(count>4)
break;
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
KillTimer(NULL,timerid);
printf("thread end here/n");
return 0;
}
另一个例子
#include
class foo_class {
static int counter;
public:
static void __stdcall timer_proc(HWND,unsigned int, unsigned int, unsigned long) {
if (counter++ <20)
MessageBox(0,"Hello","MessageBox",0);
else
PostQuitMessage(0);
}
};
int foo_class::counter=0;
WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int) {
int iTimerID = SetTimer(0, 0, 300, foo_class::timer_proc);
MSG m;
while (GetMessage(&m,0,0,0)) {
TranslateMessage(&m);
DispatchMessage(&m);
}
return 1;
}
在win2k以后的平台使用CreateTimerQueue和CreateTimerQueueTimer
msdn的例子
// testTimer.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#define _WIN32_WINNT 0x0500
#include #include
HANDLE gDoneEvent;
VOID CALLBACK TimerRoutine(PVOID lpParam, BOOLEAN TimerOrWaitFired)
{
if (lpParam == NULL)
{
printf("TimerRoutine lpParam is NULL/n");
}
else
{
// lpParam points to the argument; in this case it is an int
printf("Timer routine called. Parameter is %d./n",
*(int*)lpParam);
}
//SetEvent(gDoneEvent);
}
int main()
{
HANDLE hTimer = NULL;
HANDLE hTimerQueue = NULL;
int arg = 123;
// Use an event object to track the TimerRoutine execution
gDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (NULL == gDoneEvent)
{
printf("CreateEvent failed (%d)/n", GetLastError());
return 1;
}
// Create the timer queue.
hTimerQueue = CreateTimerQueue();
if (NULL == hTimerQueue)
{
printf("CreateTimerQueue failed (%d)/n", GetLastError());
return 2;
}
// Set a timer to call the timer routine in 10 seconds.
if (!CreateTimerQueueTimer( &hTimer, hTimerQueue,
(WAITORTIMERCALLBACK)TimerRoutine, &arg , 0, 1000*60, 0))
{
printf("CreateTimerQueueTimer failed (%d)/n", GetLastError());
return 3;
}
// TODO: Do other useful work here
printf("Call timer routine in 10 seconds.../n");
// Wait for the timer-queue thread to complete using an event
// object. The thread will signal the event at that time.
if (WaitForSingleObject(gDoneEvent, INFINITE) != WAIT_OBJECT_0)
printf("WaitForSingleObject failed (%d)/n", GetLastError());
// Delete all timers in the timer queue.
if (!DeleteTimerQueue(hTimerQueue))
printf("DeleteTimerQueue failed (%d)/n", GetLastError());
return 0;
}
如果编译不通过,只好动态加载CreateTimerQueue和CreateTimerQueueTimer
typedef BOOL (WINAPI *CreateTimerQueueTimerT)( PHANDLE phNewTimer , HANDLE TimerQueue , WAITORTIMERCALLBACKFUNC Callback , PVOID Parameter , DWORD DueTime , DWORD Period , ULONG Flags );
typedef HANDLE (*CreateTimerQueueT)(VOID);
HMODULE hMod = LoadLibrary("kernel32.dll");
if(hMod!=NULL)
{
CreateTimerQueueTimerT CreateTimerQueueTimer = (CreateTimerQueueTimerT)::GetProcAddress(hMod, "CreateTimerQueueTimer");
CreateTimerQueueT CreateTimerQueue = (CreateTimerQueueT)::GetProcAddress(hMod, "CreateTimerQueue");
if(CreateTimerQueueTimer!=NULL&&CreateTimerQueue!=NULL)
{
hTimerQueue = CreateTimerQueue();
if (NULL == hTimerQueue)
{
printf("CreateTimerQueue failed (%d)/n", GetLastError());
}
const int ntimedelay=1000*60*3;
if (!CreateTimerQueueTimer(&hTimer, hTimerQueue, TimerRoutine, 0 , ntimedelay, ntimedelay, 0))
{
printf("CreateTimerQueueTimer failed (%d)/n", GetLastError());
}
}
FreeLibrary(hMod);
使用CreateWaitableTimer不需要麻烦,此时注意一般console建立的时候,是单线程,要改为多线程。
#include "stdafx.h"
#define _WIN32_WINNT 0x0400
#include
#include
#include /* _beginthread, _endthread */
#include
#include
#include
unsigned __stdcall TF(void* arg) {
HANDLE timer=(HANDLE) arg;
while (1) {
WaitForSingleObject(timer,INFINITE);
printf(".");
}
}
int main(int argc, char* argv[]) {
HANDLE timer = CreateWaitableTimer(
0,
false, // false=>will be automatically reset
0); // name
LARGE_INTEGER li;
const int unitsPerSecond=10*1000*1000; // 100 nano seconds
// Set the event the first time 2 seconds
// after calling SetWaitableTimer
li.QuadPart=-(2*unitsPerSecond);
SetWaitableTimer(
timer,
&li,
750, // Set the event every 750 milli Seconds
0,
0,
false);
_beginthreadex(0,0,TF,(void*) timer,0,0);
// Wait forever,
while (1) ;
return 0;
}
如果是XP ,使用多媒体定时器timeSetEvent()函数,该函数定时精度为ms级。利用该函数可以实现周期性的函数调用。函数的原型如下:
MMRESULT timeSetEvent( UINT uDelay,
UINT uResolution,
LPTIMECALLBACK lpTimeProc,
WORD dwUser,
UINT fuEvent )
该函数设置一个定时回调事件,此事件可以是一个一次性事件或周期性事件。事件一旦被激活,便调用指定的回调函数, 成功后返回事件的标识符代码,否则返回NULL。函数的参数说明如下:
uDelay:以毫秒指定事件的周期。
Uresolution:以毫秒指定延时的精度,数值越小定时器事件分辨率越高。缺省值为1ms。
LpTimeProc:指向一个回调函数。
DwUser:存放用户提供的回调数据。
FuEvent:指定定时器事件类型:
TIME_ONESHOT:uDelay毫秒后只产生一次事件
TIME_PERIODIC :每隔uDelay毫秒周期性地产生事件。
具体应用时,可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在LpTimeProc回调函数 中(如:定时采样、控制等),从而完成所需处理的事件。需要注意的是,任务处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后, 应及时调用timeKillEvent()将之释放。
#include "stdafx.h"
#include
#include
#include
#pragma comment(lib,"Winmm.lib")
void CALLBACK sig_forwin(long hwnd ,int uMsg , int dwUser ,long dw1 , long dw2)
{
printf("/nOK/n");
}
int main()
{
long ret ;
ret = timeSetEvent(1000,1,( LPTIMECALLBACK )sig_forwin,0,TIME_PERIODIC);
printf("ret = %d/n",ret);
getchar();
return 0 ;
}
本文转自
http://www.w3china.org/blog/more.asp?name=hongrui&id=29543