Pproblems using Python, COM, Event (or Connection Point) and thread

Marc ENGEL marc.engel at recif.com
Wed Nov 14 04:34:14 EST 2001


Dear all,

I am trying to do a kind of Event Manager in Python. The architecture
I want is the following:
- A main python scripts start all the COM object needed by the
application with DispatchWithEvents and then wait for messages using
PumpMessage
- The EventManager registered to each COM object do litle processing:
it just delegates the event processing to a new thread and return (I
don't need to return a value for events)
- The Threaded Event Manager do the actual processing and mainly I
want it to
call the method that can process the event on other COM objects. The
Event manager may also do some additional processing depending on the
event.

In order to test this, I started from the Excel event script example
and I modify it. See script source at the end of the message. It is
running on my computer

I have 2 problems:
1 - If I try to access the COM object in the Event Thread by
uncommenting Target.Column in classe ExcelEvents (line >>> print
"Column = "#, Target.Column), I get the following error:

  File "d:\program files\python21\win32com\client\__init__.py", line
334, in _ApplyTypes_
    return self._get_good_object_(apply(self._oleobj_.InvokeTypes,
(dispid, 0, wFlags, retType, argTypes) + args), user, resultCLSID)
pywintypes.com_error: (-2147417842, "L'application a appel\xe9 une
interface qui \xe9tait maintenue en ordre pour une thread
diff\xe9rente.", None, None)

Sorry the error message is in french (but actually I am french :)). It
means "Application has called an interface that was maintained in
order for a different thread"

Any hint?

2 - I would like that class EventManager does not define all events it
can manage but dynamically create a function to be called for each
event that it is asked to manage. I thought it would be intersting to
use the magic method __getattr__ to create the method with the event
name dynamically. But as you will see if you execute the script, this
method is never called.

Is there anything I did not understand about this method?

Thanks for any hint,

Marc ENGEL

-----------------> Start Python script
import sys, time, msvcrt, win32com.client, win32gui, thread, win32ui,
win32api, win32con

sys.coinit_flags = 0 #COINIT_MULTITHREADED    
#COINIT_APARTMENTTHREADED = 0x02

import pythoncom

class EventsManager :
	def __getattr__(self, attr):
		print "Trying to call event ", attr
		args=self._prop_map_get_.get(attr)
		if args is None:
			raise AttributeError, attr
		return apply(self._ApplyTypes_, args)
	# Default handler for Event OnSheetBeforeDoubleClick
	# Delegates treatment to class ExcelEvents into a new thread
	def OnSheetBeforeDoubleClick(self, Sh, Target, Cancel):
		thread.start_new_thread(ExcelEvents().OnSheetBeforeDoubleClick, (Sh,
Target, Cancel))
		return 0

class ExcelEvents:
	def OnSheetBeforeDoubleClick(self, Sh, Target, Cancel):
		pythoncom.CoInitializeEx(0)
		print "Column = "#, Target.Column
		time.sleep(5)
		print "Finished processing event for column "#, Target.Column
		pythoncom.CoUninitialize()
		return 0


def ThreadWaitingForUserInput() :
	win32api.MessageBox(0, "Press OK when you want to stop the message
loop", "Info")
	# Post message to dummy window in order to get out of the main event
loop PumpMessages
	win32gui.PostMessage(MyDummyWindow, win32con.WM_QUIT, 0, 0)
	return 0

# Create new Execel application
excel = win32com.client.DispatchWithEvents("Excel.Application",
EventsManager)
excel.Visible=1
excel.Workbooks.Add()

# Create a dummy window for posting WM_QUIT message
MyDummyWindow = win32gui.CreateWindow("BUTTON", "TestWindow", 0, 0, 0,
100, 100, 0, 0, 0, None)

# Start new thread to display the MessageBox to exit application
thread.start_new_thread(ThreadWaitingForUserInput, ())
# Give it a chance to start
win32api.Sleep(100)
win32ui.PumpWaitingMessages()

# Main event loop waiting for quit message posted from thread
ThreadWaitingForUserInput
pythoncom.PumpMessages()
print "Quitting script..."

# Don't want dialog box for saving document before closing Excel
excel.DisplayAlerts = 0
# Remove the workbook
excel.Workbooks.Close()
# Quit application
excel.Quit()
# Release excel object
excel = None

# This is just a trick to have the script displaying error message if
any!
print "Press OK on Popup Message box to stop scipt..."
win32api.MessageBox(0, "Press OK to stop script", "Info")

-----------------> End Python script



More information about the Python-list mailing list