Difference between revisions of "Why DoEvents is Evil"

From HashVB
Jump to: navigation, search
 
Line 1: Line 1:
It is common in programming to need to have a timer of some form that will freeze your routine for a specified amount of time.  One way to do this is to use the Sleep() API.  Unfortunately there is a downside to this method, and that is that it will freeze your process. Not only does this mean that your APP's GUI updates will not occur until AFTER Sleep() returns, but also that your app will appear frozen to task manager.
+
Alot of code out there relies on the DoEvents statement, or even advertises the use of it.
 +
DoEvents can be useful in some cases, both in general it should not be used !
  
So what's the solution?  Why, create your own Sleep() function of course!
+
A call to DoEvents blocks until all the WM_MESSAGES in the message queue are processed,
 +
WM_MESSAGES are used by Windows (all versions of it) to notify an application of an "event".
 +
(Mouse or keyboard activity, timers, etc...)
  
  Private Declare Function GetTickCount& Lib "kernel32" ()
+
While the DoEvents statement is blocking the normal execution flow of the application, the GUI remains responsive however, this means that another block of code can be entered that also has a DoEvents statement in it, or even that the same block of code can be entered again.
   Private Declare Sub APISleep Alias "Sleep" Lib "kernel32.dll" (ByVal dwMilliseconds As Long)
+
 
 +
There are now two DoEvents calls blocking, if another DoEvents statement is encountered it will block again... this can cause stack overflow easily.
 +
 
 +
The following code demonstrates this behavior...
 +
 
 +
   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 +
 
 +
        For n As Integer = 1 To 10000
 +
            Button1.Text = n.ToString
 +
            Application.DoEvents()
 +
        Next
  
  Private Sub Sleep(ByVal dwMilliseconds As Long)
 
      Dim initTickCount As Long
 
     
 
      initTickCount = GetTickCount
 
      Do Until GetTickCount - initTickCount >= dwMilliseconds
 
          APISleep 10
 
          'Use the API call for sleep to prevent 100% cpu usage
 
          DoEvents
 
      Loop
 
 
   End Sub
 
   End Sub
  
This will freeze the routine from which it was called for the specified time, but leave the process free to update the GUI.
+
When you click that button, the loop will be entered, and its progress shown on the button itself.
 +
The UI is responsive, meaning you can click that same button again, the first loop will now be paused on the DoEvents statement, until the second loop terminates.
 +
Click it again to start a thirth loop, and so on...
 +
 
 +
Next to risking stack overflow exceptions, it is almost impossible to predict the flow of your application, making debugging very painful.

Revision as of 21:29, 13 October 2005

Alot of code out there relies on the DoEvents statement, or even advertises the use of it. DoEvents can be useful in some cases, both in general it should not be used !

A call to DoEvents blocks until all the WM_MESSAGES in the message queue are processed, WM_MESSAGES are used by Windows (all versions of it) to notify an application of an "event". (Mouse or keyboard activity, timers, etc...)

While the DoEvents statement is blocking the normal execution flow of the application, the GUI remains responsive however, this means that another block of code can be entered that also has a DoEvents statement in it, or even that the same block of code can be entered again.

There are now two DoEvents calls blocking, if another DoEvents statement is encountered it will block again... this can cause stack overflow easily.

The following code demonstrates this behavior...

 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
       For n As Integer = 1 To 10000
           Button1.Text = n.ToString
           Application.DoEvents()
       Next
 End Sub

When you click that button, the loop will be entered, and its progress shown on the button itself. The UI is responsive, meaning you can click that same button again, the first loop will now be paused on the DoEvents statement, until the second loop terminates. Click it again to start a thirth loop, and so on...

Next to risking stack overflow exceptions, it is almost impossible to predict the flow of your application, making debugging very painful.