Using DoEvents() in Visual Basic and .NET the Right way!

Click Star to Rate Post
1 Star2 Stars3 Stars4 Stars5 Stars (4 votes, average: 4.75 out of 5)
 

The DoEvents() method is well known and available in VB 6.0 and VB.NET. Its often used in longer running, processor intensive code. It tells Windows to process the messages in the program’s message queue. That can help keep your program from appearing frozen and allows user interaction while the CPU is still busy executing the high usage code.

(In VB 6.0 and Older DoEvents() is a Function | In .NET and Newer its a Subroutine)

Unfortunately there is a tradeoff when using DoEvents. That tradeoff is ‘Performance’. The more you call DoEvents, the more CPU cycles are taken away from your intensive code to process the message queue. Thankfully, there is a way to help offset much of the performance loss and still allow your program to be responsive. That’s by using the GetInputState() function in the User32.dll library.

[Note:

Most of the code in this article is from an example I made at www.vbcodesource.com.

It runs 3 different scenarios with benchmark data for each of them.

Scenario One: is executing a CPU intensive loop Without using DoEvents().

Scenario Two: is executing the loop using DoEvents() with the GetInputState() API call.

Scenario Three: is executing the loop using Only the DoEvents() method.

End Note]

Windows API to the Rescue

What’s nice about the GetInputState() function is you can use it to First Check if there are any messages in the calling thread’s queue that is waiting to be processed. Below is the declare for that function…

Visual Basic 6.0
'
'This call will see whether or not there are any messages waiting
'to be executed in the calling thread.

    Private Declare Function GetInputState Lib "user32" () As Long

Visual Basic.NET
'
'This call will see whether or not there are any messages waiting
'to be executed in the calling thread.
    Private Declare Function GetInputState Lib "user32" () As Int32

—————————————————

This function is very simple to use. Just simply get its return value to see if any mouse and/or keyboard messages needs processed…

'
'You save ALOT of time by using the GetInputState api call to check
'whether any messages needs to be processed first. The DoEvents()
'method is ONLY fired when there ARE messages that needs to be processed,
'thus really increasing the performance of your application.

'If it returns 0, then there are NO keyboard or mouse messages queued in the thread.

  If Not GetInputState = 0 Then Application.DoEvents()

—————————

Performance Results

In the Example I was talking about earlier I made a simple cpu intensive Loop and benchmarked each of the three scenerio’s.

  NO Doevents – 0.011106160…. Seconds.

  Doevents WITH GetInputState – 0.397925155…. Seconds.

  Doevents ONLY – 8.273245901…. Seconds.

As you can see there are definitely performance/speed differences between each scenario. Of course No DoEvents() will be the highest performing scenerio but at the cost of freezing your application until the code has finished executing. But compare DoEvents() With GetInputState to DoEvents Only. Those are very noticeable differences in performance between the two methods. Simply checking the queue first by using GetInputState() increased performance MANY Times in that test. And as you already know by doing so you will Stop your application from freezing which will allow the user to interact with your application even when your running heavy cpu intensive code.

Anyways that’s all, I hope you got something of use from this tip. Take care… 🙂

 

Jason

