CreateTimerQueue... how to use this API ?

Just starting out? Need help? Post your questions and find answers here.
Joris
Addict
Addict
Posts: 890
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

CreateTimerQueue... how to use this API ?

Post by Joris »

HI,

The source below from netmaestro shows a basic use of the CreateTimerQueue(). This is the API timer function MS recommend instead of the older API's like timeSetEvent().
Can anyone explain a bit more on how to use it ? What differs from the old API (which still can be used) ?
What is that @thandle.i or how to get it, for example in the CreateTimerQueueTimer() ?
What are the (important) benefits against the API's like timeSetEvent ?
Has anyone more sample code or some replacement for the Timer_Include.pbi on the link here ?

http://www.purebasic.fr/german/viewtopi ... 805#110805
viewtopic.php?f=3&t=43649&hilit=CreateT ... be14086d18
Another link I found later on showing a bit more :
http://www.purebasic.fr/german/viewtopic.php?p=213096

Here the MSDN link which explains a bit in the usual MSDN-way :mrgreen: :
http://msdn.microsoft.com/en-us/library ... s.85).aspx

I know there is possibly a lot to tell, but maybe the points of most interests...

Many thanks.

Code: Select all

Import ""
  CreateTimerQueue()
  CreateTimerQueueTimer(a,b,c,d,e,f,g)
EndImport

Global cc

Procedure Timer(parameter.i, b.b)
  cc+1
EndProcedure

tq = createtimerqueue()

CreateTimerQueueTimer(@thandle.i, tq, @Timer(), 0, 0, 1, $80)

Delay(10000)
Debug cc
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
User avatar
TI-994A
Addict
Addict
Posts: 2741
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: CreateTimerQueue... how to use this API ?

Post by TI-994A »

Joris wrote:Can anyone explain a bit more on how to use it?
What differs from the old API (which still can be used)?
What is that @thandle.i or how to get it, for example in the CreateTimerQueueTimer()?
What are the (important) benefits against the API's like timeSetEvent?
Has anyone more sample code or some replacement for the Timer_Include.pbi on the link here?
Hello Joris. Besides the fact that Microsoft has earmarked the timeSetEvent() function as obsolete, I personally find the two functions quite similar. They both have the same basic functionality, although they each have their own set of flags that determine threading, execution, response, etc. So, unless you have some very specific requirements on such behaviour, it shouldn't make much of a difference which one you use. Now, how to use it.

These first two examples demonstrate the simplicity of implementing these functions, by displaying the current time at one-second intervals, for ten seconds.

timeSetEvent example:

Code: Select all

Procedure timerProc(hTimer.i, uMsg.i, idTimer.i, wParam.i, lParam.i)
  Debug FormatDate("%hh:%ii:%ss", Date())
EndProcedure    

