DoEvents evolution; the API approach. (Method for 100% optimized loops) |
| | | | Submitted on: 12/13/2001 6:43:25 AM
By: <b>John Galanopoulos</b>
Level: Intermediate User Rating:
By 49 Users Compatibility:VB 4.0 (32-bit), VB 5.0, VB 6.0, VB Script, ASP (Active Server Pages) , VBA MS Access, VBA MS Excel
Users have accessed this article 17029 times. | (About the author) |
| | Do you want to make your loops 100% faster? Here's how :
Many of us have used several times DoEvents, to supply a bit of air to our App, on Heavy-Duty times such as loops for updates or inserts on recordsets etc. As we most know, DoEvents processes Windows messages currently in the message queue. But what if we wanted to execute DoEvents only in times, when we want to allow user (Keyboard and Mouse) input? ( A special "thank you" to all of you who rated this article)
This article has accompanying files | |
|
Terms of Agreement:
By using this article, you agree to the following terms...
1) You may use
this article in your own programs (and may compile it into a program and distribute it in compiled format for languages that allow it) freely and with no charge.
2) You MAY NOT redistribute this article (for example to a web site) without written permission from the original author. Failure to do so is a violation of copyright laws.
3) You may link to this article from another website, but ONLY if it is not wrapped in a frame.
4) You will abide by any additional copyright restrictions which the author may have placed in the article or article's description. |
New Page 1
DoEvents
evolution; the API approach
If there was such a function to
inspect the message queue for user input, we would have a main benefit:
We would speed up our loops ‘cause we would process all the messages in
the queue (with DoEvents) only on user input. It’s faster to check for
a message than to process all messages every time.
API provides us with such a
function:
It’s called
GetInputState and you can locate it in user32 library.
Here is the declaration:
Public Declare Function GetInputState Lib
"user32" () As Long
The GetInputState function
determines whether there are mouse-button or keyboard messages in the calling
thread's message queue.
If the queue contains one or more new mouse-button or
keyboard messages, the return value is nonzero else if there are no new
mouse-button or keyboard messages in the queue, the return value is zero.
So we can create an improved DoEvents with a Subroutine
like this :
Public Sub newDoEvents()
If GetInputState() <> 0 then DoEvents
End Sub
You
can use GetInputState() with many variations for example :
uCancelMode = False
Do until rs.Eof
Rs.AddNew
(..your source here)
Rs.Update
Rs.MoveNext
If GetInputState() <> 0 then
DoEvents
If uCancelMode Then Exit Do
End If
Loop
Msgbox “Finished.”
…or
we could use it in a ScreenSaver e.t.c.
Let’s
go a little further now and see what exactly is behind GetInputState().
It
is another API function located in User32 as well; GetQueueStatus()
The GetQueueStatus function indicates the type of messages
found in the calling thread's message queue. Here are the flags that
GetQueueStatus uses :
QS_ALLEVENTS An
input, WM_TIMER, WM_PAINT, WM_HOTKEY, or posted message is in the queue.
QS_ALLINPUT
Any
message is in the queue.
QS_ALLPOSTMESSAGE
A posted message (other than those listed here) is in the queue.
QS_HOTKEY
A
WM_HOTKEY message is in the queue.
QS_INPUT
An input message is in the queue.
QS_KEY
A WM_KEYUP, WM_KEYDOWN, WM_SYSKEYUP, or WM_SYSKEYDOWN
message is in the queue.
QS_MOUSE
A WM_MOUSEMOVE message or mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN,
and so on).
QS_MOUSEBUTTON
A mouse-button message (WM_LBUTTONUP, WM_RBUTTONDOWN, and so on).
QS_MOUSEMOVE
A WM_MOUSEMOVE message is in the queue.
QS_PAINT
A WM_PAINT message is in the queue.
QS_POSTMESSAGE
A posted message (other than those listed here)
is in the queue.
QS_SENDMESSAGE
A message sent by another thread or application
is in the queue.
QS_TIMER
A WM_TIMER message is in the queue.
(I believe that GetInputState() is a GetQueueStatus(QS_HOTKEY Or QS_KEY Or
QS_MOUSEBUTTON))
With these constants you can create your own
GetInputState function that fits your needs. For example you can create a custom
function that issues DoEvents when it’ll detects not only a Keyboard or Mouse
Key input, but also a WM_PAINT signal.
Why’s that? ‘cause in your loop you might need
to update the screen so you must let your custom function process the specific
signal.
Look at this :
Public Const QS_HOTKEY = &H80;
Public Const QS_KEY = &H1;
Public Const QS_MOUSEBUTTON = &H4;
Public Const QS_MOUSEMOVE = &H2;
Public Const QS_PAINT = &H20;
Public Const QS_POSTMESSAGE = &H8;
Public Const QS_SENDMESSAGE = &H40;
Public Const QS_TIMER = &H10;
Public 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)
Public Const QS_MOUSE = (QS_MOUSEMOVE
Or QS_MOUSEBUTTON)
Public Const QS_INPUT = (QS_MOUSE Or
QS_KEY)
Public Const QS_ALLEVENTS = (QS_INPUT
Or QS_POSTMESSAGE Or QS_TIMER Or
QS_PAINT Or QS_HOTKEY)
Public Declare Function GetQueueStatus
Lib "user32" (ByVal qsFlags As Long) As Long
Public Function cGetInputState()
Dim
qsRet As Long
qsRet = GetQueueStatus(QS_HOTKEY Or
QS_KEY Or QS_MOUSEBUTTON Or QS_PAINT)
cGetInputState = qsRet
End Function
With this function you can trigger the DoEvents to
be executed only when the message queue contains Key input, Mouse button or a
WM_PAINT signal.
Call it like this….
. . if cGetInputState() <> 0
then DoEvents
This was
tested and proved to optimise a loop by
100% !!!!!!!!!
I wrote this article believing that the API is a
powerfull part on Windows programming and deserves your attention. I was stuck
several times and API prooved to be a problem solver. API is a large world but
with little effort, you can take advantage of it. You will create more
sophisticated and user aware programs.
I hope I helped.
Any comments or suggestions are always welcomed.
John
Galanopoulos
(Below there is a link to the .doc version of this article, for you to download. If you want to implement this source in your projects, download the Class Module posted by John Baughman in this address Also, you can check out Olav Jordan's article : Optimized loop (no more doevents)
| |
Download article
Note: Due to the size or complexity of this submission, the author has submitted it as a .zip file to shorten your download time. Afterdownloading it, you will need a program like Winzipto decompress it.
Virus note:All files are scanned once-a-day by Planet Source Code for viruses,but new viruses come out every day, so no prevention program can catch 100% of them.
FOR YOUR OWN SAFETY, PLEASE: 1)Re-scan downloaded files using your personal virus checker before using it. 2)NEVER, EVER run compiled files (.exe's, .ocx's, .dll's etc.)--only run source code. 3)Scan the source code with Minnow's Project Scanner
If you don't have a virus scanner, you can get one at many places on the net including:McAfee.com
|
Terms of Agreement:
By using this article, you agree to the following terms...
1) You may use
this article in your own programs (and may compile it into a program and distribute it in compiled format for languages that allow it) freely and with no charge.
2) You MAY NOT redistribute this article (for example to a web site) without written permission from the original author. Failure to do so is a violation of copyright laws.
3) You may link to this article from another website, but ONLY if it is not wrapped in a frame.
4) You will abide by any additional copyright restrictions which the author may have placed in the article or article's description. |
Other 8 submission(s) by this author
|
|
|
Report Bad Submission |
|
|
Your Vote! |
See Voting Log |
|
Other User Comments |
12/13/2001 8:05:46 AM:Ken Hi John...I would be interested in a
*.doc version. So if you would send it
to me I'd appreciate it. Thanx
|
12/13/2001 9:07:34 AM:Lefteris Eleftheriades Thanx 4 the code. Exactly what I
needed.
Καλό
ε;
|
12/13/2001 9:17:41 AM:John Galanopoulos Thnx Lefteri ;)
|
12/13/2001 9:24:05 AM:Ken Thanks for the code John ;)
|
12/13/2001 9:28:11 AM:John Galanopoulos Anytime Ken :)
|
12/13/2001 10:08:07 AM:Shawn Finally - a tutorial worth reading. 5
from me.
|
12/13/2001 10:16:40 AM:John Galanopoulos Thnx pal. I hope i helped you with this.
|
12/13/2001 10:20:50 AM:David L I would like this in doc format also!
|
12/13/2001 12:16:38 PM:Jon Thanks for the information. I too
would be grateful for this in a doc
format.
Jon.
|
12/13/2001 12:33:02 PM:NYxZ Nice tutorial, could you send me the
.doc version too? :)
A 5* from me..
|
12/13/2001 12:42:26 PM:John Galanopoulos Thnx guys, the mail should now hit your
e-door :)
|
12/13/2001 1:35:37 PM:John Galanopoulos Thnx again all. Due to your requests i
uploaded the article for your
convinience. Its in .doc format.
|
12/13/2001 1:44:53 PM:John Great code!
I was working on some that
needed several Doevents.
|
12/13/2001 2:25:07 PM:Pete Why don't you zip up and upload the doc
to this tutorial?
If not ... please
send me the doc file.
Thanks
|
12/13/2001 2:45:39 PM:John Priestley Excellent piece of code...
You've got
my vote.
|
12/13/2001 2:57:15 PM:John Galanopoulos Thnx John. :)
|
12/14/2001 9:03:25 AM:Jean-Philippe Leconte The only thing that sùcks with this
method is the fact that it still uses
DoEvents... I agree that the other
method is to implement a message loop,
and this is not acceptable in vb. The
problem is that if you check for paint
msgs, and the user types 500 keys, and
then a paint event happens, when you'll
call Doevents, it will still process
500 keys before the paint event. It
still make code run faster so it's
still a nice code.
The other good
method is to Create a separate thread,
but this also makes VB's IDE crash if
the thread is not stopped when stopping
application.
|
12/14/2001 12:06:02 PM:kotaro I added this to our Access '97 library.
Testing showed this was 100 to 800
times faster than DoEvents, depending
on the load of other Apps on the PC
(The more apps running, the greater the
relative speed increase between
NewDoEvents and DoEvents). I REALLY
need to buy a book on API ;)
|
12/14/2001 12:11:40 PM:John Galanopoulos Thnx Kotaro for your submittion. The
part that satisfied me is that i
offered some help to you and so many
others. You are right my friend. It
does optimize the whole process. I am
preparing now a second part of this
article of a custom tailed DoEvents
command.
|
12/14/2001 5:26:35 PM:Xico These are those litle things that help
the newbies (... and the others).
Congratulations. 5 globes.
|
12/16/2001 12:38:11 PM:John Galanopoulos Thnx for your comment pal. I was really
confused and this tip saved me. Why not
you and all the others as well. Thnx
again (for voting as well :))
|
12/16/2001 7:50:43 PM:LCensoni Hey you guys, you can have big help on
API at
www.vbapi.com.
I suggest you
check it!
It's very very very good!
|
12/17/2001 4:26:57 AM:Berry Al An excellent article deserves a 5. Good
work pal.
|
12/17/2001 8:58:14 AM:LCensoni Hey man, I program in C++ too and its
very useful!
5 globes!
|
12/17/2001 11:18:22 AM:John Galanopoulos Thnx goes to my close friend Berry
:)
Thnx LCenconi for your vote pal..
it's quite a support for my first
attempt to write something that helps
others besides myself :)
|
12/22/2001 4:11:23 AM:Saifudheen A A I have been very much annoyed of speed
lose while using DoEvents in a large
For Next loops (some of my codes in
graphics uses it)
while same codes
shows very faster performance in C or
C++ VB shows slower.
This is a good
idea. 5 from me.
|
12/22/2001 3:22:36 PM:John Galanopoulos Thnx pal... I thought it would help..
it did for me. :)
|
1/9/2002 2:53:40 PM:John Galanopoulos I have just finished the second part of
this article. The source is in beta
testing phase. If this article
optimized the whole loop process, wait
to see my next one :-))))
|
2/1/2002 6:51:27 PM:Adam hard to follow in this form
|
2/3/2002 10:11:23 PM:Visualcode What is the point of this? I used
gettickcount and i got no time
difference?
|
2/4/2002 5:08:00 PM:John Galanopoulos Adam : I have uploaded the whole
tutorial in doc format. it's easier to
follow.
VisualCode : If u read the
tutorial you will understand. You
shouldn't just copy paste source...
|
2/6/2002 2:44:06 PM:Mad If GetInputState Then DoEvents
ist
quiet faster.
Mad
|
2/8/2002 12:44:50 PM:John Galanopoulos Mad : If cGetInputState Then DoEvents
is rocking
|
3/9/2002 11:34:41 AM:Arif Munandar Excellent Code. 5 globe from me
But it
can make 150% faster by little mod in
cGetInputState like this
Public
Function cGetInputState()
cGetInputState =
GetQueueStatus(QS_ALLINPUT)
End
Function
Please try!
|
3/26/2002 6:08:26 PM:Daniel Pramel nice code - i tried myself to do the
same, but i only used: "if
GetInputState <> 0 then DoEvents"....
nice to see how it works better :-))
Thanks
|
3/26/2002 6:24:11 PM:John Galanopoulos Thnx guys for your support.
|
3/28/2002 4:25:49 PM:Coding Genius I think you can get rid of the doevents
statement altogether by using
GetMessage() and DispatchMessage() API
calls. If you want an example then
E-Mail me, because you also need a new
type.
|
3/28/2002 4:31:17 PM:John Galanopoulos I have already built such a function.
Thnx anyway
|
3/29/2002 5:17:00 AM:Vasilis Ioannidis Cool coding, Yianni ;)
I'll use it in
one prog I'm developing now which seeks
for speed. 5 from me also!
|
3/29/2002 5:30:40 AM:John Galanopoulos Thxn Basili for your support in my
work. I hope i helped!
|
3/29/2002 5:48:40 AM:Merlin Great tutorial!
I think I will use
this stuff in my app. It contains a
loop that takes about 15 to 20 minutes
to calculate a lot of data. With this I
might give it a bit of speed (not the
drug ;-)).
Thanks for sharing! 5 G's
from me!
|
3/29/2002 6:03:57 AM:John Galanopoulos Hi Merlin and thnx for your support
|
3/29/2002 12:50:22 PM:BoBocK Excelent! 5 globes from me... and thanx
this will help allot...
|
3/29/2002 1:03:51 PM:Simon Woollard Nifty useful piece of code. 5 from me
(I would give 6 but they won't allow
me...)
|
3/29/2002 1:05:43 PM:Simon Nifty and very useful piece of code.
Thanks a lot. I'd give 6 but they will
only allow me 5....
Cheers.
|
3/29/2002 7:16:27 PM:B Great article John. I'm in an industry
focused on custom data crunching, so
this little tidbit is probably going to
wind up saving me hours of machine
time. Cant thank you enough for the
tip. Five stars!
|
3/31/2002 6:00:47 PM:John Galanopoulos Thank you all very much for your
support in this article.
|
4/1/2002 9:38:09 AM:Zeek79 Clean code, beddy beddy nice!
|
6/16/2002 12:47:25 AM:Sebastian Very usefull stuff, thank you very much
|
6/25/2002 4:54:17 PM:George Papadopoulos - VirusFree cool code thnx :)
|
8/12/2002 8:12:03 PM:John Galanopoulos Thank you all guys :)
|
10/7/2002 7:21:10 AM: Really Great Approach
|
11/14/2002 11:09:41 PM:Rob Loach Another thing that sux about this
function is that it doesn't check
joystick input (just keyboard and
mouse). But good tutorial.
|
11/15/2002 2:29:13 PM: Great, always wanted to know how to
interupt a loop! Thanks.
|
12/17/2002 12:10:42 PM: PLEASE HELP !
I executed the
API-Command
if GetQueueStatus(QS_KEY
or QS_MOUSEBUTTON)<>0 then DoEvents
in
a loop...
This method works excellent
in Win98,NT4,W2K - in Win-XP the
program hangs up ...
Have I done
something wrong?
Thanks for any
answers...
|
12/17/2002 1:12:17 PM:John Galanopoulos In Windows XP you need to implement
another message, WM_TIMER, cause
windows XP submit a SendMessageTimeout
constantly in the process list to
determine whether a process is hung up
or not. In this example we don't clear
WM_TIMER messages so Windows popup a
screen that says that "This application
is hung up". Hope this solves your
problem. Thanks for noticing.
|
12/17/2002 2:25:53 PM: This was an excellent tip!
It works in
Win-XP !
I am very impressed of your
fast response and you knowledges in
XP.
Thank you very much - This tip
helped me a lot.
P.S.
Do you have
another tip as good as that for calling
the Printer-Settings and switch the
orientation. In XP my module using the
winspool.drv - Api's
Public Declare
Function PrinterProperties Lib
"winspool.drv" (ByVal hwnd As Long,
ByVal hPrinter As Long) As Long
Public
Declare Function ClosePrinter Lib
"winspool.drv" (ByVal hPrinter As Long)
As Long
Public Declare Function
OpenPrinter Lib "winspool.drv" Alias
"OpenPrinterA" (ByVal pPrinterName As
String, phPrinter As Long, pDefault As
Any) As Long
Shows a dialog that I
can't edit in W2K and XP. Within 98 and
NT it works!
Again thanks...
|
12/17/2002 3:39:41 PM:John Galanopoulos Yeap :) it seems you are ignoring
pDefault member in OpenPrinter API
function.. Although Win9x seem to
ignore this, Windows 2000/XP need to
declare some things there... pDefault
is a PRINTER_DEFAULTS structure which
specifies three things : the default
data type, environment, initialization
data, and access rights for a printer.
You cannot ignore this member.. it's
like wanting to shutdown Windows..sure
in Windows 9x everybody can shutdown
them but in Windows 2000/XP you must
modify your access token to shutdown
them... same goes here.. Windows waits
for this structure to be filled with
the DEVMODE and the DesiredAccess you
want to have on the printer..
|
12/17/2002 3:51:54 PM:John Galanopoulos i made something quick.. maybe this
will solve your problems :
Private
Type PRINTER_DEFAULTS
pDatatype As
String
pDevMode As Long
DesiredAccess As Long
End
Type
Private Const
PRINTER_ALL_ACCESS = &HF000C
Private
Declare Function PrinterProperties Lib
"winspool.drv" (ByVal hwnd As Long,
ByVal hPrinter As Long) As
Long
Private Declare Function
ClosePrinter Lib "winspool.drv" (ByVal
hPrinter As Long) As Long
Private
Declare Function OpenPrinter Lib
"winspool.drv" Alias "OpenPrinterA"
(ByVal pPrinterName As String,
phPrinter As Long, pDefault As
PRINTER_DEFAULTS) As Long
Public
Sub test(shwnd As Long)
Dim
retVal As Long
Dim hPrinter As
Long
Dim pd As PRINTER_DEFAULTS
pd.DesiredAccess =
PRINTER_ALL_ACCESS
ret =
OpenPrinter(Printer.DeviceName,
hPrinter, pd)
ret =
PrinterProperties(shwnd, hPrinter)
ret = ClosePrinter(hPrinter)
End
Sub
|
12/17/2002 3:53:24 PM:John Galanopoulos paste this on a module, put the test
sub under a command button and on
runtime, click on it.. tell me if you
can change printer orientation
|
12/17/2002 3:56:01 PM:John Galanopoulos button should have this source :
Private Sub Command1_Click()
test
Me.hwnd
End Sub
|
12/18/2002 8:35:11 AM: Thank you for checking this.
The only
difference to my code was the
declaration of PRINTER_ALL_ACCESS.
The
changes do not work in W2K and
XP...<br>
I tested nearly all
Printer-Examples in this Site - but
found nothing that is working...<br>
I
only want to let the user switch the
printer orientation within a
WIN-Dialog. The Print-Out dialog is in
principle no problem...
|
12/18/2002 8:41:33 AM: I had to optimize the WM_TIMER
parameter (by testing a variable mod
VALUE = 0) in case of my loop did this
Timerevent each time running through it
- so that it was the same as if I put
the Standard - DoEvent() instead...
|
12/18/2002 9:52:35 AM:John Galanopoulos i checked the printer source i pasted
you, in my Windows XP PC and it worked
perfectly. i rechecked it in my 2000.
It also worked. also in order for the
timer to be implemented, you must use
this function Public Function
cGetInputState()
Dim qsRet As Long
qsRet = GetQueueStatus(QS_HOTKEY Or
QS_KEY Or QS_MOUSEBUTTON Or QS_PAINT Or
QS_TIMER)
cGetInputState = qsRet
End Function
|
12/18/2002 10:24:30 AM: What could be wrong? I always get the
dialog with disabled fields...
Could
it be that XP/W2K can lock these rights
although I am Admin?
|
12/18/2002 10:37:00 AM: Sorry it's me again.
Please try
this:
If cGetInputState() <> 0 Then
Beep
DoEvents
End If
The
systems beeping all the time...
|
12/18/2002 12:57:22 PM: Solved my Printerproblems without
winspool.drv...
Very good
API-Description for ShowPrint()
see:
http://www.planet-source-code.co
m/vb/scripts/showcode.asp?txtCodeId=9260
&lngWId=1
Thank you so much for
helping...
|
|
Add Your Feedback! |
Note:Not only will your feedback be posted, but an email will be sent to the code's author in your name.
NOTICE: The author of this article has been kind enough to share it with you. If you have a criticism, please state it politely or it will be deleted.
For feedback not related to this particular article, please click here. |
|