Mailing List Archive

COM Event Sinks and Connection Points in Python
I am trying to use functionality from a DLL that requires me to create a COM
event sink so that it can call back with events. I am trying to write this
event sink in Python. However, when I try to create a SimpleConnection
object, it gives this exception: "Unable to open the access token of the
current thread".

In the source code for testPyComTest.py (which is the only thing I could find
that uses the SimpleConnection object) that comes with the win32all
distribution, the following three lines exist right above code that would test
the connection point functionality:

# AAARG - why do connection points fail?
print "Skipping connection points as we have a threading bug somewhere :-("
return

Now, this comment leads me to believe that Mark Hammond, the author of the
Python Win32 stuff, has the same problem. Does anyone know how to get around
this problem? Below is the sample code I am trying to use.

#---- test.py
import pythoncom

# The GUID was retrieved from the IDL file of an external DLL.
# Is there a better way to get these without hard coding?
IID_DEMEvents = pythoncom.MakeIID ("{7BAE0700-E7D5-11d0-9C22-0020AFF2B0F5}")

class MonitorEvents:
"""Event Sink for Test.DEM"""
_reg_clsid_ = "{554A2C64-EC50-11D2-BD51-006097B6AF50}"
_reg_desc_ = "PythonTest.MonitorEvents"
_reg_progid_ = "PythonTest.MonitorEvents"
_reg_class_spec_ = "test.MonitorEvents"
_public_methods_ = ["onSubscribe"]
_public_attrs_ = []
_readonly_attrs_ = []
_com_interfaces_ = [IID_DEMEvents]

def onSubscribe (self):
# Not implemented yet.
pass

if __name__ == "__main__":
import win32com.server.register
import win32com.client
import win32com.client.connect

# Test.DEM is the ProgID of the event source. (This is an
# external DLL.)
dem = win32com.client.Dispatch ("Test.DEM")

# MonitorEvents is the Python class that implements the Event Sink.
meobj = MonitorEvents()

# The following line causes an exception.
s = win32com.client.connect.SimpleConnection (dem, meobj, IID_DEMEvents)

# Creating the SimpleConnection object fails with: # #Traceback
(innermost last): # File "T:\Playground\Python\Monitor\monitor.py", line
54, in ? # s = win32com.client.connect.SimpleConnection (dem, meobj,
IID_DEMEvents) # File "C:\Tools\Python\win32com\client\connect.py", line
10, in __init__ # self.Connect(coInstance , eventInstance, eventCLSID) #
File "C:\Tools\Python\win32com\client\connect.py", line 27, in Connect #
self.cookie = self.cp.Advise(comEventInstance) #pywintypes.com_error:
(-2147220990, 'Unable to open the access token of the current thread', None,
None)

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
COM Event Sinks and Connection Points in Python [ In reply to ]
cingram@my-dejanews.com wrote in message
<7eggfh$o0f$1@nnrp1.dejanews.com>...
>I am trying to use functionality from a DLL that requires me to create a
COM
>event sink so that it can call back with events. I am trying to write this
>event sink in Python. However, when I try to create a SimpleConnection
>object, it gives this exception: "Unable to open the access token of the
>current thread".

There appears to be some problem using connection points from Python.exe.
Some objects - mainly OCX controls - only fire event when running inside
Pythonwin as an OCX.

The "threading bug" I mention isnt the same as this. The threading bug will
actually cause Python to die completely with an access violation. I am
fairly certain they are not related.

Events seem a black art. Im happy to help you track this down, but I havent
much time...

Mark.
COM Event Sinks and Connection Points in Python [ In reply to ]
Some of COM features (especially when running in a Single Threaded Apartment
(STA)) depend on the application having an event loop. I have not looked at
the sources for PythonWin, but I have looked at the Python ones, and I did
not see any event loop servicing the event queue. This would explain why you
don't see the fired events.

Martin

Mark Hammond wrote in message <7egnl2$ca5$1@m2.c2.telstra-mm.net.au>...
>
>cingram@my-dejanews.com wrote in message
><7eggfh$o0f$1@nnrp1.dejanews.com>...
>>I am trying to use functionality from a DLL that requires me to create a
>COM
>>event sink so that it can call back with events. I am trying to write
this
>
>There appears to be some problem using connection points from Python.exe.
>
>Events seem a black art. Im happy to help you track this down, but I
havent
>much time...
COM Event Sinks and Connection Points in Python [ In reply to ]
(posted, and copied to Mark)

