Re: [comtypes-users] Using a COMObject from a client more than once

2010-02-16 Thread Thomas Heller
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


[comtypes-users] Using a COMObject from a client more than once

2010-02-10 Thread James Teh
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.

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?
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.

Jamie

-- 
James Teh
Email/MSN Messenger/Jabber: ja...@jantrid.net
Web site: http://www.jantrid.net/


--
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