HOWTO: a replacement for Doevents which does not yield to keystrokes 
Author Message
 HOWTO: a replacement for Doevents which does not yield to keystrokes

There are often times when for various reasons you need to allow
pending messages in the queue to be processed but you would much
rather not have errant mouse or keyboard events occur at that time.

For example, you need to call Doevents sometimes to resolve paint
problems, or when loading an HTML document into the web browser
control, to allow messages to be processed before proceeding
(normally, you loop, calling doevents, until document.readystate goes
to "complete" - you can use the browser control events provided but
they are not reliable and if you want to synchronously load a document
the code is still going to have to spin somewhere).

Doevents is also often required after setting focus to a control.

But the problem is that doevents allows your code to be re-entered
with mouse and keyboard events that you may not be prepared to handle
at that time. This results in code that has static gate flags to
protect it from re-entrancy. An even more annoying problem is that the
keystrokes must then be discarded, so that typeahead is lost.

The code below provides a replacement for DoEvents that will not
remove any pending mouse or keyboard events from the message queue,
but which will pump any other messages to their destination. This
preserves typeahead while allowing your code to yield where needed.

Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA"
(lpMsg As MSG, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, ByVal
wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
Private Declare Function TranslateMessage Lib "user32" (lpMsg As MSG)
As Long
Private Declare Function DispatchMessage Lib "user32" Alias
"DispatchMessageA" (lpMsg As MSG) As Long

Private Const QS_POSTMESSAGE = &H8
Private Const PM_NOREMOVE = &H0
Private Const PM_REMOVE = &H1
Private Const QS_HOTKEY = &H80
Private Const QS_TIMER = &H10
Private Const QS_SENDMESSAGE = &H40
Private Const PM_NOYIELD = &H2
Private Const QS_MOUSEMOVE = &H2
Private Const QS_MOUSEBUTTON = &H4
Private Const QS_MOUSE = _
    (QS_MOUSEMOVE Or QS_MOUSEBUTTON)
Private Const QS_KEY = &H1
Private Const QS_INPUT = (QS_MOUSE Or QS_KEY)
Private Const QS_PAINT = &H20

Private Const PM_QS_INPUT = (QS_INPUT * (2 ^ 16))
Private Const PM_QS_PAINT = (QS_PAINT * (2 ^ 16))
Private Const PM_QS_POSTMESSAGE = _
    ((QS_POSTMESSAGE Or QS_HOTKEY _
    Or QS_TIMER) * (2 ^ 16))
Private Const PM_QS_SENDMESSAGE = _
    (QS_SENDMESSAGE * (2 ^ 16))

Private Type POINTAPI
        x As Long
        y As Long
End Type

Private Type MSG
    hwnd As Long
    message As Long
    wParam As Long
    lParam As Long
    time As Long
    pt As POINTAPI
End Type

Public Sub Yield()
Dim m As MSG
'process any posted messages on the stack - not keyboard or mouse
messages
While PeekMessage(m, 0, 0, 0, PM_REMOVE Or PM_QS_POSTMESSAGE Or
PM_QS_PAINT)
    TranslateMessage m
    DispatchMessage m
Wend
End Sub



Tue, 27 Sep 2005 01:01:53 GMT  
 HOWTO: a replacement for Doevents which does not yield to keystrokes
Andrew,

Interesting...

Here's a message pump that you can modify to suit your needs.
Can you post back here with your modified code? I think many
would be interested to see how you make out. :-)

Good luck.

Private Type POINTAPI
  x As Long
  y As Long
End Type

Private Type MSG
  hWnd As Long
  Message As Long
  wParam As Long
  lParam As Long
  time As Long
  pt As POINTAPI
End Type

Private Function MyDoEvents() As Boolean
'===========================================================================
' MyDoEvents - Message pump for our private window.
'===========================================================================

  Const WM_QUIT = &H12
  Const PM_REMOVE = &H1

  Dim theMsg As MSG

  If CBool(PeekMessage(theMsg, m_hWnd, 0&, 0&, PM_REMOVE)) Then

    If theMsg.Message = WM_QUIT Then
      Exit Function
    End If

    TranslateMessage theMsg
    DispatchMessage theMsg

  End If

  MyDoEvents = True

End Function

+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+
Monte Hansen - MVP VB
http://KillerVB.com
+|+|+|+|+|+|+|+|+|+|+|+|+|+|+|+


Quote:
> There are often times when for various reasons you need to allow
> pending messages in the queue to be processed but you would much
> rather not have errant mouse or keyboard events occur at that time.

