James Teh schrieb:
Hi.
In our project, we communicate with Microsoft SAPI 4 speech synthesisers
using COM. When we want to speak data, we must provide an object which
can receive events. (The IConnectionPoint* interfaces are not used.)
Following is a rough, very simplified outline of the code:
class SynthDriverBufSink(COMObject):
_com_interfaces_ = [ITTSBufNotifySink]
...
class SynthDriver(object):
def __init__(self):
self._ttsCentral = ...
self._bufSink=SynthDriverBufSink()
...
def performSpeak(self, text):
...
self._ttsCentral.TextData(..., text,
self._bufSink, ITTSBufNotifySink._iid_)
_ttsCentral.TextData accepts a pointer to IUnknown (this is defined in
its interface), as well as the iid of the ITTSBufNotifySink interface.
The issue is that self._bufSink is created at instantiation, but is used
in many calls to performSpeak. In comtypes 0.6.1, this was fine.
However, in 0.6.2, when the ref count of a COMObject hits 0, the
_com_pointers_ dict gets cleared to avoid a memory leak (svn r544). This
means that the first call to performSpeak is fine. However, after this
call completes, the ref count on self._bufSink will drop to 0,
_com_pointers_ will be cleared and subsequent calls will fail to get the
appropriate pointer.
James,
I agree with you that this is a problem. I'm looking into it but it seems
to take langer than expected.
We've fixed this by never holding the underlying COMObject. In the
constructor, we do:
self._bufSink=SynthDriverBufSink().QueryInterface(ITTSBufNotifySink)
This way, the pointer will AddRef and keep the underlying COMObject
alive and will Release it when the pointer gets garbage collected.
Despite the solution, this raises the question: Are we supposed to never
maintain a long-lasting reference to an underlying COMObject? That is,
was it always intended that a COMObject should never be held directly?
No, it was not intended to be this way.
In C++, one usually has the ref count start at 1, rather than 0. I
understand this would present challenges in Python, as you don't know
when to clean up the object. However, it'd be good to have some policy
documentation on this scenario.
A possible solution would be to change the COMObject.IUnknown_QueryInterface()
and COMObject.QueryInterface() methods so that they call __prepare_comobject()
again when they find an empty _com_pointers_ dictionary. In this way the
object can be used again even after the refcount has dropped to zero.
Jamie
--
Thanks,
Thomas
--
SOLARIS 10 is the OS for Data Centers - provides features such as DTrace,
Predictive Self Healing and Award Winning ZFS. Get Solaris 10 NOW
http://p.sf.net/sfu/solaris-dev2dev
___
comtypes-users mailing list
comtypes-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/comtypes-users