这是一个看似简单,但是很复杂的问题,因为windows使用WM_TIMER,但是console下没有Hwnd,没有消息分发器,不象unix下可以用alarm信号定时执行某个函数,不知道java是如何实现的。想起masterz曾经给出过例子,自从做java后,再也没有见过他。其实这个也不难,但首先要保证你的定时器要在一个线程中设置,如果你用MFC,那么在控制台中你可以从CWinThread派生一个类,然后在这个类中设置定时器,但不像CWnd类中的定时器那么好用。 user timer in workthread of console app #include <windows.h> #include <stdio.h> #include <conio.h> unsigned long WINAPI Thread(PVOID pvoid); void main() { DWORD dwThreadId; printf("use timer in workthread of console application<masterz>\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 <windows.h>
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 <windows.h>#include <stdio.h>
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 <windows.h>
#include <stdio.h>
#include <process.h> /* _beginthread, _endthread */#include <stddef.h>#include <stdlib.h>#include <conio.h>
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 <stdio.h> #include <windows.h> #include <mmsystem.h> #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 ; } |