[comtypes-users] Using a COMObject from a client more than once
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
Re: [comtypes-users] Problem calling method
Hi Thomas! On Wed, Feb 10, 2010 at 05:42:51PM +0100, Thomas Heller wrote: Thanks for the reply! > Ok, the interface that you have is a pure dispinterface, which means that > all methods of the COM object are eventually called as IDispatch.Invoke() > calls. > > The Invoke() method packs all parameters into a DISPPARAM structure which > basically is an array of VARIANT instances. This explains the error that > you get - comtypes is trying to pack the POINTER parameter that you have > created into a VARIANT. This only works for 'automation-compatible' data > types > and your pointer is not one of those. Ok, that makes some sense. > I would guess that the 'mode_ptr' argument is an argument that must be passed > by reference (this is visual basic speak). Do you have sample VB code that > shows how this method is used? >From the documentation of this control, I get this prototype (I don't know if that's the right name): --- Function GetControlMode(lChanID As Long, plMode As Long) As Long Parameters lChanID - the channel identifier plMode - returns the control loop feedback status --- I found this other funcion, that seems similar and has a code example: --- Function GetMaxTravel(lChanID As Long, plMaxTravel As Long) As Long Parameters lChanID - the channel identifier plMaxTravel - returns the maximum travel (in microns) Example: Private Sub cmdGetTravel_Click() Dim sngMaxTravel As Single MG17Piezo1.GetMaxTravel CHAN1_ID, sngMaxTravel ' inform user of piezo max travel MsgBox "Maximum travel of piezo = " & sngMaxTravel --- Does this help? > However, it could be that comtypes is not able to call this method... I hope not! (crossing fingers... :-)) Bye & Good Luck! Pablo B. -- 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
Re: [comtypes-users] Problem calling method
Am 30.01.2010 06:23, schrieb Pablo Bianucci: > Hi! > > I am trying to use an ActiveX control (.OCX, from a piezo electric stage > controller)) from a Python program. I have managed to get the control to work, > but I am having problems calling a method. > > This is the method in question (from the autogenerated typelib): > > === >DISPMETHOD([dispid(20)], c_int, 'GetControlMode', >( [], c_int, 'lChanID' ), >( [], POINTER(c_int), 'plMode' )), > === > > This is what I am doing trying to use the method (it should give me an > integer): > > === > mode = 0 > mode_ptr = cast(mode, POINTER(c_int)) What you are doing here is that you create a NULL pointer - which is probably not what you want. But see below. > try: > piezo1.GetControlMode(APTPiezoLib.CHAN1_ID, mode_ptr) > except Exception, e: > print "Exception:", e > === > > And I get: > > === > Exception: Cannot put in > VARIANT > ===i > > I have no previous experience with comtypes or ctypes (or Win32 programming, > for that matter ;-)), so I might be doing something stupidly wrong. I've tried > all the permutations I could think of already, so I need expert help. Ok, the interface that you have is a pure dispinterface, which means that all methods of the COM object are eventually called as IDispatch.Invoke() calls. The Invoke() method packs all parameters into a DISPPARAM structure which basically is an array of VARIANT instances. This explains the error that you get - comtypes is trying to pack the POINTER parameter that you have created into a VARIANT. This only works for 'automation-compatible' data types and your pointer is not one of those. I would guess that the 'mode_ptr' argument is an argument that must be passed by reference (this is visual basic speak). Do you have sample VB code that shows how this method is used? However, it could be that comtypes is not able to call this method... 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