Timer unter Windows
-
Hallo an alle!
Folgendes Problem: Ich möchte einen Timer im Programm setzen, der nach z.B. 5 sec eine bestimmte Aktion ausführt, das Programm soll bis dahin aber normal weiter laufen.
Habe folgendes versucht:
// Funktion, die beim Timeout ausgeführt werden soll void CALLBACK TimeOut(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { printf("Timeout!"); } main() { UINT timerID; // ID für Timer; timerID = SetTimer(NULL,1,(UINT)5000,&(TIMERPROC)TimeOut); // Timer setzen auf 5 sec /* Hier folgt weiterer Code */ }
Alles läuft ohne Fehler, aber das Programm arbeitet einfach den weiteren Code ab, ohne dass die TimeOut Funktion jemals aufgerufen wird.
Was mache ich falsch?
-
Hallo,
Wireman schrieb:
Was mache ich falsch?
Nur die Dokumentation nicht richtig gelesen, denn:
MSDN-Doku schrieb:
An application can process WM_TIMER messages by including a WM_TIMER case statement in the window procedure or by specifying a TimerProc callback function when creating the timer. When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER.
MfG,
Probe-Nutzer
-
Danke für die Antwort, aber leider werd ich nicht so ganz schlau daraus.
When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER.
Was genau will mir dieser Text sagen? Was muss ich wo ändern? Wäre für ein paar erklärende Worte dankbar.
-
CALLBACKTimeOut
fehlt da eventuell ein Leerzeichen
also CALLBACK TimeOut
-
Melan schrieb:
CALLBACKTimeOut
fehlt da eventuell ein Leerzeichen
also CALLBACK TimeOutNe, war nur ein Tippfehler beim Schreiben des Beitrags.
-
du schreibst den code ab um ihn hier darzustellen?
wegrofl
-
omfg schrieb:
du schreibst den code ab um ihn hier darzustellen?
wegroflNa du scheinst ja ein besonders helles Köpfchen zu sein.
Das Originalprogramm ist lange, verschachtelt und kompliziert. Da ist Copy/Paste
nicht so einfach möglich, also habe ich das eigentliche Problem an einem kurzen Beispielcode verdeutlicht.
Nachdem das hoffentlich zu deiner Zufriedenheit geklärt ist dürfte einer produktiven Antwort ja nichts mehr im Wege stehen.
-
Du kannst die Thematik über Waitable Timer realisieren.
VOID CALLBACK TimerAPCProc( LPVOID lpArg, // Data value DWORD dwTimerLowValue, // Timer low value DWORD dwTimerHighValue ) // Timer high value { MessageBox(NULL, "Timer", "TEST", MB_OK); } int main( void ) { HANDLE hTimer; BOOL bSuccess; __int64 qwDueTime; LARGE_INTEGER liDueTime; MYDATA MyData; hTimer = CreateWaitableTimer( NULL, // Default security attributes FALSE, // Create auto-reset timer TEXT("MyTimer")); // Name of waitable timer if (hTimer != NULL) { // Create an integer that will be used to signal the timer // 5 seconds from now. qwDueTime = -5 * _SECOND; // Copy the relative time into a LARGE_INTEGER. liDueTime.LowPart = (DWORD) ( qwDueTime & 0xFFFFFFFF ); liDueTime.HighPart = (LONG) ( qwDueTime >> 32 ); bSuccess = SetWaitableTimer( hTimer, // Handle to the timer object &liDueTime, // When timer will become signaled 0, // Periodic timer interval of 2 seconds TimerAPCProc, // Completion routine NULL, // Argument to the completion routine FALSE ); // Do not restore a suspended system if ( bSuccess ) { while(true) { SleepEx( 0, // Don't wait TRUE ); // Put thread in an alertable state*/ printf("Main\n"); } } else { printf("SetWaitableTimer failed with error"); } } return 0; }
Link zu Snycfunktionen.
Link zu SleepEx.Gruß
-
Du könntest Dir auch einen kleinen Thread mit MessageSchleife schreiben:
#include <windows.h> #include <process.h> #include <iostream> #include <conio.h> using namespace std; // Funktion, die beim Timeout ausgeführt werden soll void CALLBACK TimeOut(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { printf("Timeout!\n"); } DWORD WINAPI MyThread (void * Param) { MSG msg; UINT timerID; // ID für Timer; timerID = SetTimer(NULL,1,(UINT)5000,&(TIMERPROC)TimeOut); // Timer setzen auf 5 sec while (GetMessage (&msg, NULL, 0, 0)) { DispatchMessage(&msg); } KillTimer(NULL, timerID); return 0; } void main(void) { int i; char c; DWORD dwThreadID; HANDLE hThread; hThread = CreateThread(NULL, 0, MyThread, NULL, 0, &dwThreadID); getch(); PostThreadMessage(dwThreadID, WM_QUIT, 0, 0); WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); }
-
Hallo,
Wireman schrieb:
Danke für die Antwort, aber leider werd ich nicht so ganz schlau daraus.
When you specify a TimerProc callback function, the default window procedure calls the callback function when it processes WM_TIMER. Therefore, you need to dispatch messages in the calling thread, even when you use TimerProc instead of processing WM_TIMER.
Was genau will mir dieser Text sagen? Was muss ich wo ändern? Wäre für ein paar erklärende Worte dankbar.
Gerne. Da du nur eine einfache Konsolenanwendung schreiben willst, so wie es aussieht, gibt es einige Konsequenzen. Unter anderem müsstest du, um SetTimer zu verwenden, eine "Nachrichtenschleife" einbauen, was für Konsolenprogramme eher untypisch ist. Erst diese Schleife würde dafür sorgen, dass deine Timer-Funktion aufgerufen wird. Aber wenn das Programm weiter laufen soll, dann ist so ein Vorgehen sowieso nicht geeignet, ganz abgesehen davon, dass SetTimer für Konsolenprogramme überhaupt nicht verwendet werden sollte.
Also müssen andere Lösungen her, es gibt einige, aber die einfachste wären wohl der Einsatz von Multimedia-Timer, die benötigen keine Nachrichtenschleife und warten in einem eigenen Thread, bis sie die bestimmte Aktion, die auch mit einer Callback-Funktion festgelegt wird, auslösen, siehe:
http://msdn.microsoft.com/en-us/library/ms712704(VS.85).aspx
MfG,
Probe-Nutzer
-
Probe-Nutzer schrieb:
Aber wenn das Programm weiter laufen soll, dann ist so ein Vorgehen sowieso nicht geeignet, ganz abgesehen davon, dass SetTimer für Konsolenprogramme überhaupt nicht verwendet werden sollte.
Also müssen andere Lösungen her, es gibt einige, aber die einfachste wären wohl der Einsatz von Multimedia-Timer,
Die Lösung mit dem Thread finde ich einfacher, und das Hauptprogramm läuft schön weiter. Was spricht dagegen?
-
Man kann es auch mehr oder weniger Plattformunabhngig gestalten, wenn man boost::thread benutzt:
#include <boost/thread.hpp> //irgendwas, das ausgeführt werden soll void performSomeAction() { std::cout << "The action!\n"; } //Funktion wird in Thread ausgelagtert und fuehrt jede Sekunde performSomeAction aus void timerFunction() { for(;;) //der Timer laeuft endlos { performSomeAction(); boost::xtime xt; boost::xtime_get(&xt, boost::TIME_UTC); xt.sec += 1; boost::thread::sleep(xt); } } int main() { //Thread starten boost::thread t(timerFunction); //bla... }
Man kann das noch schöner machen, aber das so erstmal als grobe Idee.
-
Belli schrieb:
Probe-Nutzer schrieb:
Aber wenn das Programm weiter laufen soll, dann ist so ein Vorgehen sowieso nicht geeignet, ganz abgesehen davon, dass SetTimer für Konsolenprogramme überhaupt nicht verwendet werden sollte.
Also müssen andere Lösungen her, es gibt einige, aber die einfachste wären wohl der Einsatz von Multimedia-Timer,
Die Lösung mit dem Thread finde ich einfacher, und das Hauptprogramm läuft schön weiter. Was spricht dagegen?
Einfacher? Kommt darauf an, wie du "einfacher" definierst. Mit meinem Vorschlag kann Wireman sein bisheriges Programm fast übernehmen, er muss nur Funktionen tauschen, und nichts weiter beachten (ausser dem Hinzulinken einer weiteren Bibliothek und dem Hinzufügen des "richtigen" Headers), auch hier läuft das Programm weiter. Also deutlich weniger Code, um das gleiche zu erreichen, für mich ist das einfacher.
Belli schrieb:
Was spricht dagegen?
Für mich das Vorhandensein einer Nachrichtenschleife, einer zusätzlichen Funktion, die eigentlich nur eine Nachricht, WM_TIMER, behandeln soll, nur damit eine Callback-Funktion aufgerufen werden kann. Dann besser noch
MfG,
Probe-Nutzer
-
Ja ... die Thread-Lösung schien MIR wohl deshalb einfacher, weil ich da alles nötige parat hatte; in die Thematik mit dem MulitMediaTimer musste ich mich erst mal einlesen ...
-
Danke an alle für die Antworten, ich werde die Varianten mal ausprobieren und sehen was am besten funktioniert.