Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: Is it Safe to Reset a Timer in the timer's Callback Function??

214 views
Skip to first unread message

Nikolaos D. Bougalis

unread,
Jun 1, 2004, 2:18:00 PM6/1/04
to
bruce wrote:
> Hi,
>
> New to MFC and C++, and timer syntax is giving me fits. Here is what I am trying to do. From one function (bottom of the 3 listed below) I would like to set a timer for a specific amount of time. Compiler is happy.
> Then, from within the Timer Callback routine, I want to set another timer (second routine shown below), using the exact same syntax, but I get the compiler error:
>
> CWnd::SetTimer : illegal call of non-static member function
>
> Also, if I want to reset a timer for another period of time, is it done by just calling SetTimer again, with the same parameters, from within the Callback function (and passing the Callback function iteself as a parameter? I.e., in the PeriodicTimerCallback function, below, could I replace "do some stuff" wit this line?
>
> Any suggestions about what I might be doing wrong would be gladly accepted
>
> UINT StartUpTimer = CWnd::SetTimer(998, 5000, PeriodicTimerCallback);
>
>
>
>
> void CALLBACK EXPORT PeriodicTimerCallback( HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
> {
> .. do some stuff
> }
>
>
> void CALLBACK EXPORT OneShotTimerCallback( HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
> {
> ...
> ===========> following line throws compiler error
> UINT StartUpTimer = CWnd::SetTimer(998, 5000, PeriodicTimerCallback);
> ....
> }
>
> And in calling routine, I have this ....
>
> // And, set the timer ....
> UINT StartUpTimer = CWnd::SetTimer(999, SetTimeInMilliSeconds, OneShotTimerCallback);

CWnd::SetTimer() is not a static member function -- that means, that in
order to call it, you MUST have a valid CWnd object.

Why do you use callbacks, instead of handling WM_TIMER in the window class?

-n

Pat

unread,
Jun 1, 2004, 2:49:00 PM6/1/04
to

"bruce" <anon...@discussions.microsoft.com> wrote in message
news:006E3E45-03A5-476E...@microsoft.com...

I must admit I never did it that way. What's always worked for me was to
use something like:
SetTimer(201, 10, NULL);
and use class wizard to handle the WM_TIMER message
in an OnTimer(UINT nIDEvent).
which has stuff like:
switch (nIDEvent)
{
case 201:
KillTimer(201);
...


Nikolaos D. Bougalis

unread,
Jun 1, 2004, 3:47:58 PM6/1/04
to

Well, it really depends on your specific application. Without knowing
more about what you're trying to do, I cannot answer the "does it make
more sense" question.

If you decide to try the WM_TIMER way, what you'll have to do is add a
handler function for WM_TIMER (the MS IDE's let you do in a "point and
click" fashion, but the details vary depending of the version of the IDE
you're using). It will end up looking something like this:

void CYourWnd::OnTimer(UINT nIDEvent)
{
if(nIDEvent == 998)
{ // this is the "998" timer
...
return;
}

if(nIDEvent == 999)
{ // this is the "999" timer
...
return;
}

// You can add more "if" blocks like the above here
// for as many timer ID's as you need.
//
// Remember to call the base class if you did not
// recognize the timer ID. If your class is derived
// from something other than CWnd, then replace
// CWnd with the appropriate base class

CWnd::OnTimer(nIDEvent);
}

Now, when you set the timer, you can do something like this:

SetTimer(998, 5000, NULL);

-n

Trevor

unread,
Jun 1, 2004, 4:35:41 PM6/1/04
to

"bruce" <anon...@discussions.microsoft.com> wrote in message
news:17B8C00D-50EF-4F5D...@microsoft.com...
> Nikolaos,
>
> I guess it is because I am unaware of WM_Timer and how I would use it,
whereas I thought I had SetTimer figured out. Does it make more sense to
user WM_Timer, and if so, can you point me to some examples and or white
papers?
>

You should make this decision carefully. I prefer to use callbacks rather
than having WM_TIMER be posted. The reason I choose callbacks over WM_TIMER
is that the callback will always be called no matter how many messages the
window is pumping. The WM_TIMER message is a low priority message. If your
message queue is full or really busy, all of your WM_TIMER messages are
ignored because they are of less priority than most other window messages
(virtually all but WM_PAINT). There is also less overhead in calling a
function directly rather than posting a windows message and waiting for it
to be seen by your message loop. I am not saying do not use WM_TIMER, but
if it is anything critical, I would not trust the WM_TIMER method over the
callback method because under certain situations your WM_TIMER message will
never be received.

Joseph M. Newcomer

unread,
Jun 1, 2004, 10:06:12 PM6/1/04
to
The timer callback routine has no reference to a window, so you cannot call
CWnd::SetTimer, which requires a window reference. Timer callbacks are particularly nasty
things to use, because Microsoft overlooked the ability to pass a pointer-sized value to
them to carry useful information. Therefore, they are very risky to consider at all in
such a context.

Do not use hardwired numbers for timer IDs. Always use a #define.

But in general, you should consider using WM_TIMER messages instead of callbacks. Life
becomes a great deal simpler.

The answer is that it is legal to reset the timer interval in any handler. The problem is
that the callback has to be a static method, and consequently cannot access the CWnd.
Using an OnTimer handler makes this problem go away, and is the preferred way of handling
timer events.

As far as I can tell, there is no advantage to using timer callbacks, and considerable
disadvantage.
joe

On Tue, 1 Jun 2004 10:06:04 -0700, "bruce" <anon...@discussions.microsoft.com> wrote:

>Hi,
>
>New to MFC and C++, and timer syntax is giving me fits. Here is what I am trying to do. From one function (bottom of the 3 listed below) I would like to set a timer for a specific amount of time. Compiler is happy.
>Then, from within the Timer Callback routine, I want to set another timer (second routine shown below), using the exact same syntax, but I get the compiler error:
>
> CWnd::SetTimer : illegal call of non-static member function
>
>Also, if I want to reset a timer for another period of time, is it done by just calling SetTimer again, with the same parameters, from within the Callback function (and passing the Callback function iteself as a parameter? I.e., in the PeriodicTimerCallback function, below, could I replace "do some stuff" wit this line?
>
>Any suggestions about what I might be doing wrong would be gladly accepted
>
> UINT StartUpTimer = CWnd::SetTimer(998, 5000, PeriodicTimerCallback);
>
>
>
>
>void CALLBACK EXPORT PeriodicTimerCallback( HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
>{
> .. do some stuff
>}
>
>
>void CALLBACK EXPORT OneShotTimerCallback( HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
>{
> ...
>===========> following line throws compiler error
> UINT StartUpTimer = CWnd::SetTimer(998, 5000, PeriodicTimerCallback);
> ....
>}
>
>And in calling routine, I have this ....
>
> // And, set the timer ....
> UINT StartUpTimer = CWnd::SetTimer(999, SetTimeInMilliSeconds, OneShotTimerCallback);
>

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Alexander Grigoriev

unread,
Jun 1, 2004, 10:41:54 PM6/1/04
to
Window timer callback is handled at the same time WM_TIMER is dequeued.
There is no difference between handling WM_TIMER and having a callback
function called, regarding latency.

"Trevor" <tre...@nospam.com> wrote in message
news:eoDIfgBS...@TK2MSFTNGP10.phx.gbl...

Joseph M. Newcomer

unread,
Jun 1, 2004, 10:20:16 PM6/1/04
to
I once believed that, but it isn't true. I forget who posted the correction to me, many
years ago. The callback is initiated by the same mechanism that dispatches the WM_TIMER
message itself. This means the callback happens only when the WM_TIMER message would be
dispatched.

From the SetTimer documentation:

Remarks

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.

The overhead issue is irrelevant and should not even enter such a discussion.

joe

Joseph M. Newcomer [MVP]

Jerry Coffin

unread,
Jun 3, 2004, 11:06:17 AM6/3/04
to
In article <eoDIfgBS...@TK2MSFTNGP10.phx.gbl>, tre...@nospam.com
says...

[ ... ]

> You should make this decision carefully. I prefer to use callbacks rather
> than having WM_TIMER be posted. The reason I choose callbacks over WM_TIMER
> is that the callback will always be called no matter how many messages the
> window is pumping.

Not true -- the callback function is invoked from a WM_TIMER handler
in DefWindowProc/DefFrameProc.

--
Later,
Jerry.

The universe is a figment of its own imagination.

0 new messages