> For example, you need to call Doevents sometimes to resolve paint
> problems, or when loading an HTML document into the web browser
> control, to allow messages to be processed before proceeding
> (normally, you loop, calling doevents, until document.readystate goes
> to "complete" - you can use the browser control events provided but
> they are not reliable and if you want to synchronously load a document
> the code is still going to have to spin somewhere).

> Doevents is also often required after setting focus to a control.

> But the problem is that doevents allows your code to be re-entered
> with mouse and keyboard events that you may not be prepared to handle
> at that time. This results in code that has static gate flags to
> protect it from re-entrancy. An even more annoying problem is that the
> keystrokes must then be discarded, so that typeahead is lost.

> The code below provides a replacement for DoEvents that will not
> remove any pending mouse or keyboard events from the message queue,
> but which will pump any other messages to their destination. This
> preserves typeahead while allowing your code to yield where needed.

> Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA"
> (lpMsg As MSG, ByVal hwnd As Long, ByVal wMsgFilterMin As Long, ByVal
> wMsgFilterMax As Long, ByVal wRemoveMsg As Long) As Long
> Private Declare Function TranslateMessage Lib "user32" (lpMsg As MSG)
> As Long
> Private Declare Function DispatchMessage Lib "user32" Alias
> "DispatchMessageA" (lpMsg As MSG) As Long

> Private Const QS_POSTMESSAGE = &H8
> Private Const PM_NOREMOVE = &H0
> Private Const PM_REMOVE = &H1
> Private Const QS_HOTKEY = &H80
> Private Const QS_TIMER = &H10
> Private Const QS_SENDMESSAGE = &H40
> Private Const PM_NOYIELD = &H2
> Private Const QS_MOUSEMOVE = &H2
> Private Const QS_MOUSEBUTTON = &H4
> Private Const QS_MOUSE = _
>     (QS_MOUSEMOVE Or QS_MOUSEBUTTON)
> Private Const QS_KEY = &H1
> Private Const QS_INPUT = (QS_MOUSE Or QS_KEY)
> Private Const QS_PAINT = &H20

> Private Const PM_QS_INPUT = (QS_INPUT * (2 ^ 16))
> Private Const PM_QS_PAINT = (QS_PAINT * (2 ^ 16))
> Private Const PM_QS_POSTMESSAGE = _
>     ((QS_POSTMESSAGE Or QS_HOTKEY _
>     Or QS_TIMER) * (2 ^ 16))
> Private Const PM_QS_SENDMESSAGE = _
>     (QS_SENDMESSAGE * (2 ^ 16))

> Private Type POINTAPI
>         x As Long
>         y As Long
> End Type

> Private Type MSG
>     hwnd As Long
>     message As Long
>     wParam As Long
>     lParam As Long
>     time As Long
>     pt As POINTAPI
> End Type

> Public Sub Yield()
> Dim m As MSG
> 'process any posted messages on the stack - not keyboard or mouse
> messages
> While PeekMessage(m, 0, 0, 0, PM_REMOVE Or PM_QS_POSTMESSAGE Or
> PM_QS_PAINT)
>     TranslateMessage m
>     DispatchMessage m
> Wend
> End Sub



Thu, 29 Sep 2005 02:24:11 GMT  
 HOWTO: a replacement for Doevents which does not yield to keystrokes
Quote:

> Andrew,

> Interesting...

> Here's a message pump that you can modify to suit your needs.
> Can you post back here with your modified code? I think many
> would be interested to see how you make out. :-)

[snip]

I did look at a window-specific pump, and your example is excellent
for that purpose - thanks for sharing it with us all. In my case I
deliberately created an application-level pump because I was trying to
handle embedded web browser windows in the context of a VB
application, and in this case I am processing all pending messages for
the application, rather than just a specific window.

I wish Microsoft had made DoEvents a bit more flexible so we didn't
have to go to these extremes, but that's VB for you..... sigh....



Sun, 02 Oct 2005 19:46:41 GMT  
 
 [ 3 post ] 

 Relevant Pages 

1. DoEvents not doing any events

2. Need help with commonon dialog not doing doevents

3. VB 5.0 BUG RaiseEvent Yields execution as DoEvents !!!!!!

4. Yield (DoEvents) in a .DLL

5. VB 5.0 BUG RaiseEvent Yields execution as DoEvents !!!!!!

6. API replacement for DoEvents

7. Howto? Refresh a progressbar without DoEvents

8. DoEvents when doing UpdateBatch

9. Howto? Refresh a progressbar without DoEvents

10. Howto? Refresh a progressbar without DoEvents

11. DAO in VB5 yields User-defined type not defined

12. CreateReportOnRuntimeDS from VB yields File Not Found in Win98 and XP

 

 
Powered by phpBB® Forum Software