[python-win32] DispatchWithEvents design question

Richard Bell rbell01824 at earthlink.net
Sun Jun 10 15:41:35 CEST 2007


My apologies if this has already been sent but I did not receive a post
acknowledgement.

|Tim,
|
|Thanks again.  Your assistance has been extremely helpful.
|
|I've modified the test routine to illustrate the substance of our exchange
|and am posting it by way of giving something back to the group and in the
|off chance that it may prove useful to others.
|
|BTW, I'm still a bit concerned about the Python COM related crash on
|trailing events but will leave it to others more skilled than me to decide
|what if anything should be done.
|
|By way of explanation for others the output, included below after the code,
|illustrates the following:
|
|At 2.185 when the main sets ie.Visible = 1, the OnVisible event code runs
|BEFORE control returns to the main routine at 2.272 and absent a
|PumpWaitingMessages.  Clearly setting this IE property will cause the On-
|event code to run and some events are synchronous with main's interaction
|with COM.
|
|At 2.272 when the main sets ie.StatusBar = 0, both the OnCommandStateChange
|and OnStatus bar on event routines run BEFORE control returns to the main
|routine at 2.275 and absent a PumpWaitingMessages.  While later
|OnCommandStateChange events must be pumped, there are some conditions when
|a given On-event routine WILL EXECUTE absent a pump but later WILL REQUIRE
|a pump.
|
|At 2.324 when the main initiates a navigation both the OnCommandStateChange
|and OnBeforeNavigate2 event routines run BEFORE control returns to the main
|at 2.400 and absent a PumpWaitingMessages.  Clearly event routines can and
|do run when some (but not necessarily all) COM object properties are
|changed or methods executed.
|
|At 2.401 when the main spins in Python for 30 seconds WITHOUT pumping NO
|On-event code is run.  In an apartment-threaded model absent a bug in the
|object's COM interface event code should never be executed unless COM
|properties are changed or methods executed.
|
|At 32.413 when the main does 'one pump' the OnCommandStateChange event
|coded is executed 3 times BEFORE control returns to the main at 32.419.
|Clearly events can and do occur while the main is off doing whatever and
|the COM object is off doing its own whatever.  These events will queue and
|subsequent pumping or other interactions (not illustrated but true) that
|cause the pythoncom message queue to be processed will cause the associated
|On-event routines to execute.
|
|FWIW, if the test is run again the number and of events here will vary
|since the processes (the test and IE) are entirely separate.
|
|At 32.419 when the main spins for 10 seconds NO On-event routines are
|executed.  This verifies and supports the NO EVENTS UNLESS PROPERTIES OR
|METHODS rule.
|
|At 42.429 when the main does another pump there are no pending events.
|FWIW, in other runs of this test occasionally there will be another event
|or two reflecting the flow of the separate test and IE processes.
|
|At 47.460 when the main starts pumping messages for 30 seconds events start
|to occur and the IE window begins to display.  The IE window does NOT paint
|before then even though some 40+ seconds have elapsed.  Clearly IE is
|'hung' waiting disposition of some events.  It should be noted that in the
|case of IE some events, for example NewWindow2, expect a return value so
|that IE can be expected to (and as far as I know does) wait for the event
|to be processed before proceeding.  While it is not clear what event this
|particular Navigate2 is waiting on, it is clearly waiting since subsequent
|to starting to pump messages the page displays in roughly another 17
|seconds.  Clearly, in a DispatchWithEvents world when events are caught
|they MUST be pumped to allow the correspondent process (IE) to proceed.
|Absent pumping the correspondent can 'hang' waiting for the event to be
|processed.
|
|At 97.461 subsequent pumping yields NO events.  This page is now stable.
|It should be noted that this particular stable behavior is a function of
|this particular page and NOT a general characteristic of IE or COM.
|
|It is entirely possible for HTML pages to go off and do whatever whenever
|and cause events.  For instance, on this page in particular the right hand
|frame paints and a topmost window document complete event occurs (not
|illustrated in this example, but an indication that all the bytes from the
|original navigation request are now received) before all events have
|occurred and the page is completely rendered.  On this page, when IE begins
|to process the page after the topmost window document complete event occurs
|there is a bit of script attached to the pages OnLoad event that runs to
|build the left hand frame.  This script goes back to the web to get the
|left frame contents and generates a stream of events that occur after the
|initial navigation is (in some sense) complete.  This illustrates that a
|page CAN go off and generate events without interaction from the main
|automation routine.  While on this page the script is triggered by the
|pages OnLoad event, it is entirely possible that on page script will wait
|around a bit or be attached to some other page feature and then start to do
|things that generate events.  A slight modification of this test that stops
|pumping after the topmost window document complete event will leave the
|left frame NOT displayed until messages are once again pumped.
|
|
|
|--- Begin Code ---
|import win32com.client
|import pythoncom
|import time
|
|class events():
|    def OnVisible(self, vis):
|        self.eventMsg( 'OnVisible is %s'%(vis))
|    def OnBeforeNavigate2(self,pDisp,url,flags,
|                          targetFrameName,postData,
|                          headers,cancel):
|        self.eventMsg( "OnBeforeNavigate2 on url [%s] on frame [%s]"%
|              (url, targetFrameName))
|    def OnCommandStateChange(self,
|                             Command,
|                             Enable):
|        self.eventMsg( 'OnCommandStateChange: %s %s'%(Command,Enable))
|    def OnProgressChange(self, nProgress, nProgressMax):
|        msg = 'OnProgressChange progress %d max %d' % (
|            nProgress, nProgressMax)
|        self.eventMsg( msg )
|    def OnStatusBar(self,
|                      status):
|        self.eventMsg('OnStatusBar')
|    def eventMsg( self, msg ):
|        print 'At %6.3f Event tag [%s] %s'%(time.clock(), tag, msg)
|
|tag = 'No tag'
|def mainMsg( t, msg = ''):
|    global tag
|    tag = t
|    print 'At %6.3f Main  tag [%s] %s'%(time.clock(), t, msg)
|    return
|
|def spin( t, msg ):
|    mainMsg( 'Spin for %s seconds, no pump'%t, msg)
|    t0 = time.clock()
|    while time.clock()-t0 < t: pass
|
|def spinPump( t, msg ):
|    mainMsg( 'Pump %s seconds'%t, msg)
|    t0 = time.clock()
|    while time.clock()-t0 < t: pythoncom.PumpWaitingMessages()
|
|time.clock()        # just get clock running
|mainMsg( 'Begin test' )
|mainMsg( 'win32com.client.DispatchWithEvents' )
|ie = win32com.client.DispatchWithEvents(
|    'InternetExplorer.Application',
|    events)
|# NO PUMP MESSAGE
|mainMsg( 'Set ie.Visible', 'On-event routines run')
|ie.Visible = 1
|mainMsg( 'Set ie.StatusBar false', 'On-event routines run' )
|ie.StatusBar = 0
|mainMsg( 'Set ie.StatusBar true', 'On-event routines run' )
|ie.StatusBar = 1
|mainMsg( 'Navigate to ... aa752574.aspx',
|         'OnBeforeNavigate2 event routine runs' )
|url = 'http://msdn2.microsoft.com/en-us/library/aa752574.aspx'
|ie.Navigate(url)
|mainMsg( 'Back from Navigate', 'The page should NOT be displayed')
|spin(30, 'The page should not display and there should be no events' )
|mainMsg( 'One pump',
|         'The page should still NOT be displayed, ' + \
|         'but we should see a few messages and ' + \
|         'IE is hung waiting for events to be processed' )
|pythoncom.PumpWaitingMessages()
|spin( 10, 'The page should still NOT be displayed, ' + \
|      'there should be no events and '
|      'IE is hung waiting for events to be processed' )
|mainMsg( 'Another pump',
|         'The page should still NOT be displayed, ' + \
|         'but we may see a few more messages and ' + \
|         'IE is still hung waiting for events to be processed' )
|pythoncom.PumpWaitingMessages()
|spin( 5, 'The page should still NOT be displayed, ' + \
|      'there should be no events and '
|      'IE is hung waiting for events to be processed' )
|spinPump( 30, 'The page should NOW start displaying')
|spinPump( 20, 'The page should be stable and there should be no trailing
|events' )
|mainMsg( 'End test' )
|--- End Code ---
|
|--- Begin Output ---
|At  0.000 Main  tag [Begin test]
|At  0.000 Main  tag [win32com.client.DispatchWithEvents]
|At  2.185 Main  tag [Set ie.Visible] On-event routines run
|At  2.189 Event tag [Set ie.Visible] OnCommandStateChange: 2 False
|At  2.272 Event tag [Set ie.Visible] OnVisible is True
|At  2.272 Main  tag [Set ie.StatusBar false] On-event routines run
|At  2.275 Event tag [Set ie.StatusBar false] OnCommandStateChange: 1 False
|At  2.275 Event tag [Set ie.StatusBar false] OnStatusBar
|At  2.275 Main  tag [Set ie.StatusBar true] On-event routines run
|At  2.321 Event tag [Set ie.StatusBar true] OnStatusBar
|At  2.324 Main  tag [Navigate to ... aa752574.aspx] OnBeforeNavigate2 event
|routine runs
|At  2.328 Event tag [Navigate to ... aa752574.aspx] OnCommandStateChange: 2
|False
|At  2.353 Event tag [Navigate to ... aa752574.aspx] OnBeforeNavigate2 on
|url [http://msdn2.microsoft.com/en-us/library/aa752574.aspx] on frame []
|At  2.400 Main  tag [Back from Navigate] The page should NOT be displayed
|At  2.401 Main  tag [Spin for 30 seconds, no pump] The page should not
|display and there should be no events
|At 32.413 Main  tag [One pump] The page should still NOT be displayed, but
|we should see a few messages and IE is hung waiting for events to be
|processed
|At 32.413 Event tag [One pump] OnCommandStateChange: 1 False
|At 32.416 Event tag [One pump] OnCommandStateChange: 2 False
|At 32.417 Event tag [One pump] OnCommandStateChange: 1 False
|At 32.419 Main  tag [Spin for 10 seconds, no pump] The page should still
|NOT be displayed, there should be no events and IE is hung waiting for
|events to be processed
|At 42.429 Main  tag [Another pump] The page should still NOT be displayed,
|but we may see a few more messages and IE is still hung waiting for events
|to be processed
|At 42.429 Main  tag [Spin for 5 seconds, no pump] The page should still NOT
|be displayed, there should be no events and IE is hung waiting for events
|to be processed
|At 47.460 Main  tag [Pump 30 seconds] The page should NOW start displaying
|At 47.461 Event tag [Pump 30 seconds] OnProgressChange progress 100 max
|10000
|At 47.484 Event tag [Pump 30 seconds] OnProgressChange progress 100 max
|10000
|At 47.655 Event tag [Pump 30 seconds] OnProgressChange progress 150 max
|10000
|At 47.657 Event tag [Pump 30 seconds] OnProgressChange progress 200 max
|10000
|At 47.660 Event tag [Pump 30 seconds] OnProgressChange progress 250 max
|10000
|At 47.661 Event tag [Pump 30 seconds] OnProgressChange progress 300 max
|10000
|At 47.666 Event tag [Pump 30 seconds] OnProgressChange progress 350 max
|10000
|At 47.667 Event tag [Pump 30 seconds] OnProgressChange progress 400 max
|10000
|At 47.667 Event tag [Pump 30 seconds] OnProgressChange progress 450 max
|10000
|At 47.668 Event tag [Pump 30 seconds] OnProgressChange progress 500 max
|10000
|At 47.669 Event tag [Pump 30 seconds] OnProgressChange progress 550 max
|10000
|At 47.671 Event tag [Pump 30 seconds] OnProgressChange progress 600 max
|10000
|At 47.700 Event tag [Pump 30 seconds] OnProgressChange progress 666800 max
|1000000
|At 48.256 Event tag [Pump 30 seconds] OnCommandStateChange: -1 False
|At 48.447 Event tag [Pump 30 seconds] OnCommandStateChange: 2 False
|At 48.448 Event tag [Pump 30 seconds] OnCommandStateChange: 1 False
|At 48.497 Event tag [Pump 30 seconds] OnCommandStateChange: -1 False
|At 48.654 Event tag [Pump 30 seconds] OnProgressChange progress 1060000 max
|1000000
|At 54.270 Event tag [Pump 30 seconds] OnProgressChange progress 1000000 max
|1000000
|At 54.271 Event tag [Pump 30 seconds] OnProgressChange progress -1 max
|1000000
|At 54.286 Event tag [Pump 30 seconds] OnProgressChange progress 1000000 max
|1000000
|At 54.584 Event tag [Pump 30 seconds] OnBeforeNavigate2 on url
|[http://msdn2.microsoft.com/en-us/library/aa752574(d=toc).aspx] on frame []
|At 54.610 Event tag [Pump 30 seconds] OnProgressChange progress 1000000 max
|10000
|At 54.616 Event tag [Pump 30 seconds] OnCommandStateChange: -1 False
|At 54.769 Event tag [Pump 30 seconds] OnProgressChange progress 0 max 0
|At 56.209 Event tag [Pump 30 seconds] OnCommandStateChange: 2 False
|At 56.210 Event tag [Pump 30 seconds] OnCommandStateChange: 1 False
|At 57.316 Event tag [Pump 30 seconds] OnProgressChange progress 70800 max
|1000000
|At 64.288 Event tag [Pump 30 seconds] OnProgressChange progress 1000000 max
|1000000
|At 64.345 Event tag [Pump 30 seconds] OnProgressChange progress -1 max
|1000000
|At 64.526 Event tag [Pump 30 seconds] OnCommandStateChange: -1 False
|At 64.854 Event tag [Pump 30 seconds] OnProgressChange progress 0 max 0
|At 77.460 Main  tag [Pump 20 seconds] The page should be stable and there
|should be no trailing events
|At 97.461 Main  tag [End test]
|
|--- End Output ---




More information about the Python-win32 mailing list