[python-win32] COM server with events and multiple threads

David Janssens dja at info.ucl.ac.be
Thu May 19 16:21:59 CEST 2005


Thanks for the reply,

The reason I chose to set the threading model of the python server 
component to "free" was that if I do this, then the component gets 
created in the MTA of the VB6 GUI process. If I don't do this, the VB6 
event handlers are run in different threads than the GUI thread and many 
problem arise.

I don't know how to tell VB6 to use free-threading or how to spawn new 
threads in VB6 that belong to the MTA. Are you sure it's possible, do 
you have more information on how to do this? I suppose the problem is 
quite common to all people who whish to use a VB6 GUI with a python COM 
server backend. If I can get it working, I would like to submit a sample 
that shows how to do it, because I think it could be useful to many people.

Thanks for your help,
David Janssens

The events are sent to the GUI as follows: (This is based on a sample I 
found on the same mailing list, except the sample didn't set the 
threading model of the component to "free")

import sys
import pythoncom
import win32com.server
import win32com.server.connect
from win32com.server.exception import COMException
import winerror

IID_IServerWithEvents_Event = pythoncom.MakeIID('{11AEB37F-0CAB-4DE2-B975-F05567EADC8E}')
IID_IServerWithEvents = pythoncom.MakeIID('{938F1121-21ED-47A0-B0B7-47D7D6E99A7B}')

class Node(win32com.server.connect.ConnectableServer):
	_reg_desc_ = 'MyProject Node Component'
	_reg_clsid_ = '{49604ea4-bb2a-d04a-7fdd-b20e7e79cb40}'
	_reg_progid_ = 'MyProject.Node'
	_reg_threading_ = 'free'
	_public_methods_ = ['run'] + win32com.server.connect.ConnectableServer._public_methods_
	_connect_interfaces_ = [IID_IServerWithEvents_Event]

	# Need to overload this method to tell that we support IID_IServerWithEvents
	def _query_interface_(self, iid):
		if iid == IID_IServerWithEvents:
			return win32com.server.util.wrap(self)

	### node methods called from gui ##################################

	def run(self):
		try:
			pass
		except Exception,e:
			raise COMException(str(e),winerror.OLE_E_OLEVERB)

	### node events sent to gui #######################################

	def connected(self):
		self._BroadcastNotify(self.NotifyConnected, (None,))

	def disconnected(self):
		self._BroadcastNotify(self.NotifyDisconnected, (None,))

	def NotifyConnected(self, interface, args):
		interface.Invoke(0x000003ea, 0, pythoncom.DISPATCH_METHOD, 1)

	def NotifyDisconnected(self, interface, args):
		interface.Invoke(0x000003eb, 0, pythoncom.DISPATCH_METHOD, 1)

if __name__=='__main__':
    print 'Registering COM Server...'
    import win32com.server.register
    win32com.server.register.UseCommandLine(Node, debug=1)

The corrresponding IDL file is:

[
  uuid(d77f974c-234f-0795-cf3e-aced80d9fc89),
  version(1.0),
  helpstring("MyProject 1.0 Type Library")
]
library MyProject
{
    importlib("stdole32.tlb");

    [
      uuid(938F1121-21ED-47A0-B0B7-47D7D6E99A7B),
      version(0.1)
    ]
    dispinterface IServerWithEvents {
        properties:
        methods:
            [id(0x000003e8)]
            VARIANT run();
    };

    [
      uuid(11AEB37F-0CAB-4DE2-B975-F05567EADC8E),
      version(0.1)
    ]
    dispinterface IServerWithEvents_Event {
        properties:
        methods:
            VARIANT connected();
            [id(0x000003eb)]
            VARIANT disconnected();
            [id(0x000003ec)]
    };

    [
      uuid(49604ea4-bb2a-d04a-7fdd-b20e7e79cb40),
      version(0.1)
    ]
    coclass Node {
        [default] dispinterface IServerWithEvents;
        [default, source] dispinterface IServerWithEvents_Event;
    };
};

(I generate a TLB file from the IDL file and import that into VB6)

Mark Hammond wrote:

>>I am trying to build an application where the GUI is implemented as a
>>VB6 exe and most of the core functionality is implemented as a python
>>COM server that is called by the GUI.
>>
>>The python COM server has multiple threads running in it and sends
>>events once in a while to the VB6 GUI.
>>
>>The python COM server needs to be run in the MTA of the application's
>>process because all the events from the server to the GUI need to be
>>marshalled, so I set the threading model of the python COM
>>server to "free".
>>    
>>
>
>A COM server can only indicate the threading options it supports - the
>*creator* of the COM object is responsible for setting the actual thread
>mode used.  If the server doesn't support the mode, you get that error.
>
>Consider: The thread mode is set by a CoInitialize(Ex) call.  Such a call
>must be made before your COM object can be used or instantiated by that
>thread.  Therefore, by the time your server has been created/called, the
>thread mode must have already been set.
>
>You need to tell VB to use free-threading if you want your object to be only
>used that way.
>
>  
>
>>disappears. But of course that doesn't suit me because then
>>some VB6 gui
>>code that handles COM server events gets called in threads that are
>>different from the main gui thread.
>>    
>>
>
>COM itself should take care of that.  Earlier you mentioned:
>
>  
>
>>The python COM server has multiple threads running in it and sends
>>events once in a while to the VB6 GUI.
>>    
>>
>
>How do you pass the event sink objects to the threads?  If ever a COM
>objects crosses thread boundaries, it must do so via
>CoMarshalInterThreadInterfaceInStream().  If you fail to do that, then you
>will not get COM's proxying.  Note however that the call you make in this
>thread will still block until the other thread could handle it - ie, the
>event delivery is unlikely to be asynch.
>
>Mark
>
>  
>


More information about the Python-win32 mailing list