Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
Home
Discussion GroupsVB SyntaxEnterprise DevelopmentDatabase AccessControlsCOMWin APICrystal ReportDeploymentGeneralGeneral 2
Related Topics
VB.NET / ASP.NETMS SQL ServerMS AccessOther Database ProductsMore Topics ...

VB Forum / Win API / September 2008



Tip: Looking for answers? Try searching our database.

PeekMessage and Filtered Nested Message Loops

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Jai Singh - 17 Sep 2008 19:43 GMT
I am a non-MFC programmer that primarily works in .NET as well as legacy VB 6.
In both of those high-level RAD language worlds, the platforms offer a
DoEvents() function.  It seems that DoEvents() is a non-filtered nested
message pump that is used to flush the message queue.  I have determined that
DoEvents is essentially "evil" in most programs because of subroutine
re-entrancy problems and the generation of unplanned for execution sequences
(this opinion was confirmed via web searches and opinions provided by
industry "leaders" as well as Microsoft Developers).  

.NET provides the IMessageFilter interface which allows a programmer to
create a filter on incoming messages before calling Application.DoEvents()...
however in legacy VB 6 there is no such functionality.

Problem:

In some instances, it appears that programmers do in fact need to retrieve
and dispatch a specific set of Windows Messages for a thread or hWnd at a
particular point in time in order to put a specific control in a particular
state.  DoEvents should not be used because it retrieves and dispatches all
messages irregardless of type or destination.

Solution:

In such an instance it seems that a programmer in a RAD language could
utilize the Win32 API and its PeekMessage(), TranslateMessage(),
DispatchMessage() functions to essentially create a filtered version of
DoEvents.

I was wondering if there are any potential pitfalls in using PeekMessage()
to create a nested message pump that only dispatches certain messages and
does not dispatch others?

Thanks in advance,
Jai
MikeD - 18 Sep 2008 01:23 GMT
>I am a non-MFC programmer that primarily works in .NET as well as legacy VB
>6.
[quoted text clipped - 33 lines]
> to create a nested message pump that only dispatches certain messages and
> does not dispatch others?

OK...FIRST...are you using VB6 (or under) or .NET? It's unclear because you
say you work with both (but primarily .NET). If .NET, you need to ask in a
newsgroup with "dotnet" or "vsnet" in the name. Regardless, it'd probably be
helpful if you stated exactly what your ultimate goal is. Depending on
whether you're using VB6 or .NET, the answer could be different (which is
why you need to clarify this and post in the appropriate newsgroup).

THIS newsgroup is for VB6 and under only.  We don't deal with .NET here.

As far as DoEvents in VB6, all it does it yield to Windows to give it (and
your app) time to process messages I personally have never encountered a
problem with DoEvents, except for calling it too often and slowing
performance because the app is yielding too much. Although, I am aware of
circumstances where DoEvents can be more detrimental.  VB6's Help documents
this.  It states:

"Any time you temporarily yield the processor within an event procedure,
make sure the procedure is not executed again from a different part of your
code before the first call returns; this could cause unpredictable results.
In addition, do not use DoEvents if other applications could possibly
interact with your procedure in unforeseen ways during the time you have
yielded control."

