Saturday, September 23, 2006

A more reliable timer (unstoppable)

VFP Timer is known not so reliable. Under certain conditions, the VFP timer event can be pending/stopped. In Win32API There is a more reliable timer, SetTimer() API. However, since the older VFP version does not support the callback, many VFP'er go to C/C++ for the solution.

In VFP9, there is a way to use the SetTimer() API. BindEvent() can make this possible. Since our apps is under VFP control, there might a bit delay before the timer is fired. Anyway, again, thanks to enhanced of BindEvent() command :)

Actually, I had shown how to use SetTimer() in my OwnerDrawn Menu class. But you might not noticed that or maybe you don't get the idea about how it works. Here is the explanation.

Let's see the SetTimer declaration first:
Declare Long SetTimer in User32 ;
Long nhWnd, Long nEventId, Long uElapse, Long lpTimerFunc

As you see, the last parameter of SetTimer is pointer to a function (callback procedure). So how can you use this function. Very simple, pass in NULL pointer. Once you pass a NULL pointer, the OS will post a WM_TIMER message instead of calling the procedure. Now, simply bind the WM_TIMER into your top-level form. That would be all. For more info on SetTimer, take a look at MSDN (as usual)

This example will show you one condition that will pending/stopped the VFP timer, while SetTimer() will continue running.
? 'Using VFP Timer. Do you see the wait window?'
? 'Press ESC key or click on cancel button when ready...'
oVFPTimer = CreateObject( 'VFP_Timer' )
oVFPTimer = Null

? 'Using SetTimer() API. Watch for the wait window counting'
oWMTimer = CreateObject( 'TimerProc', _VFP.hWnd )
oWMTimer = Null


Define Class VFP_Timer as Timer
Interval = 500
Enabled = .T.
nCounter = 0

Procedure Timer
*** You won't see the wait window
Wait 'Using VFP Timer: ' + transform( This.nCounter ) window nowait
This.nCounter = This.nCounter + 1

Define Class TimerProc as Custom
#Define WM_TIMER 0x0113
#Define IDT_TIMER 1

nCounter = 0
hWnd = 0

Procedure Init( th_Wnd )
Declare Long SetTimer in User32 ;
Long nhWnd, Long nEventId, Long uElapse, Long lpTimerFunc

Declare Long KillTimer in User32 Long nhWnd, Long nEventId

** Bind the event first before SetTimer
BindEvent( th_Wnd, WM_TIMER, This, 'TimerProc' )
SetTimer( th_Wnd, IDT_TIMER, 500, 0 )
This.hWnd = th_Wnd

Procedure TimerProc( th_Wnd, tn_Msg, t_wParam, t_lParam )
Wait 'Using BindEvent (WM_TIMER): ' + transform( This.nCounter ) window nowait
This.nCounter = This.nCounter + 1
Return 0

Procedure Destroy
KillTimer( This.hWnd, IDT_TIMER )
UnBindEvents( This.hWnd )

Happy coding :)

1 comment:

Anonymous said...

Hi Mr. Herman,

I like to read your blog :)

hm... I oppositely do not suspect if that VFP timer not so realiable, it's not become attention of me during the time.

even have made Billing Aplication for the Internet Rent (WarNet) of last some years, also used timer, but during that also there is no complain of my user, possible feel does not be harmed.

Thank's Mr. Herman with this timer article, I can take its benefit of period to come.

Tetap semangat..
English saya ngaco, yang penting ngerti dah he..he..he