How to use SetTimer API
Solution 1
There are few problems with your program:
- C programs do end when they leave
main()
so there is no time when the timer can occur. -
Win32 timers need the message pump (see below) to be working, as they are implemented through
WM_TIMER
message, even when they are not associated with any window, and if you provide function callback.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.
Source: MSDN: SetTimer function
-
The callback function has bad prototype. See http://msdn.microsoft.com/en-us/library/windows/desktop/ms644907%28v=vs.85%29.aspx
void CALLBACK f(HWND hwnd, UINT uMsg, UINT timerId, DWORD dwTime) { printf("Hello"); } int main() { MSG msg; SetTimer(NULL, 0, 1000*60,(TIMERPROC) &f); while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 0; }
(Note this example program never ends, instead, real program should have some additional logic to do so by sending WM_QUIT
).
Solution 2
I found the best implementation to be as follow:
#define TIMER1 1001
#define TIMER2 1002
SetTimer(hWndMainWnd, // handle to main window
TIMER1, // timer identifier
1000,
NULL); // no timer callback
SetTimer(hWndMainWnd, // handle to main window
TIMER2, // timer identifier
5000,
NULL); // no timer callback
Then, as part of the main event loop:
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_TIMER:
if (wParam == TIMER1)
{
// do something1
}
else
if (wParam == TIMER2)
{
// do smoething2
}
break;
user2219913
Updated on November 20, 2020Comments
-
user2219913 over 3 years
I tried to use
SetTimer
API to call a function every X minutes. So, i have written this test codevoid f() { printf("Hello"); } int main() { SetTimer(NULL, 0, 1000*60,(TIMERPROC) &f); }
I should have Hello written every minute but it does not work.
-
mity about 11 years@ComFreek: Thx for editing, can you tell me how you do that? When I mark some (bad) part as code, I then often have a problem how to fix it, the editor just behaves strange.
-
ComFreek about 11 yearsNp ;) I replaced your
<code>
and<pre>
tags by four indents (plus the indents of the list). See also here for editing help. I've also added a quote from MSDN stating your point #2. -
user2219913 about 11 yearsthanks Mity, but if I have two methods and I want to call the first one every 15 minute and the other only one time in my programm
-
mity about 11 yearsYou can use two timers, one of them stopped with
KillTimer
in its handler. Or use one timer with a flag variable and oneif
in the timer proc. -
user2219913 about 11 yearsand if I have some code after the while that I want to execute.
-
mity about 11 yearsThat's already unrelated question. Take into account that writing Win32 programs (and using the timers lead to that) implies event-driven programming. That's simply quite different approach from writing classical C program who takes input, does some computations and writes down some output.
-
IInspectable over 6 yearsThe OP doesn't have a window, and wants to use a callback instead. This answer doesn't address that scenario. Besides, the timer IDs need to be unique. Using hardcoded values will clash with other timer code. Use the address of an object with sufficient lifetime instead. That's why the ID is pointer-sized. Also, when copying code, proper attribution should come with it.
-
Michael Haephrati over 6 yearsThe "window" parameter is optional and can be replaced by a NULL. See msdn.microsoft.com/en-us/library/windows/desktop/… to learn more. The answer addresses the exact scenario, and was fully tested. This is our own code and it works. Using hard-coded values won't clash with other timer code because all timers which are defined by SetTimer() are defined within the scope of the application. For the purpose of the answer, using these preprocessor definitions is the best thing to do.
-
IInspectable over 6 yearsThe
window
parameter is optional only, if you provide a callback. And when you do, theWM_TIMER
message is no longer posted to your window. The window procedure is meaningless in that scenario. If you use a timer callback, the timer ID is no longer associated with a window, and must be globally unique across your application. An application that uses 3rd-party code cannot use hardcoded ID values without risking a collision. Using the address of an object with suitable lifetime is the conventional technique to ensure uniqueness. -
Michael Haephrati over 6 yearsMy answer has no flaws and was fully tested. You are either repeating things I already wrote or picking up irrelevant details (like the pre-processor directive I am using). I have really nothing more to add to what I wrote. There is nothing wrong using hardcoded ID in the scope of this answer, and even if 3rd party libraries are used, it should usually not interfere (and you can find that most 3rd libraries contain a mass of their own "DEFINE ..." and that CAN be a problem but it rare. When that happens you just change your definitions. This is NOT the reason not to use DEFINE.
-
IInspectable over 6 yearsTimers can be used in two distinct ways: By handling the
WM_TIMER
message and by having the system invoke a callback. The OP is asking about the latter, while your answer explains how to use the former. Both ways have significant differences: Handling the timer (message handling in the window procedure vs. providing a callback) and scope of ID uniqueness (window vs. application). While this answer fails to explain, how to use timers with a callback, it also falls short of explaining, why the OP's code doesn't work. This answer is not useful. -
Charlie Scott-Skinner about 5 yearsThe C++ example from MSDN in the link you gave (and that I was already using) doesn't compile - thank you for showing the proper callback prototype