codekingpro/portable-devtools
114k
1# A sample originally provided by Richard Bell, and modified by Mark Hammond.2 3# This sample demonstrates how to use COM events in a free-threaded world.4# In this world, there is no need to marshall calls across threads, so5# no message loops are needed at all. This means regular cross-thread6# sychronization can be used. In this sample we just wait on win32 event7# objects.8 9# See also ieEventsApartmentThreaded.py for how to do this in an10# aparment-threaded world, where thread-marshalling complicates things.11 12# NOTE: This example uses Internet Explorer, but it should not be considerd13# a "best-practices" for writing against IE events, but for working with14# events in general. For example:15# * The first OnDocumentComplete event is not a reliable indicator that the16# URL has completed loading17# * As we are demonstrating the most efficient way of handling events, when18# running this sample you will see an IE Windows briefly appear, but19# vanish without ever being repainted.20 21import sys22 23sys.coinit_flags = 0 # specify free threading24 25 26import pythoncom27import win32api28import win32com.client29import win32event30 31 32# The print statements indicate that COM has actually started another thread33# and will deliver the events to that thread (ie, the events do not actually34# fire on our main thread.35class ExplorerEvents:36 def __init__(self):37 # We reuse this event for all events.38 self.event = win32event.CreateEvent(None, 0, 0, None)39 40 def OnDocumentComplete(self, pDisp=pythoncom.Empty, URL=pythoncom.Empty):41 #42 # Caution: Since the main thread and events thread(s) are different43 # it may be necessary to serialize access to shared data. Because44 # this is a simple test case, that is not required here. Your45 # situation may be different. Caveat programmer.46 #47 thread = win32api.GetCurrentThreadId()48 print("OnDocumentComplete event processed on thread %d" % thread)49 # Set the event our main thread is waiting on.50 win32event.SetEvent(self.event)51 52 def OnQuit(self):53 thread = win32api.GetCurrentThreadId()54 print("OnQuit event processed on thread %d" % thread)55 win32event.SetEvent(self.event)56 57 58def TestExplorerEvents():59 iexplore = win32com.client.DispatchWithEvents(60 "InternetExplorer.Application", ExplorerEvents61 )62 63 thread = win32api.GetCurrentThreadId()64 print("TestExplorerEvents created IE object on thread %d" % thread)65 66 iexplore.Visible = 167 try:68 iexplore.Navigate(win32api.GetFullPathName("..\\readme.html"))69 except pythoncom.com_error as details:70 print("Warning - could not open the test HTML file", details)71 72 # In this free-threaded example, we can simply wait until an event has73 # been set - we will give it 2 seconds before giving up.74 rc = win32event.WaitForSingleObject(iexplore.event, 2000)75 if rc != win32event.WAIT_OBJECT_0:76 print("Document load event FAILED to fire!!!")77 78 iexplore.Quit()79 # Now we can do the same thing to wait for exit!80 # Although Quit generates events, in this free-threaded world we81 # do *not* need to run any message pumps.82 83 rc = win32event.WaitForSingleObject(iexplore.event, 2000)84 if rc != win32event.WAIT_OBJECT_0:85 print("OnQuit event FAILED to fire!!!")86 87 iexplore = None88 print("Finished the IE event sample!")89 90 91if __name__ == "__main__":92 TestExplorerEvents()93 