VB6 Timer Object not working as expected

Posted on 2007-08-01
Last Modified: 2013-12-20
guaranteed to Stump the expert.

I am using the timer object in VB6.  Along with that I am using the GetTickCount api.  I call the GetTickCount at the beginning of the timer routine and display the returned value, we'll call it INTERVAL.  I call it again at the end of the routine and display the delta from the first call (the elapsed time of the routine called ELAPSED).  I set the timer interval so that it is larger than the elapsed time of the routine.  When I run this code the INTERVAL is always the sum of ELAPSED and the timer interval.  This implies that the timer object restarts itself after every execution of the timer routine.  I don't know exactly how the timer object works, but this result was HIGHLY unexpected.  What I expected was that as long as ELPASED was less than the timer interval then INTERVAL would be very close to the timer interval.  But that is not the case.  Can you explain this?  Is this a bug?  Or is this "By Design"?  
Question by:tkamrath
    LVL 12

    Expert Comment

    The DateDiff() function is more accurate in calculating ELAPSE times than the Timer object/function as it gets reset to 0 at 12:00 midnight.

    Here is a sample method to calculate the time elapsed between two time intervals:

    Dim StartTime
    Dim EndTime
    Dim Duration
    Dim ii As Long

    StartTime = Now()

    Do Until ii >= 1234567
       ii = ii + 1

    EndTime = Now()

    Duration = DateDiff("s", StartTime, EndTime)

    MsgBox "It took " & Duration & " seconds to finish the job."
    LVL 85

    Expert Comment

    by:Mike Tomlinson
    Can you show us your code please?....
    LVL 76

    Expert Comment

    Don't quite inderstand what you have found, but, yes, the Timer keeps on running, firing its timer event every time its interval is reached.
    LVL 38

    Expert Comment

    I also see the same behaviour you are describing.  It's as if the timer stops timing while executing the code in the timer event.

    It is an interesting discovery, and I think probably by design, although I can't find anything in any documentation anywhere.  It's probably to prevent the re-entrancy problems that would occur if the timer fired every 100 ms when the code takes 400 ms to execute.  Combined with a DoEvents statement in the timer event code, and you would have an event cascade, leading to a stack overflow.

    It seems to me that in the past VB versions (3, 4, or 5)  I have experienced re-entrancy problems with timers, but with this behaviour, I don't see how that's possible anymore.
    LVL 38

    Accepted Solution

    Here's the code I used if anyone wants to play with it.  Two buttons, a text box and a timer.  Compile for most consistent results.

    Option Explicit
    Private Declare Function GetTickCount Lib "kernel32.dll" () As Long
    Private Declare Sub Sleep Lib "kernel32.dll" (ByVal dwMilliseconds As Long)

    Private mInterval As Long

    Private Sub Command1_Click()
        Timer1.Interval = CLng(Text1.Text)
        Timer1.Enabled = True
    End Sub

    Private Sub Command2_Click()
        Timer1.Enabled = False
        mInterval = 0
    End Sub

    Private Sub Form_Load()
        Text1.Text = "250"
        Me.AutoRedraw = True
    End Sub

    Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
        Timer1.Enabled = False
    End Sub

    Private Sub Timer1_Timer()
        If Not Me.Enabled Then Exit Sub
        Dim lngElapsed As Long, lngIntervalOld As Long
        Dim i As Long, j As Long
        lngIntervalOld = mInterval
        mInterval = GetTickCount
        For i = 1 To 100000
        lngElapsed = GetTickCount - mInterval
        If lngIntervalOld > 0 And mInterval > 0 Then
            Me.Print mInterval - lngIntervalOld, lngElapsed
        End If
    End Sub
    LVL 76

    Expert Comment

    I think I now understand what behaviour you find surprising.

    That is that the Timer countdown does not proceed while the object's Timer event is still being processed. As far as I remember that has always been the case.

    Author Comment

    This is all good.  It means I am not imagining things.  SOMEONE ELSE SEES IT!!!

    But if most people don't know this, think of all the screwed up code out there.  If I have an app where I need execution every 100 msec and my routine takes 42 msec to execute, that is about a 50% error.  Most people probably write that off thinking the VB timer is just not that accurate.  BUT...

    If your timer interval is 1000 msec and you set the timer interval to TIMER1.Interval = 1000 - ELAPSEDTIME at the end of the timer routine then the timer is VERY accurate.  Now that I know I am not imagining it, that is how I will fix this.
    LVL 76

    Expert Comment

    I always restart the timer at the end of the Timer event. I even disable it first

    Sub Timer1_Timer()

      ' do the event processing

       Timer1.Enabled = False
       Timer1.Interval = 100
       Timer1.Enabled = True
    End Sub
    LVL 13

    Expert Comment


    so, what you did GrahamSkan, was what the timer internal was already doing :)

    Featured Post

    How to improve team productivity

    Quip adds documents, spreadsheets, and tasklists to your Slack experience
    - Elevate ideas to Quip docs
    - Share Quip docs in Slack
    - Get notified of changes to your docs
    - Available on iOS/Android/Desktop/Web
    - Online/Offline

    Join & Write a Comment

    When trying to find the cause of a problem in VBA or VB6 it's often valuable to know what procedures were executed prior to the error. You can use the Call Stack for that but it is often inadequate because it may show procedures you aren't intereste…
    Most everyone who has done any programming in VB6 knows that you can do something in code like Debug.Print MyVar and that when the program runs from the IDE, the value of MyVar will be displayed in the Immediate Window. Less well known is Debug.Asse…
    Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…
    Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

    754 members asked questions and received personalized solutions in the past 7 days.

    Join the community of 500,000 technology professionals and ask your questions.

    Join & Ask a Question

    Need Help in Real-Time?

    Connect with top rated Experts

    19 Experts available now in Live!

    Get 1:1 Help Now