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 starting IE as follows:

    ie = win32com.client.DispatchWithEvents( object, YamieEvents )
    ie.event = win32event.CreateEvent(None,0,0,None)

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 pump 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 truly 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.


_______________________________________________
Python-win32 mailing list
Python-win32@python.org
http://mail.python.org/mailman/listinfo/python-win32

Reply via email to