For the most part (there are other circumstances), in VB6 you most
frequently need to use DoEvents in a loop when you also need your program to
be responsive to user input (such as the user clicking a Cancel button to
exit the loop prematurely). Other times you might use DoEvents to allow
Windows time to redraw the screen or a portion of it (a low priority in
Windows) BEFORE you enter into a tight loop (but invoking a control's or
form's Refresh method is usually better than DoEvents in this case because
it's more specific to what you need accomplished).

Signature

Mike
Microsoft MVP Visual Basic

Jai Singh - 18 Sep 2008 11:58 GMT
I thought that I was being SPECIFIC, but perhaps not enough FOR YOU so let me
CLARIFY.

1st of all, I am concerned about DoEvents in Visual Basic 6.0 (your
newsgroup grouping structure simply uses "Visual Basic" and "Windows API").  
The pitfalls of DoEvents in VB 6 is a relatively worn topic:

http://blogs.msdn.com/tmiller/archive/2003/11/07/57524.aspx

http://blogs.msdn.com/jfoscoding/archive/2005/08/06/448560.aspx

http://discuss.fogcreek.com/joelonsoftware3/default.asp?cmd=show&ixPost=92327&ix
Replies=20


http://discuss.joelonsoftware.com/default.asp?dotnet.12.481760.7

http://www.codinghorror.com/blog/archives/000159.html

I have read the VB 6 documentation and its explanation of DoEvents.  The
warning to watch for re-entrancy problems is understated at best.  In
multi-component, multi-tier applications of any complexity it is nearly
impossible to avoid re-entrancy when a call to DoEvents is made inside of
some component (i.e. one team's right hand doesn't know what the left hand of
the other team is doing).

To my understanding DoEvents is essentially a wrapper for a Do loop that
utilizes PeekMessage(), TranslateMessage(), and DispatchMessage().  Many non
C programmers today are unaware of message pumps etc... but DoEvents is
essentially a nested message pump.

I mentioned .NET because it has the IMessageFilter interface which allows a
programmer to place a filter on the underlying message pump and even on the
nested message pump that Application.DoEvents() uses.  VB6 does not have this
feature so I wanted to determine the best way to implement similar
functionality in VB 6.

Again, DoEvents, if I understand it correctly, represents a non-filtered
nested message loop.  I want to created a filtered nested message loop which
enables me to retrieve and dispatch a set of messages by message type or
target (i.e. hwnd).
MY QUESTION TO YOU IS:  what are the potential pitfalls of creating such a
filtering system using PeekMessage?

HERE IS AN EXAMPLE:

Public Function Pump(ByVal bRenderUIs As Boolean, ByVal colWinHandles As
MTKList, ByVal colMessagesToDispatch As MTKList) As Boolean
On Error Resume Next
   
   Dim tMSG As MSG
   Dim lRet As Long
   Dim lNum1 As Long
   Dim lNum2 As Long
   Dim lVal1 As Long
   Dim lVal2 As Long

   'OBTAIN AND DISPATCH SPECIFIC MESSAGES FOR SPECIFIC WINDOWS
   If Not colWinHandles Is Nothing And Not colMessagesToDispatch Is Nothing
Then
       For lNum1 = 1 To colWinHandles.Count
           lVal1 = colWinHandles.Item(lNum1)
           If IsValidWinHandle(lVal1) = True Then
               For lNum2 = 1 To colMessagesToDispatch.Count
                   lVal2 = colMessagesToDispatch.Item(lNum2)
                   If IsValidMessage(lVal2) = True Then
                       lRet = PeekMessage(tMSG, lVal1, lVal2, lVal2,
PM_REMOVE)
                       If lRet = 0 Then
                           TranslateMessage tMSG
                           DispatchMessage tMSG                            
                       End If
                   End If
               Next lNum2
           End If
       Next lNum1
   End If
   
   If bRenderUIs = True Then
       PumpWMPaintForAllWindowHandles
   End If
   
   PumpMessagesForWindowHandles = True

End Function

"WHY WOULD I LIKE TO CREATE SUCH A FUNCTION?" (gee... I'm glad that you are
so courteous and helpful and asked...):

In some rare situations a developer may be working with a 3rd party control
(i.e. closed source, black box).  At a specific point in execution the
program may invoke a method (say .CellFocus(x,y)) on that control in order to
place the control in a specified state (lets say at line 100).  THE PROBLEM
is that at line 101 the control is not actually in that state even though,
according to the documentation, it should be.
Lines 102 to 105 of the program expect the control to be in that state.  The
programmer discovers that if he places DoEvents at line 102 that the control
then enters the proper state (presumably because a particular MESSAGE was
received by that control).  However, re-entrancy occurrs in some scenarios
because DoEvents was utilized and because the large program written by 15
developers over 8 years has places where re-entrancy is possible.  

EXAMPLE:

   wbBrowser.Navigate2 (msDisplayFileName)
       DoEvents

SOLUTION:

So, it seems like that it might be useful to create a version of DoEvents
that filters out certain Windows Messages and dispatches others (thus
avoiding re-entrancy via the pump).

AGAIN, TO CLARIFY, MY QUESTION:  

What are the potential pitfalls of creating a filtered nested message pump
in a VB6 application vai the PeekMessage() Win32 API function?

> >I am a non-MFC programmer that primarily works in .NET as well as legacy VB
> >6.
[quoted text clipped - 65 lines]
> form's Refresh method is usually better than DoEvents in this case because
> it's more specific to what you need accomplished).
Wolfgang Enzinger - 18 Sep 2008 13:04 GMT
>I thought that I was being SPECIFIC, but perhaps not enough FOR YOU so let me
>CLARIFY.
>
>1st of all, I am concerned about DoEvents in Visual Basic 6.0 (your
>newsgroup grouping structure simply uses "Visual Basic" and "Windows API").  

I think you misunderstand the concept of newsgroups. This isn't Mike's
newsgroup grouping structure. The structure was made by MS, and almost
everybody replying here does so on a volunteer basis.

>> For the most part (there are other circumstances), in VB6 you most
>> frequently need to use DoEvents in a loop when you also need your program to
[quoted text clipped - 4 lines]
>> form's Refresh method is usually better than DoEvents in this case because
>> it's more specific to what you need accomplished).

The Refresh method was my preferred approach in this situation,
however, it will work only for 20 seconds or so in WinXP or higher.
Then, without a DoEvents, the form won't be redrawn anymore until the
thread is idle again.

So a was looking for an alternative solution. DoEvents was not an
option, because I didn't feel like disabling every button and so on
only to avoid a second, reentrant routine call.

So - and this might answer Jai's question - I found this replacement,
and it works fine without any unwanted side effects in all of my
projects for a couple of years now:

FUNCTION AllowRefresh (BYVAL hWnd AS LONG) AS BOOLEAN
DIM mMSG AS tagMSG
 IF PeekMessage(mMSG, hWnd, WM_PAINT, WM_PAINT, PM_REMOVE) THEN
 TranslateMessage mMSG
 DispatchMessage mMSG
 FUNCTION = True
 END IF
END FUNCTION  

HTH,
Wolfgang
Jai Singh - 18 Sep 2008 15:33 GMT
Wolfgang,

Thanks for that confirmation.  That is exactly what I was doing in my
PumpWMPaintForAllWindowHandles() function related to the bRenderUIs flag.

Glad to know that it hasn't caused you any grief.

Jai

> >I thought that I was being SPECIFIC, but perhaps not enough FOR YOU so let me
> >CLARIFY.
[quoted text clipped - 39 lines]
> HTH,
> Wolfgang
Karl E. Peterson - 18 Sep 2008 21:04 GMT
> So - and this might answer Jai's question - I found this replacement,
> and it works fine without any unwanted side effects in all of my
[quoted text clipped - 8 lines]
>  END IF
> END FUNCTION

So what is that, PowerBasic?
Signature

.NET: It's About Trust!
http://vfred.mvps.org

Alfie [UK] - 18 Sep 2008 23:21 GMT
>> So - and this might answer Jai's question - I found this replacement,
>> and it works fine without any unwanted side effects in all of my
[quoted text clipped - 10 lines]
>
>So what is that, PowerBasic?

Well apart from the 'Function=True' which should be 'AllowRefresh=True'
it's a VB classic version of a C message pump for WM_Paint.
Signature

Alfie [UK]
<http://www.delphia.co.uk/>
God must love stupid people, he made so many of them.

Karl E. Peterson - 18 Sep 2008 23:46 GMT
>>> So - and this might answer Jai's question - I found this replacement,
>>> and it works fine without any unwanted side effects in all of my
[quoted text clipped - 13 lines]
> Well apart from the 'Function=True' which should be 'AllowRefresh=True'
> it's a VB classic version of a C message pump for WM_Paint.

Well, yeah, that and the fact it's never seen the inside of a VB IDE, eh?
Signature

.NET: It's About Trust!
http://vfred.mvps.org

Alfie [UK] - 19 Sep 2008 19:38 GMT
>Well, yeah, that and the fact it's never seen the inside of a VB IDE, eh?

Hmmm, I see Wolfgang confirmed, but I didn't even consider case when
checking if it was valid VB :)
Signature

