eventsFreeThreaded.py 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. # A sample originally provided by Richard Bell, and modified by Mark Hammond.
  2. # This sample demonstrates how to use COM events in a free-threaded world.
  3. # In this world, there is no need to marshall calls across threads, so
  4. # no message loops are needed at all. This means regular cross-thread
  5. # sychronization can be used. In this sample we just wait on win32 event
  6. # objects.
  7. # See also ieEventsApartmentThreaded.py for how to do this in an
  8. # aparment-threaded world, where thread-marshalling complicates things.
  9. # NOTE: This example uses Internet Explorer, but it should not be considerd
  10. # a "best-practices" for writing against IE events, but for working with
  11. # events in general. For example:
  12. # * The first OnDocumentComplete event is not a reliable indicator that the
  13. # URL has completed loading
  14. # * As we are demonstrating the most efficient way of handling events, when
  15. # running this sample you will see an IE Windows briefly appear, but
  16. # vanish without ever being repainted.
  17. import sys
  18. sys.coinit_flags=0 # specify free threading
  19. import os
  20. import win32api
  21. import win32event
  22. import win32com.client
  23. import pythoncom
  24. import time
  25. # The print statements indicate that COM has actually started another thread
  26. # and will deliver the events to that thread (ie, the events do not actually
  27. # fire on our main thread.
  28. class ExplorerEvents:
  29. def __init__(self):
  30. # We reuse this event for all events.
  31. self.event = win32event.CreateEvent(None, 0, 0, None)
  32. def OnDocumentComplete(self,
  33. pDisp=pythoncom.Empty,
  34. URL=pythoncom.Empty):
  35. #
  36. # Caution: Since the main thread and events thread(s) are different
  37. # it may be necessary to serialize access to shared data. Because
  38. # this is a simple test case, that is not required here. Your
  39. # situation may be different. Caveat programmer.
  40. #
  41. thread = win32api.GetCurrentThreadId()
  42. print("OnDocumentComplete event processed on thread %d"%thread)
  43. # Set the event our main thread is waiting on.
  44. win32event.SetEvent(self.event)
  45. def OnQuit(self):
  46. thread = win32api.GetCurrentThreadId()
  47. print("OnQuit event processed on thread %d"%thread)
  48. win32event.SetEvent(self.event)
  49. def TestExplorerEvents():
  50. iexplore = win32com.client.DispatchWithEvents(
  51. "InternetExplorer.Application", ExplorerEvents)
  52. thread = win32api.GetCurrentThreadId()
  53. print('TestExplorerEvents created IE object on thread %d'%thread)
  54. iexplore.Visible = 1
  55. try:
  56. iexplore.Navigate(win32api.GetFullPathName('..\\readme.htm'))
  57. except pythoncom.com_error as details:
  58. print("Warning - could not open the test HTML file", details)
  59. # In this free-threaded example, we can simply wait until an event has
  60. # been set - we will give it 2 seconds before giving up.
  61. rc = win32event.WaitForSingleObject(iexplore.event, 2000)
  62. if rc != win32event.WAIT_OBJECT_0:
  63. print("Document load event FAILED to fire!!!")
  64. iexplore.Quit()
  65. # Now we can do the same thing to wait for exit!
  66. # Although Quit generates events, in this free-threaded world we
  67. # do *not* need to run any message pumps.
  68. rc = win32event.WaitForSingleObject(iexplore.event, 2000)
  69. if rc != win32event.WAIT_OBJECT_0:
  70. print("OnQuit event FAILED to fire!!!")
  71. iexplore = None
  72. print("Finished the IE event sample!")
  73. if __name__=='__main__':
  74. TestExplorerEvents()