Ok, create an ActiveX exe project (mine's called clsTimer). Set the instancing to SingleUse. Add a module (I call it vbTimerClassSupportFunctions), and drop in the following code:
[tt]
' This whole support module exists merely to get around the fact that we cannot use AddressOf
' in a class module. Additionally we'll need to make our class SingleUse to ensure that each vbTimer get's it's own
' timerproc
Option Explicit
Public CurrentTimer As vbTimer
' Use this to get around one of the limitations of AddressOf
Public Function ReturnAddress(lpAddress As Long) As Long
ReturnAddress = lpAddress
End Function
' This is the timer callback function
Public Sub TimerProc(ByVal hwnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, _
ByVal dwTime As Long)
Call CurrentTimer.RaiseIt(hwnd, uMsg, idEvent, dwTime)
End Sub
Public Function TimerProcAddress(myTimer As vbTimer) As Long
Set CurrentTimer = myTimer
TimerProcAddress = ReturnAddress(AddressOf TimerProc)
End Function
[/tt]
Now, if you don't already have one add a class module (I call mine vbTimer), and drop in the following code:
[tt]
Option Explicit
Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
Private mvarEnabled As Boolean
Private mvarInterval As Long
Private mvarTimerID As Long
Public Event Timer()
Public Property Let Interval(ByVal vdata As Long)
mvarInterval = vdata
End Property
Public Property Get Interval() As Long
Interval = mvarInterval
End Property
Public Property Let Enabled(ByVal vdata As Boolean)
mvarEnabled = vdata
ToggleTimer
End Property
Public Property Get Enabled() As Boolean
Enabled = mvarEnabled
End Property
Friend Sub RaiseIt(ByVal hwnd As Long, ByVal uMsg As Long, ByVal idEvent As Long, ByVal dwTime As Long)
If idEvent = mvarTimerID Then
RaiseEvent Timer
End If
End Sub
Private Sub Class_Terminate()
If mvarTimerID Then
KillTimer 0, mvarTimerID
End If
End Sub
' Should timer be activated?
Private Sub ToggleTimer()
If mvarEnabled = True And mvarInterval > 0 Then
mvarTimerID = SetTimer(0, 0, mvarInterval, TimerProcAddress(Me))
ElseIf mvarTimerID Then
KillTimer 0, mvarTimerID
mvarTimerID = 0
End If
End Sub
[/tt]
You can only use the compiled version of this in other projects, as the VB IDE does not actually support single instancing.
In use, because we are using an event, the vbTimer object will need to be hosted in a proxy class module (or a form module - but we want to avoid forms...). Here's an example. Create a new, formless project, with Sub Main as the startup. Add a reference to clsTimer. Add a Class module (I call mine TimerProxy[), and drop in the following code, which demonstrates two timers:
[tt]
Option Explicit
Public WithEvents myTimer1 As vbTimer
Public WithEvents myTimer2 As vbTimer
Private Sub myTimer1_Timer()
Debug.Print "Timer1 Event"
End Sub
Private Sub myTimer2_Timer()
Debug.Print "Timer2 Event"
End Sub
[/tt]
Finally drop the following the code module:
[tt]
Option Explicit
Private Sub main()
Dim lp As Long
Dim starttime As Date
Dim endtime As Date
Dim mytimers As TimerProxy
Set mytimers = New TimerProxy
Set mytimers.myTimer1 = New vbTimer
Set mytimers.myTimer2 = New vbTimer
mytimers.myTimer1.Interval = 1000
mytimers.myTimer1.Enabled = True
mytimers.myTimer2.Interval = 2000
mytimers.myTimer2.Enabled = True
starttime = Now
endtime = DateAdd("s", 60, Now)
Do Until Now = endtime
DoEvents
Loop
End Sub