12 thoughts on “Using DoEvents() in Visual Basic and .NET the Right way!

  1. Garrison

    Great bit of code, helped make my app stable. One thing I noticed though was changing int32 to int64 helped me a whole lot more. My application checked stress on a CPU by finding prime numbers and sorting gathered data to give me a stress factor. When I changed int32 to int64, my application became super stable and never crashed. Also, it allowed the data to be displayed in real time on my form. I used VB.Net framework for this program and this peice of code completed it. Kudos to ya Jason! You are in the credits ;D

    Reply
  2. Jason Post author

    Thanks alot for the comment. I’m glad your getting your app to work the way you want it. It actually looks to be kinda interesting. Take care 🙂

    Jason

    Reply
  3. yulius

    Simple sample code, but right on target, tq for your article and explanation, it helps me a lot about doevents, so i can implement it on my app.

    tq bro. JBU

    Reply
  4. asdfg

    where to put this code:
    If Not GetInputState = 0 Then Application.DoEvents()
    on button?or on form load?

    and where is “application.DoEvents()” in VB6?

    Reply
  5. Jason Post author

    If using VB 6.0 then replace application.doevents with just DoEvents. Like below..

    If Not GetInputState = 0 then DoEvents

    You will want to put that code somewhere inside your resource intensive codes to allow your users to still communicate with your application without your application freezing.

    Jason

    Reply
  6. Vicky Mehta

    Hi Jason,

    I am having one case and need your advice whether to use DoEvents() / Any Other / Nothing to use.

    I have developed an application in VB 6.0 before 5-6 Years and is working fine.

    Now From some time as Data is increased (MS Access), It gives some unexpected result.

    I am using DbName.Execute “…Query to Update Tables…” and then after this line I had Used DoEvents(), to let DbName.Execute Query to be completed first and then go ahead with the rest of the code.

    So Is it the right use of DoEvents(), as I had monitored that in some Advanced CPU, the problems occurs due to non executing the Query / Query is Running Still the rest of the code is executed

    I actually want to Stop executing further code, once the Query Executed Completely, Then I want to execute further code

    Please Guide !

    Reply
  7. Jason Post author

    Hi Vicky, the main reason to use Doevents is to get Windows to process what-ever messages have been queued up by your program.

    For instance, your populating a listbox with lots of data continuously, but the listbox will not show any of its contents until the operation is done. Thus calling Doevents will get windows to process the _Paint message which will then show the results being added to the listbox.

    About your specific problem, you didn’t mention what your un-predictable results were. If loading the database contents is really that intense, executing the code in a thread seperate from the main thread would be ideal. Unfortunately, you can’t directly use the CreateThread api without your program crashing. There are workarounds though if your interested. Just let me know.

    Jason

    Reply
  8. Lou

    Will it work with a Timer in VB2005?

    I tried to use in a tight loop checking for a bit input from a digital interface device with a Timer control generating an interval event. Seems as though the timer event is not queued so my app is locking up during the loop time. Any ideas?

    Reply
  9. Jason Post author

    Hi Lou, i’m not 100% understanding your problem. But from what I believe your saying, try running a 1ms sleep call in your loop. Doevents is useful if you want user-interface parts of your program to still be useable and not freeze while running an intensive operation. It will kill performance since the message queue is checked each time you call DoEvents.

    I’m not sure how speed critical your loop is, but calling Threading.Thread.Sleep(1) will cause a very quick 1ms delay which may help. Its at least worth giving it a try. 🙂

    Jason

    Reply
  10. John

    I am writing a program in VB 6.0 that allows a user to view a series of screens of information. Since the information on each screen varies, I need to pause the program until the user is finished. I have been able to do this by using a timer and a ‘tight-loop’ containing a DoEvents call. 6The timer ensures that after a specified amount of time, the program “automatically” goes to the next screen of information. When all of the information has been displayed, the program “automatically” stops doing the display and returns to where it was when the user chose to see the data. However, I would like to have TWO buttons for the user: One button (which I have now) to update the screen info when the user clicks it; the OTHER button would IMMEDIATELY stop the data display (just as if all of the data had been displayed). The second button would be a sort of “exit button” so the user could quickly end the display.

    I am having trouble adding the second button. Here is the pseudo-code of what I have tried:

    Private m_blnContinueToProcessData
    Private m_blnContinueLooping
    Private m_intTimerCount

    Sub ProcessTheData()
    m_blnContinue1ToProcessData = True
    Do While And m_blnContinueToProcessData
    DisplayTheData()
    Pause()
    CheckForMoreData()
    Loop
    End Sub

    Sub Pause()
    m_intTimerCount = 0
    m_ blnContinueLooping = True
    tmrTimer.Enabled = True
    Do While blnContinueLooping
    DoEvents ‘catches the ‘click’ OF BUTTON-1 and terminates the loop
    Loop
    End Sub

    Sub BUTTON-1_Click()
    blnContinueLooping = False
    tmrTimer.Enabled = False
    End Sub

    Sub tmrViewTimer_Timer()
    intTimerCount = intTimerCount 1
    If intTimerCount = TIMER_COUNT_MAX Then
    tmrTimer.Enabled = False
    blnContinueLooping = False
    End If
    End Sub

    BUTTON-2 is supposed to set m_blnContinue to False to end the loop in the ProcessData subroutine.

    Whenever I try to use both buttons, one or the other doesn’t work!

    ANY help you can give me would be MUCH appreciated.

    John Jaros

    Reply
    1. Jason Post author

      Hi, if you do end up seeing this message; it would be better if you could send the full project to my temporary email account that is listed below. If you decide to zip it up and send it to me, MAKE sure you explain the exact problems you are having in the email message.

      Edit: email removed

      If you do decide to contact my me, leave a comment here, to help me remember to check the rarely used email account I listed above. Thanks 🙂

      Jason

      Reply

Leave a Reply