When interfacing to a COM object, is it possible to pump messages in a thread?
I'm working on an application that automates IE and needs to monitor IE events (yes I know about Pamie). I'm able to start IE as follows: ie = win32com.client.DispatchWithEvents( object, YamieEvents ) ie.event = win32event.CreateEvent(None,0,0,None) An earlier post by Mark Hammond suggested the ie.event line as a fix to an issue that seems to remain an issue in the current release. The class YamieEvents catches a number of events and outputs trace messages whenever an event occurs. It looks like this: class YamieEvents: def OnBeforeNavigate2(self, pDisp=defaultNamedNotOptArg, url=defaultNamedNotOptArg, Flags=defaultNamedNotOptArg, TargetFrameName=defaultNamedNotOptArg, PostData=defaultNamedNotOptArg, Headers=defaultNamedNotOptArg, Cancel=defaultNamedNotOptArg): out = 'OnBeforeNavigate2 URL [%s] \n' % url out += ' Flags [%s] \n' %`Flags` out += ' TargetFrameName [%s]' % TargetFrameName print out; # many more On event routines I'm able to navigate and wait as follows seeing the event trace: ie.Navigate(url) try: ie.Navigate(url) WaitMsg() except pythoncom.com_error, details: PrintFlush( "Warning - could not open %s"%url, details ) Where WaitMsg() looks like this: def WaitMsg(timeout=30, donetime=2000): # timeout in seconds, dontime in milliseconds! timeStart = time.time() timeTic = timeStart while True: rc = win32event.MsgWaitForMultipleObjects( (ie.event,), 0, donetime, win32event.QS_ALLEVENTS) if rc == win32event.WAIT_OBJECT_0: pass elif rc == win32event.WAIT_OBJECT_0+1: pythoncom.PumpWaitingMessages() elif rc == win32event.WAIT_TIMEOUT: PrintFlush( ' WaitMsg: got donetime' ) return True else: PrintFlush( 'Unrecognized event' ) timeNow = time.time() if timeNow - timeStart > timeout: PrintFlush( ' ##### got timeout' ) return False if timeNow - timeTic > 1: PrintFlush( '.', ) timeTic = timeNow So far everything seems to work fine. However, I've encountered a difficulty when dealing with web pages that have script that causes events AFTER the navigation is complete! Since the message pump is not being run, these events are not processed and IE appears to be hung (the script's page changes, navigations, etc. do no occur). I'm trying to work out how to run the message loop on a thread so that messages are continually pumped and these script modified pages are properly handled. Modeling a solution after Mark Hammond's Appendix D threads example I'm creating the message pump thread as follows: ie = win32com.client.DispatchWithEvents("InternetExplorer.Application", \ YamieEvents) ie.event = win32event.CreateEvent(None,0,0,None) ie.Visible = 1 WaitMsg() # now IE is up and google is displayed, there is good reason to think IE # is good and truely ready to be used #pass our ie com object to a thread to run the message loop # marshal the object object_stream = pythoncom.CoMarshalInterThreadInterfaceInStream( \ pythoncom.IID_IDispatch, ie ) args = (object_stream,) handle, id = win32process.beginthreadex( None, 0, PumpMessages, args, 0 ) The thread function looks like this: def PumpMessages(object_stream): pythoncom.CoInitialize() # initialize com for single thread # unmarshal the DispatchWithEvents object object = pythoncom.CoGetInterfaceAndReleaseStream( \ object_stream, pythoncom.IID_IDispatch) # convert to a useable DispatchWithEvents object ie = win32com.client.DispatchWithEvents( object, YamieEvents ) # without this line, MsgWaitForMultipleObjects reports no attribute event!? ie.event2 = win32event.CreateEvent(None,0,0,None) # now we should be in a position wait for events and pump messages timeStart = time.time() while True: rc = win32event.MsgWaitForMultipleObjects( (ie.event2,), 0, 1000, win32event.QS_ALLEVENTS) if rc == win32event.WAIT_OBJECT_0: PrintFlush( ' thread: event' ) elif rc == win32event.WAIT_OBJECT_0+1: PrintFlush( ' thread: pump' ) pythoncom.PumpWaitingMessages() elif rc == win32event.WAIT_TIMEOUT: PrintFlush( ' thread: tic' ) else: PrintFlush( ' thread: unrecognized event' ) if time.time() - timeStart > 40: PrintFlush( ' thread: got timeout' ) break # be a good citizen and cleanup self ie = None pythoncom.CoUninitialize() I've a question about this code since it was necessary to create a second event for the ie object even though the original object and it's event should (I believe) be available. Am I doing something wrong here? Second when I test this code I see that the thread runs ( trace messages thread: tic occur). But events are not being pumped since none of the event messages occur. Eventually the thread times out. Any clues as to what I'm missing? I appreciate that this is a lengthy post. I've tried to show only the critical sections of code but the issue is complex. Thanks for any help. -- http://mail.python.org/mailman/listinfo/python-list