[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


Re: [comtypes-users] Problem calling method

2010-02-10 Thread Pablo Bianucci
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

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