[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