If you’re a Windows developer and don’t know this then you need to learn it, now. Here’s why:
I’ve been examining some legacy code that has a Timer event with some lengthy code that contains DoEvents calls. A simplified version looks something like this:
Private Sub tmrProcess_Timer() 'Run some slow processing code here DoEvents 'More slow code here DoEvents 'Lots more slow code and the occasional DoEvents here If booComplete Then tmrProcess.Enabled = False End If End Sub
The timer has it’s Interval set to 250 and the slow code could take up to thirty or so seconds to complete.
Given that VB6 is single threaded and that timer messages are low priority the question is if it is at all possible for the Timer event to be re-entered during a DoEvents call or will the VB6 runtime block execution of a Timer event if the Timer event is currently executing?
The reference above contains some interesting clues as to the answer. In particular it states that WM_PAINT messages are combined into a single message but there is no mention of whether or not WM_TIMER messages are combined.
So the best way to find out is to write a test program:
Option Explicit Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Private Counter As Integer Private StopTimer As Boolean Private Sub cmdStart_Click() txtResults.Text = "Time: " & Format(Now, "HH:mm:ss") & " Start" Counter = 0 StopTimer = False tmrTest.Interval = 500 tmrTest.Enabled = True End Sub Private Sub cmdStop_Click() txtResults.Text = txtResults.Text & vbCrLf & "Time: " & Format(Now, "HH:mm:ss") & " Counter: " & Counter & " Stop" StopTimer = True End Sub Private Sub tmrTest_Timer() Static Index As Integer Index = Index + 1 Counter = Counter + 1 txtResults.Text = txtResults.Text & vbCrLf & "Time: " & Format(Now, "HH:mm:ss") & " Index: " & Index & " Counter: " & Counter DoEvents Sleep 1000 DoEvents Sleep 1000 DoEvents txtResults.Text = txtResults.Text & vbCrLf & "Time: " & Format(Now, "HH:mm:ss") & " Index: " & Index & " Counter: " & Counter If StopTimer = True Then tmrTest.Enabled = False txtResults.Text = txtResults.Text & vbCrLf & "Time: " & Format(Now, "HH:mm:ss") & " Stopped" End If End Sub
Here’s my test results:
Time: 15:54:38 Start
Time: 15:54:38 Index: 1 Counter: 1
Time: 15:54:40 Index: 1 Counter: 1
Time: 15:54:41 Index: 2 Counter: 2
Time: 15:54:43 Index: 2 Counter: 2
Time: 15:54:43 Index: 3 Counter: 3
Time: 15:54:44 Counter: 3 Stop
Time: 15:54:45 Index: 3 Counter: 3
Time: 15:54:45 Stopped
What I think is happening is that additional calls to the Timer event are being cancelled by the VB6 runtime Windows Procedure so that only one Timer event can run at once. Then when the Timer is cancelled any remaining WM_TIMER messages are either removed from the queue, ignored, or fail silently because the function they are calling is no longer valid.
Because the Windows Procedure is the core of a client program and are not required to be standardized it would be very interesting to compare how different programs, and especially different programming language runtimes, handle the same situation.