[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