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