| Article ID: | T1090 |
| Date: | 10/31/02 (updated 4/10/03) |
| Products: | VB Guide |
| Subject: | MsgWait timer for VB and VC++ applications |
Sometimes you may want to delay for a specified time in you VB (or VC++) application or cause your application to sleep momentarily while waiting for some event to occur. The MsgWait sample code below is a subroutine that waits for a specified number of milliseconds. The MsgWait routine is based on the WinAPI MsgWaitForMultipleObjects. This allows your application to sleep until time has expired, and momentarily wake up to process events immediately.
First, we will compare three different loop
methods using VB.
The following Do..Loop causes your application to
"hog" the CPU. If you observe CPU Usage while this loop occurs, you will
see 100%. Events are processed immediately, but since the application is
using the CPU more, the process that is sending events does not get as much CPU
time, so event throughput is reduced.
Do
DoEvents
Loop Until
g_CycleComplete
This Do..Loop uses the WinAPI Sleep
function. This considerably reduces the CPU Usage, but events will not be
processed as quickly. In fact, no events will be processed during the
Sleep time. 10 ms is the smallest interval that can be
used.
Do
Sleep 10
DoEvents
Loop Until g_CycleComplete
By using MsgWait, your application will not cause the CPU Usage to be 100%. If an event occurs, it will be processed immediately. This is more efficient for processing events, since your application will sleep until one or more events occur, process the events, then sleep again.
Do
MsgWait 10
Loop
Until g_CycleComplete
Also, VB does not have a delay timer, so MsgWait can be used for this
purpose.
For example:
ExecuteMyFunc1
MsgWait 1000
ExecuteMyFunc2
The table below shows a comparison between the different loop methods. The test was performed by running a SPEL+ task that executes SPELCom_Event in a loop with no delays. As you can see, the MsgWait method allows the greatest event throughput with low CPU usage.
| Loop method | Approximate events per second | CPU Usage |
| Do DoEvents Loop Until g_CycleComplete |
560 | High |
| Do Sleep 10 DoEvents Loop Until g_CycleComplete |
100 | Low |
| Do MsgWait 10 Loop Until g_CycleComplete |
640 | Low |
MsgWait for Visual Basic
Here is the MsgWait sample code for use with VB. To use in your VB application, create a new code module and paste this sample code in the new module.
Option Explicit
Private Const QS_KEY = &H1
Private Const QS_MOUSEMOVE = &H2
Private Const QS_MOUSEBUTTON = &H4
Private Const QS_POSTMESSAGE =
&H8
Private Const QS_TIMER = &H10
Private Const QS_PAINT =
&H20
Private Const QS_SENDMESSAGE = &H40
Private Const
QS_HOTKEY = &H80
Private Const QS_MOUSE = (QS_MOUSEMOVE Or
QS_MOUSEBUTTON)
Private Const QS_INPUT = (QS_MOUSE Or QS_KEY)
Private
Const QS_ALLEVENTS = (QS_INPUT Or QS_POSTMESSAGE Or QS_TIMER Or QS_PAINT Or
QS_HOTKEY)
Private Const QS_ALLINPUT = (QS_SENDMESSAGE Or QS_PAINT Or
QS_TIMER Or QS_POSTMESSAGE Or QS_MOUSEBUTTON Or QS_MOUSEMOVE Or QS_HOTKEY Or
QS_KEY)
Private Declare Function GetTickCount Lib "kernel32" () As
Long
Private Declare Function MsgWaitForMultipleObjects Lib "user32" (ByVal
nCount As Long, pHandles As Long, ByVal fWaitAll As Long, ByVal dwMilliseconds
As Long, ByVal dwWakeMask As Long) As Long
'
*********************************************************
' * MsgWait
'
*
' * Sleeps for a specified time but allows
' * events to process
immediately
' *
' * Input: ms - milliseconds to wait
' * Output:
none
' *
' * Notes: Resolution in NT 3.5 and above is 10 ms
' *
Copyright (c) 2002, Epson America, Inc. FAR Division
'
*********************************************************
Sub MsgWait(ByVal
ms As Long)
Dim start As Long, timeRemaining As Long, timeNow
As Long
start = GetTickCount()
timeRemaining =
ms
Do
' Sleep until timeout or event
occurs
MsgWaitForMultipleObjects 0, 0, 0, timeRemaining,
QS_ALLINPUT
timeNow = GetTickCount()
If timeNow - start >= timeRemaining Then
Exit Sub
ElseIf timeNow
< start Then
' Handle GetTickCount 49.7
day wrap around
start = timeNow
End If
timeRemaining = timeRemaining
- (timeNow - start)
start = timeNow
DoEvents
Loop
End Sub
MsgWait for Visual C++
Here is the MsgWait sample code for use with VC++. A DoEvents function is also shown that processes Windows messages. If messages are not processed, no events will be received.
void DoEvents();
void MsgWait(long
ms);
'
*********************************************************
' * DoEvents
' *
' * Processes all Windows messages in the message queue
' * for the
current thread
' *
' * Input: none
' * Output: none
'
*
' * Notes: Resolution in NT 3.5 and above is 10 ms
' * Copyright (c)
2003, Epson America, Inc. FAR Division
'
*********************************************************
void DoEvents()
{
MSG msg;
long sts;
do {
if (sts = PeekMessage(&msg, (HWND)
NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
} while
(sts);
}
'
*********************************************************
' * MsgWait
'
*
' * Sleeps for a specified time but allows
' * events to process
immediately
' *
' * Input: ms - milliseconds to wait
' * Output:
none
' *
' * Notes: Resolution in NT 3.5 and above is 10 ms
' *
Copyright (c) 2003, Epson America, Inc. FAR Division
'
*********************************************************
void MsgWait(long ms)
{
long start, timeRemaining,
timeNow;
start = GetTickCount();
timeRemaining =
ms;
do {
// Sleep until timeout or event
occurs
MsgWaitForMultipleObjects(0, 0, 0, timeRemaining,
QS_ALLINPUT);
timeNow = GetTickCount();
if (timeNow - start >= timeRemaining)
return;
else if (timeNow
< start)
// Handle GetTickCount 49.7 day
wrap around
start = timeNow;
timeRemaining = timeRemaining - (timeNow - start);
start = timeNow;
DoEvents();
} while(1);
}
