Can I use a SetTimer() API in a console C++ application?
I have a console application that is using a DLL file that uses a SetTimer()
call to create a timer and fire a function within itself. The call is below:
SetTimer((HWND)NULL, 0, timer_num, (TIMERPROC)UnSyncMsgTimer)) == 0)
It is expecting to receive timer messages, but this never happens. I assume because mine is a console application and not a standard Windows GUI application (like where the DLL file was originally used). This stops a key part of the DLL files functionality from working.
My application needs to stay a consol开发者_如何学JAVAe application, and I cannot change the DLL.
Is there a work around to make this work?
You can use CreateTimerQueueTimer function
HANDLE timer_handle_;
CreateTimerQueueTimer(&timer_handle_, NULL, TimerProc, user_object_ptr, 10, 0, WT_EXECUTEDEFAULT);
//callback
void TimerProc(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
user_object* mgr = (user_object*) lpParameter;
mgr->do();
DeleteTimerQueueTimer(NULL, timer_handle_, NULL);
timer_handle_ = NULL;
}
Timers set using the SetTimer
API require a Windows message processing function to be actively running, as that is where the time messages are sent.
If you need a timer thread then you could register a Window class and create a default window message pump (See this article for a short example), but a simpler process would probably be to just spin up a second thread to handle your timing events and send notifications.
Have a look at the following example which shows how to use WM_TIMER messages with a console app:
(Credit to the Simple Samples site)
#define STRICT 1
#include <windows.h>
#include <iostream.h>
VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime) {
cout << "Time: " << dwTime << '\n';
cout.flush();
}
int main(int argc, char *argv[], char *envp[]) {
int Counter=0;
MSG Msg;
UINT TimerId = SetTimer(NULL, 0, 500, &TimerProc);
cout << "TimerId: " << TimerId << '\n';
if (!TimerId)
return 16;
while (GetMessage(&Msg, NULL, 0, 0)) {
++Counter;
if (Msg.message == WM_TIMER)
cout << "Counter: " << Counter << "; timer message\n";
else
cout << "Counter: " << Counter << "; message: " << Msg.message << '\n';
DispatchMessage(&Msg);
}
KillTimer(NULL, TimerId);
return 0;
}
Have you considered Waitable Timers or Timer Queues? While it is possible to use SetTimer
from a console app, these other facilities might be more appropriate for you.
Using Timer Queues
Creates a timer-queue timer. This timer expires at the specified due time, then after every specified period. When the timer expires, the callback function is called.
The following example creates a timer routine that will be executed by a thread from a timer queue after a 10 second delay. First, the code uses the
CreateEvent
function to create an event object that is signaled when the timer-queue thread completes. Then it creates a timer queue and a timer-queue timer, using theCreateTimerQueue
and CreateTimerQueueTimer functions, respectively. The code uses theWaitForSingleObject
function to determine when the timer routine has completed. Finally, the code callsDeleteTimerQueue
to clean up.
For more information on the timer routine, see WaitOrTimerCallback
.
Example code from MSDN:
#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);
if(TimerOrWaitFired)
{
printf("The wait timed out.\n");
}
else
{
printf("The wait event was signaled.\n");
}
}
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 , 10000, 0, 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());
CloseHandle(gDoneEvent);
// Delete all timers in the timer queue.
if (!DeleteTimerQueue(hTimerQueue))
printf("DeleteTimerQueue failed (%d)\n", GetLastError());
return 0;
}
This is another example code from MSDN
This is another example from Codeproject
#include <windows.h>
HANDLE hTimer = NULL;
unsigned long _stdcall Timer(void*)
{
int nCount = 0;
while(nCount < 10)
{
WaitForSingleObject(hTimer, 5000);
cout << "5 s\n";
nCount++;
}
cout << "50 secs\n";
return 0;
}
void main()
{
DWORD tid;
hTimer = CreateEvent(NULL, FALSE, FALSE, NULL);
CreateThread(NULL, 0, Timer, NULL, 0, &tid);
int t;
while(cin >> t)
{
if(0==t)
SetEvent(hTimer);
}
CloseHandle(hTimer);
}
Resource:
- https://msdn.microsoft.com/en-us/library/windows/desktop/ms682485(v=vs.85).aspx
- https://msdn.microsoft.com/en-us/library/windows/desktop/ms687003(v=vs.85).aspx
Very simple timer without Windows
MSG Msg;
UINT TimerId = (UINT)SetTimer(NULL, 0, 0, NULL); // 0 minute
while (TRUE)
{
GetMessage(&Msg, NULL, 0, 0);
if (Msg.message == WM_TIMER)
{
KillTimer(NULL, TimerId);
cout << "timer message\n";
TimerId = (UINT)SetTimer(NULL, 0, 60000, NULL); // one minute.
}
DispatchMessage(&Msg);
}
精彩评论