Alfie [UK]
<http://www.delphia.co.uk/>
Ever stop to think and forget to start again?

Karl E. Peterson - 19 Sep 2008 19:46 GMT
>>Well, yeah, that and the fact it's never seen the inside of a VB IDE, eh?
>
> Hmmm, I see Wolfgang confirmed, but I didn't even consider case when
> checking if it was valid VB :)

I was just sorta joshing, but all those years of editting the VBPJ "hot tips"
special editions taught me to recognize code that's never ran in VB immediately.
Just amazing how many people write code in their news/email apps! <g>
Signature

.NET: It's About Trust!
http://vfred.mvps.org

Wolfgang Enzinger - 18 Sep 2008 23:32 GMT
>> So - and this might answer Jai's question - I found this replacement,
>> and it works fine without any unwanted side effects in all of my
[quoted text clipped - 10 lines]
>
>So what is that, PowerBasic?

Yep. ;-)

I copied that snipped from my PB source code and adapted everything
that's specific to PB ... well, almost everything. <g>

Actually all of my VB projects nowadays depend on a DLL written in PB,
mainly for two reasons:

* I don't wanna see Functions that have proofed to be stable over the
years explain themselves over and over again in the VB debugger whenever
I forget to press the shift key along with <F8>, which happens oftenly
...