"Mark Hammond" <MHammond@skippinet.com.au> wrote:

>
>cingram@my-dejanews.com wrote in message
><7eggfh$o0f$1@nnrp1.dejanews.com>...
>>I am trying to use functionality from a DLL that requires me to create a
>COM
>>event sink so that it can call back with events. I am trying to write this
>>event sink in Python. However, when I try to create a SimpleConnection
>>object, it gives this exception: "Unable to open the access token of the
>>current thread".
>
>There appears to be some problem using connection points from Python.exe.
>Some objects - mainly OCX controls - only fire event when running inside
>Pythonwin as an OCX.

For controls this is to be expected. They are allowed to be fairly
non-functional until activated, which requires a control site. They might
implement IDispatch, but they can not be used a 'just' an automation server.

>The "threading bug" I mention isnt the same as this. The threading bug will
>actually cause Python to die completely with an access violation. I am
>fairly certain they are not related.

I read that comment a while ago, and Ive been meaning to investigate since then.
Well, my next project will be using events, and this post reminded me, so I
thought I would take a look.

If I remove the extra 'return' from testPyComTest.py then I always get a
Fatal Python error: PyThreadState_Get: no current thread
Is this the bug you mean? I think I have some answers....

I believe this problem is not caused by a bug in pythoncom, but by several bugs
in PyCOMTest, the C++ server that complements this test harness.

In PyCOMImpl.cpp, line 49, a new thread is started. That thread uses the Fire
method of the CPyCOMTest object, however this breaks the COM apartment rules. To
pass an object reference across apartments you need to use
CoMarshalInterThreadInterfaceInStream, at least once.

Secondly, the new thread does not call CoInitializeEx.

Hopefully I will have time to dig further next week.

I hope this helps,

Toby Dickenson
COM Event Sinks and Connection Points in Python [ In reply to ]
Martin Bertolino wrote in message <7eie3h$sr$1@newsin-1.starnet.net>...
>Some of COM features (especially when running in a Single Threaded
Apartment
>(STA)) depend on the application having an event loop. I have not looked at
>the sources for PythonWin, but I have looked at the Python ones, and I did
>not see any event loop servicing the event queue. This would explain why
you
>don't see the fired events.

I have tried that - although without a window (note pythoncom exposes enough
to run a message loop - win32event an even better one :)

Also tried running within Pythonwin (so it has a window), but not as a
control - still didnt work. Seemed to need some of the control container
plumbing to be in place.

Dont think I tried all of the threading models tho...

Mark.
COM Event Sinks and Connection Points in Python [ In reply to ]
Toby Dickenson wrote in message <3711134d.17632096@news.freeserve.net>...
>"Mark Hammond" <MHammond@skippinet.com.au> wrote:

>For controls this is to be expected. They are allowed to be fairly
>non-functional until activated, which requires a control site. They might
>implement IDispatch, but they can not be used a 'just' an automation
server.

Actually, in many cases, I can use the functionality of the objects - just
not get events. Excel, Word and MSAgent are good examples - can use the
IDispatch interfaces fine, but cant get events.

However, Im not convinced it isnt something silly I have done, lacking the
time to give it serious effort.

>If I remove the extra 'return' from testPyComTest.py then I always get a
>Fatal Python error: PyThreadState_Get: no current thread
>Is this the bug you mean? I think I have some answers....

Yes, and great!

>I believe this problem is not caused by a bug in pythoncom, but by several
bugs
>in PyCOMTest, the C++ server that complements this test harness.
>
>In PyCOMImpl.cpp, line 49, a new thread is started. That thread uses the
Fire
>method of the CPyCOMTest object, however this breaks the COM apartment
rules. To
>pass an object reference across apartments you need to use
>CoMarshalInterThreadInterfaceInStream, at least once.

ohh. Yes. good point. This means it probably should work if we init
Pythoncom as free-threaded.

>Secondly, the new thread does not call CoInitializeEx.
Oops.
>
>Hopefully I will have time to dig further next week.

Great - let me know if it fixes it! However, the particular thread state
error from Python makes me think it wont - the problems you describe would,
to me, imply different symptoms.

I am sort-of hoping that this is actually finding a threading bug in the COM
framework. If so, it will be useful as it is easily reproducible. Ahhh,
for more time to play with this stuff...

Mark.