豪华大巴车价格:[python-win32] DispatchWithEvents design ques...

来源:百度文库 编辑:九乡新闻网 时间:2024/04/28 21:02:44

[python-win32] DispatchWithEvents design question

Richard Bell rbell01824 at earthlink.net
Tue Jun 5 19:38:36 CEST 2007

  • Previous message: [python-win32] DispatchWithEvents experiment with subclass event routine and pump messages
  • Next message: [python-win32] DispatchWithEvents design question
  • Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

I'm continuing to work on a class to automate IE in an apartment-threadedearly binding class.  The current design is relatively conventional andlooks like this:class Yie(object):def __init__(self, eventClass):--- code deleted ---self._ie = win32com.client.DispatchWithEvents("InternetExplorer.Application",YieEvents)self._ie.Visible = 1_yamies[self._ie.HWND] = self--- code deleted ------ class methods that automate IE ---class YieEvents(object):--- class methods that respond to IE events ---It is necessary for several reasons for the event class event handlers tooccasionally reference attributes and methods in the Yie instance holdingself._ie.  To support this requirement I keep a dictionary of Yie instancesindexed by self._ie.HWND which is known to self._ie and its YieEventsOn-event handlers.But there is a catch. When DispatchWithEvents creates self._ie it firstinitializes the IE com object, then an internal object, and finallyYieEvents.  Depending on timing, it is possible for IE to start throwingevents BEFORE control returns to the Yie's __init__ routine and BEFORE_yamies is set.  When this occurs the event routines are unable to find theYie instance they are servicing.As a purely practical matter, this doesn't really cause much difficultybecause the early events are OnVisible and OnCommandStateChange both ofwhich can be safely ignored as IE comes up.  Even so, I'm troubled by thebehavior.In casting around for a solution I poked into the code forDispatchWithEvents.  If I understand it correctly, it is possible to includeIE automation methods as part of the event class something like this:class Yie:--- class variables ---def __init__(self):--- instance variables ---def NavigateWait1( self, url):--- code to navigate and wait for completion ------ methods to provide other IE automation services ---def OnVisible(self, vis):--- code to handle OnVisible event ------ methods to handle other IE events ---Using this design it is possible to use the class something like this:ie = win32com.client.DispatchWithEvents('InternetExplorer.Application',Yie)ie.Visible=Trueie.NavigateWait1('www.google.com')Since the revised Yie class holds BOTH the event and automation methods theneed for the dictionary goes away and the On-event routines can referencewhatever instance attributes/methods are needed. A bit of experimentationshows that this does indeed work (if anyone is interested, I'll gladly postthe code).Question 1: Is this a good design/idea/advisable?  I'm still learning aboutCOM automation and there are many that understand it rather better than I.What do you think?One of the things that has to happen for this to work is that a navigatingIE automation method (Navigate2, GoBack, etc.) MUST pump messages or IEhangs.  The net of this is that the IE automation code to support navigationneeds to look something like this:def NavigateWait1( self, url, timeout):startTime = time.time()self.Navigate2( url )while True:pythoncom.PumpWaitingMessages()rc = win32event.MsgWaitForMultipleObjects((self._eventNone,), 0, 250,win32event.QS_ALLEVENTS)if (rc == win32event.WAIT_TIMEOUT):if time.clock() - startTime >= timeout:returnDuring navigation the while loop pumps messages every 250 MS.  As eventsoccur the event routines are invoked and do whatever they do including,possibly, changing attributes within the IE automation instance.Eventually, the timeout elapses and the while loop terminates. But ...Question 2: Is this safe?  Python source gets translated into byte code.  Iunderstand that a single byte code is atomic and can not be interrupted (isthis true?).  But how about a statement?  There are a number of places inthe automation code where several statements have to execute entirely or theinternal state of the automation instance is inconsistent.  Do I need toprotect these with a Mutex?  Alternately, can I depend onpythoncom.PumpWaitingMessages to be atomic such that the event routines CANONLY occur while the while loop is invoking PumpWaitingMessages?One of the things the IE automation class needs to deal with is an IENewWindow event.  The nub of this is that when a page wants to generate anew window is causes an OnNewWindow3 event.  The event has the followingtemplate:def OnNewWindow3(self,ppDisp=defaultNamedNotOptArg,cancel=defaultNamedNotOptArg,dwFlags=defaultNamedNotOptArg,bstrUrlContext=defaultNamedNotOptArg,bstrUrl=defaultNamedNotOptArg):The event routine can return nothing, in which case IE does whatever thebrowser's configuration defines.  Alternately, the event routine can returnTrue to cancel the NewWindow request (seehttp://msdn2.microsoft.com/en-us/library/aa768288.aspx).  Finally, the eventroutine can return the IDispatch interface pointer of an InternetExplorerobject that will host the new window.  This latter bit means that the eventroutine must instantiate a new instance something like this:new_ie = win32com.client.DispatchWithEvents('InternetExplorer.Application',Yie)Based on my knowledge of Python, I think this should work just fine.  It is,after all, just a method in a class creating a new instance of the class.Some experimentation shows that the OnNewWindow3 event routine can do this:new_ie = win32com.client.DispatchWithEvents('InternetExplorer.Application',Yie)return new_ie, falseand the new IE instance is created.  But I'm a bit concerned that the new IEmay start generating events BEFORE I return from the original IE'sNewWindow3 event routine!  That is, after all, the problem this new designis intended to address.  If it does, this means that the Python COM routinescan potentially be re-entered while processing an event.  Alternately, doesPumpWaitingMessages insure that at most one message at a time occurs so thatthe NewWindow3 event routine is guaranteed to complete BEFORE another eventon the original or new IE can occur?Question 3: Does PumpWaitingMessages insure that at MOST one message/eventis pumped such that reentrancy is not an issue?My apologies for the length of this post but I wanted to be as clear aspossible in hopes that I can get some feedback.  I appreciate that these arerather subtle questions.  If I'm able to satisfy myself on the answers, I'llgladly provide a demo to add to the distribution for the benefit of others.Thanks in advance for any help.Regards,Richard