and

* PB allows some stuff that VB doesn't, e.g. calling a function when you
only know the function address (retrieved by GetProcAddress()) and of
course the parameter list -> no need for hacks like CreateThread() as
mentioned in another thread.

Wolfgang
Karl E. Peterson - 18 Sep 2008 23:46 GMT
>>> So - and this might answer Jai's question - I found this replacement,
>>> and it works fine without any unwanted side effects in all of my
[quoted text clipped - 12 lines]
>
> Yep. ;-)

Check's in the mail, right, Bob?!  ;-)

> I copied that snipped from my PB source code and adapted everything
> that's specific to PB ... well, almost everything. <g>
[quoted text clipped - 13 lines]
> course the parameter list -> no need for hacks like CreateThread() as
> mentioned in another thread.

I'm pretty sure that's where I'll end up if/when ClassicVB stops doing the job for
me.  I'd gotten around that function pointer thing with some code of Curland's, but
your parameterless idea will work really nice for some other stuff.  Have you
started using that newest release yet?  It sounded like they'd gone a lot closer to
VB-style COM objects, but I've been too busy to really look at it too hard.
Signature

.NET: It's About Trust!
http://vfred.mvps.org

Wolfgang Enzinger - 19 Sep 2008 14:39 GMT
>I'm pretty sure that's where I'll end up if/when ClassicVB stops doing the job for
>me.  I'd gotten around that function pointer thing with some code of Curland's, but
>your parameterless idea will work really nice for some other stuff.  Have you
>started using that newest release yet?  It sounded like they'd gone a lot closer to
>VB-style COM objects, but I've been too busy to really look at it too hard.

I didn't look very deeply into it so far, too, but here are a few
impressions:

* As per documentation, the extended COM support looks really great!

* When I got my copy of PB9, the first thing I tried was to recompile
a few DLLs that I had written using PB8. I have to say that there are
some compatibility breaks. Some of them were confirmed by the support
team (e.g. all .INC files for COM components made with the COM browser
that came with PB8 have to be redone with the new COM browser, because
the old files contain lots of errors in the eye of the new compiler),
others seem to be bugs typical for a x.0 version (at least that's what
I infer from the fact that the support team doesn't really comment
them).

* Creating COM servers is not as easy as it looks at first glance. My
tests so far were a little frustrating, and when I finally had a COM
DLL done then it crashed the VB IDE. Maybe that's because I used VB5,
but there are several similar reports in the PB forum.

Currently I have no big hurry in using the new features, so probably
I'll wait for the first service release (9.1) before continuing.