timer = timeSetEvent_(1000, 0, @timerProc(), 1, #TIME_PERIODIC)

quitTimer = ElapsedMilliseconds()
While ElapsedMilliseconds() - quitTimer < 10000 : Wend
KillTimer_(0, timer)

CreateTimerQueue example:

Code: Select all

Import "kernel32.lib"
  CreateTimerQueue()
  CreateTimerQueueTimer(hTimer, hTimerQueue, timerCallback,
                        param, dueTime, period, flags)
  DeleteTimerQueueEx(hTimerQueue, completionEvent)
EndImport

Procedure timerProc(param.i, timer.i)
  Debug FormatDate("%hh:%ii:%ss", Date())
EndProcedure

timerQueue = CreateTimerQueue()
CreateTimerQueueTimer(@timer, timerQueue, @timerProc(), 0, 0, 1000, 0)

quitTimer = ElapsedMilliseconds()
While ElapsedMilliseconds() - quitTimer < 10000 : Wend
DeleteTimerQueueEx(timerQueue, 0)
In response to your question, about the @thandle.i parameter in the CreateTimerQueueTimer() function; thandle is a variable (I just named it "timer" in my example) that will be assigned a unique handle to the timer that is being created. Since this function is capable of creating multiple timers, this handle would be required to delete it without deleting the entire queue. This is illustrated in this next example, where three different timer functions are running concurrently (SetTimer(), timeSetEvent(), CreateTimerQueueTimer()), each with two independent active timers, set at different intervals. They each display the current time, at one-second and five-second intervals respectively, and can be terminated individually by clicking on their corresponding buttons:

Code: Select all

Global timer_ST, timer_SE

Import "kernel32.lib"
  CreateTimerQueue()
  DeleteTimerQueueTimer(hTimerQueue, hTimer, completionEvent)
  DeleteTimerQueueEx(hTimerQueue, completionEvent)
  CreateTimerQueueTimer(hTimer, hTimerQueue, timerCallback,
                        param, dueTime, period, flags)
EndImport

Procedure timerProc_ST(hWnd.i, uMsg.i, idTimer.i, dwTime.i)
  If idTimer = timer_ST
    SetGadgetText(1, "SetTimer 1: " + FormatDate("%hh:%ii:%ss", Date()))
  Else
    SetGadgetText(2, "SetTimer 2: " + FormatDate("%hh:%ii:%ss", Date()))
  EndIf
EndProcedure    

Procedure timerProc_SE(hTimer.i, uMsg.i, idTimer.i, wParam.i, lParam.i)
  If hTimer = timer_SE
    SetGadgetText(3, "timerSetEvent 1: " + FormatDate("%hh:%ii:%ss", Date()))
  Else
    SetGadgetText(4, "timerSetEvent 2: " + FormatDate("%hh:%ii:%ss", Date()))
  EndIf
EndProcedure    

Procedure timerProc_Q(param.i, timer.i)
  SetGadgetText(5, "CreateTimerQueue 1: " + FormatDate("%hh:%ii:%ss", Date()))
EndProcedure

Procedure timerProc_Q2(param.i, timer.i)
  SetGadgetText(6, "CreateTimerQueue 2: " + FormatDate("%hh:%ii:%ss", Date()))
EndProcedure

wFlags = #PB_Window_ScreenCentered | #PB_Window_SystemMenu
OpenWindow(0, #PB_Any, #PB_Any, 600, 100, "Windows Timer Functions", wFlags)
TextGadget(1, 50, 20, 140, 30, "SetTimer 1: ")
TextGadget(2, 50, 50, 140, 30, "SetTimer 2: ")
TextGadget(3, 220, 20, 150, 30, "timerSetEvent 1: ")
TextGadget(4, 220, 50, 150, 30, "timerSetEvent 2: ")
TextGadget(5, 410, 20, 150, 30, "CreateTimerQueue 1: ")
TextGadget(6, 410, 50, 150, 30, "CreateTimerQueue 2: ")
ButtonGadget(7, 25, 15, 20, 20, "X")
ButtonGadget(8, 25, 47, 20, 20, "X")
ButtonGadget(9, 195, 15, 20, 20, "X")
ButtonGadget(10, 195, 47, 20, 20, "X")
ButtonGadget(11, 385, 15, 20, 20, "X")
ButtonGadget(12, 385, 47, 20, 20, "X")

timer_ST = SetTimer_(0, 0, 1000, @timerProc_ST())
timer_ST2 = SetTimer_(0, 0, 5000, @timerProc_ST())

timer_SE = timeSetEvent_(1000, 0, @timerProc_SE(), 1, #TIME_PERIODIC)
timer_SE2 = timeSetEvent_(5000, 0, @timerProc_SE(), 1, #TIME_PERIODIC)

timerQueue = CreateTimerQueue()
CreateTimerQueueTimer(@timer_Q, timerQueue, @timerProc_Q(), 0, 0, 1000, 0)
CreateTimerQueueTimer(@timer_Q2, timerQueue, @timerProc_Q2(), 0, 0, 5000, 0)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      appQuit = 1
    Case #PB_Event_Gadget
      Select EventGadget()
        Case 7
          KillTimer_(0, timer_ST)
          DisableGadget(7, 1)
        Case 8
          KillTimer_(0, timer_ST2)
          DisableGadget(8, 1)
        Case 9
          timeKillEvent_(timer_SE)
          DisableGadget(9, 1)
        Case 10
          timeKillEvent_(timer_SE2)
          DisableGadget(10, 1)
        Case 11
          ;deletes individual timer - queue still active
          DeleteTimerQueueTimer(timerQueue, timer_Q, 0)
          DisableGadget(11, 1)
        Case 12
          DeleteTimerQueueTimer(timerQueue, timer_Q2, 0)
          DisableGadget(12, 1)
      EndSelect
  EndSelect
Until appQuit = 1

;terminates any active timers
KillTimer_(0, timer_ST)
KillTimer_(0, timer_ST2)
timeKillEvent_(timer_SE)
timeKillEvent_(timer_SE2)
DeleteTimerQueueEx(timerQueue, 0)   ;deletes the entire queue
Hope it's helpful.
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
Joris
Addict
Addict
Posts: 890
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: CreateTimerQueue... how to use this API ?

Post by Joris »

TI-994A wrote:Hello Joris. Besides the fact that Microsoft has earmarked the timeSetEvent() function as obsolete, I personally find the two functions quite similar. They both have the same basic functionality, although they each have their own set of flags that determine threading, execution, response, etc. So, unless you have some very specific requirements on such behaviour, it shouldn't make much of a difference which one you use. Now, how to use it.
Hope it's helpful.
Nice example code TI-994A, thanks. A good one to experiment with too.

Indeed the two functions look quite similar, the more examples I see now the more it become's part of my questioning why this one is now recommended ?
Yet, one thing isn't clear, can this timer-resolution become changed, during running or is this also like with timeSetEvent() (first stop timer then change resolution and run again), I believe it is...
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
User avatar
TI-994A
Addict
Addict
Posts: 2741
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: CreateTimerQueue... how to use this API ?

Post by TI-994A »

Joris wrote:...why this one is now recommended?
...can this timer-resolution become changed, during running...
Hello again Joris. From what I gather, the CreateTimerQueue() function runs each created timer in a separate thread, whereas timeSetEvent() maintains them all in a single thread. And it also has the ability to modify the timer resolution mid-process, without having to stop and restart them; something which timeSetEvent() isn't able to do. Besides that, I suppose that there must be other reasons why they've scrapped the timeSetEvent() function.

I've modified the earlier example to include the ChangeTimerQueueTimer() function, which does this. Here, three timers are created, with corresponding slider gadgets that change their individual intervals on the fly, from one to ten seconds:

Code: Select all

Import "kernel32.lib"
  CreateTimerQueue()
  DeleteTimerQueueTimer(hTimerQueue, hTimer, completionEvent)
  DeleteTimerQueueEx(hTimerQueue, completionEvent)
  ChangeTimerQueueTimer (hTimerQueue, hTimer, dueTime, period)
  CreateTimerQueueTimer(hTimer, hTimerQueue, timerCallback,
                        param, dueTime, period, flags)
EndImport

Global timer_Q1, timer_Q2, timer_Q3

Procedure timerProc_Q(param.i, timer.i)
  SetGadgetText(param, "Timer " + Str(param) + ": " +
                FormatDate("%hh:%ii:%ss", Date()) +
                "   (" + Str(GetGadgetState(param + 3)) + 
                " second interval)")
EndProcedure

Procedure getTimer(gadgetEvent)
  Select gadgetEvent
    Case 4, 7
      ProcedureReturn timer_Q1
    Case 5, 8
      ProcedureReturn timer_Q2
    Case 6, 9
      ProcedureReturn timer_Q3
  EndSelect
EndProcedure

wFlags = #PB_Window_ScreenCentered | #PB_Window_SystemMenu
OpenWindow(0, #PB_Any, #PB_Any, 380, 120, "Windows Queue Timer", wFlags)
TextGadget(1, 50, 20, 200, 30, "Timer 1: ")
TextGadget(2, 50, 50, 200, 30, "Timer 2: ")
TextGadget(3, 50, 80, 200, 30, "Timer 3: ")

TrackBarGadget(4, 260, 15, 100, 20, 1, 10, #PB_TrackBar_Ticks)
TrackBarGadget(5, 260, 45, 100, 20, 1, 10, #PB_TrackBar_Ticks)
TrackBarGadget(6, 260, 75, 100, 20, 1, 10, #PB_TrackBar_Ticks)

ButtonGadget(7, 25, 15, 20, 20, "X")
ButtonGadget(8, 25, 47, 20, 20, "X")
ButtonGadget(9, 25, 79, 20, 20, "X")

timerQueue = CreateTimerQueue()
CreateTimerQueueTimer(@timer_Q1, timerQueue, @timerProc_Q(), 1, 0, 1000, 0)
CreateTimerQueueTimer(@timer_Q2, timerQueue, @timerProc_Q(), 2, 0, 1000, 0)
CreateTimerQueueTimer(@timer_Q3, timerQueue, @timerProc_Q(), 3, 0, 1000, 0)

Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      appQuit = 1
    Case #PB_Event_Gadget
      eGadget = EventGadget()
      Select eGadget
        Case 4, 5, 6
          newInterval = GetGadgetState(eGadget) * 1000
          ChangeTimerQueueTimer(timerQueue, getTimer(eGadget), 0, newInterval)
        Case 7, 8 ,9
          DeleteTimerQueueTimer(timerQueue, getTimer(eGadget), 0)
          DisableGadget(eGadget, 1)
          DisableGadget(eGadget - 3, 1)
      EndSelect
  EndSelect
Until appQuit = 1

DeleteTimerQueueEx(timerQueue, 0)
Notice that now, all three timers are being handled by a single callback procedure, and not separately as before. However, unlike timeSetEvent(), the callback for CreateTimerQueueTimer() does not receive the timer IDs as a parameter, which makes it difficult to identify which timer fired the call. To facilitate this, a user-definable parameter (the fourth argument in the function call, simply documented as "Parameter") is used to associate each timer with a user-assigned ID.

As always, hope it helps. :wink:
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
Joris
Addict
Addict
Posts: 890
Joined: Fri Oct 16, 2009 10:12 am
Location: BE

Re: CreateTimerQueue... how to use this API ?

Post by Joris »

I have to repeat myself (yeah timers.... :wink:) : Nice example code again TI-994A, thanks. Good one to experiment with too.

Until now I use the timeSetEvent() API's with the highest resolution (1 msec) and do some recalculations if realtime BPM changes are needed in my music prog. It's a quit complicated to do that because the timer may not be stopped to set another interval then. CreateTimerQueueTimer() however makes it possibly easier as BPM changes can be made within the timing itself by ChangeTimerQueueTimer()... maybe that makes things much less complicated (hopefully).

Great TI-994A.
Yeah I know, but keep in mind ... Leonardo da Vinci was also an autodidact.
Post Reply