P
puff
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.
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.