Wolfgang
Karl E. Peterson - 19 Sep 2008 19:44 GMT
I think I'll take your final word ...

> Currently I have no big hurry in using the new features, so probably
> I'll wait for the first service release (9.1) before continuing.

... to heart.  Appreciate the heads-up.  Thanks!
Signature

.NET: It's About Trust!
http://vfred.mvps.org

>>I'm pretty sure that's where I'll end up if/when ClassicVB stops doing the job for
>>me.  I'd gotten around that function pointer thing with some code of Curland's,
[quoted text clipped - 28 lines]
>
> Wolfgang
DanS - 18 Sep 2008 23:41 GMT
> The Refresh method was my preferred approach in this situation,
> however, it will work only for 20 seconds or so in WinXP or higher.
[quoted text clipped - 4 lines]
> option, because I didn't feel like disabling every button and so on
> only to avoid a second, reentrant routine call.

Me.Enabled = False
DoEvents
Me.Enabled = True
Wolfgang Enzinger - 19 Sep 2008 14:39 GMT
>> So a was looking for an alternative solution. DoEvents was not an
>> option, because I didn't feel like disabling every button and so on
[quoted text clipped - 3 lines]
>DoEvents
>Me.Enabled = True

Yeah, but timer controls on this form, for instance, will continue to
fire events that will be handled during DoEvents ...

Wolfgang
Thorsten Albers - 18 Sep 2008 11:33 GMT
Jai Singh <JaiSingh@discussions.microsoft.com> schrieb im Beitrag
<4DCA67A9-57EE-47D3-B425-42BA0FF1B144@microsoft.com>...
> I have determined that
> DoEvents is essentially "evil" in most programs because of subroutine
> re-entrancy problems and the generation of unplanned for execution sequences
> (this opinion was confirmed via web searches and opinions provided by
> industry "leaders" as well as Microsoft Developers).  

No, DoEvents as such is in no way evil. It's use only leads to trouble if
the developer using it doesn't know how to use it correctly, and/or if his
code relies on a certain order in the firing of events - which the code
shouldn't do. If a procedure should not be executed under certain
conditions a) your code should store somewhere the current state on which
the execution depends, and b) your procedure should check the conditions
(which could be at least e.g. a simple static procedure flag 'I am already
running' to avoid re-entrance...).

Signature

----------------------------------------------------------------------
Thorsten Albers                               albers(a)uni-freiburg.de
----------------------------------------------------------------------

Jai Singh - 18 Sep 2008 12:26 GMT
Guten Tag.  Thank you for your reply.

> Jai Singh <JaiSingh@discussions.microsoft.com> schrieb im Beitrag
> <4DCA67A9-57EE-47D3-B425-42BA0FF1B144@microsoft.com>...
[quoted text clipped - 13 lines]
> (which could be at least e.g. a simple static procedure flag 'I am already
> running' to avoid re-entrance...).
expvb - 18 Sep 2008 15:49 GMT
> I was wondering if there are any potential pitfalls in using PeekMessage()
> to create a nested message pump that only dispatches certain messages and
> does not dispatch others?

I am aware of the C++ equivalent of DoEvents. One possible pitfall when you
process selected messages is that if these messages and their VB6 code
changes focus, VB6 maybe sending other messages to handle the focus change
and calling Validate event, I am not sure how VB6 handles this. Use Spy++ to
see what happens.

If you are only looking for a specific message that has VB6 code that
doesn't change the focus, then it should be safe to make your own custom
DoEvents.
Dean Earley - 18 Sep 2008 15:49 GMT
> I am a non-MFC programmer that primarily works in .NET as well as legacy VB 6.
> In both of those high-level RAD language worlds, the platforms offer a
> DoEvents() function.  It seems that DoEvents() is a non-filtered nested
> message pump that is used to flush the message queue.

Please don't multipost.
http://www.blakjak.demon.co.uk/mul_crss.htm

Signature

Dean Earley (dean.earley@icode.co.uk)
i-Catcher Development Team

iCode Systems

 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2009 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.