SAFEARRAY(ISpecific*)* type in COM Automation from Python

Alex Martelli aleaxit at yahoo.com
Fri Apr 6 12:26:43 EDT 2001


"Putland, Karl" <KPutland at servicemagic.com> writes...:

> > I have to call a method on an Automation object that needs
> > a parameter of type SAFEARRAY(IFoo*), where IFoo is a (dual)
> > interface defined in that same type library.  I can make
    [snip]
> Bellow is a snipped dredged up from a Python
> COM server I wrote a while back.  I think
> you will find this helpful.  First create
> a collection, then wrap the collection.

But I shouldn't be passing a Collection -- rather, a
SAFEARRAY(IFoo*).  How would a Collection object help...?

Let me try to cut this down to a toy-sized example.
Say I have a server that implements the following
relevant part of an IDL file, with the 'obvious'
toy implementation:

 [
  object,
  uuid(8078B16D-2AA6-11D5-9E61-0060B0EB1D67),
  dual,
  helpstring("IFoo Interface"),
  pointer_default(unique)
 ]
 interface IFoo : IDispatch
 {
  [propget, id(1), helpstring("property TheString")] HRESULT
    TheString([out, retval] BSTR *pVal);
  [propput, id(1), helpstring("property TheString")] HRESULT
    TheString([in] BSTR newVal);
 };

 [
  object,
  uuid(8078B16F-2AA6-11D5-9E61-0060B0EB1D67),
  dual,
  helpstring("IFooMaker Interface"),
  pointer_default(unique)
 ]
 interface IFooMaker : IDispatch
 {
  [id(1), helpstring("method MakeFoo")] HRESULT
    MakeFoo([in]BSTR TheString, [out, retval]IFoo* *pVal);
 };

 [
  object,
  uuid(8078B173-2AA6-11D5-9E61-0060B0EB1D67),
  dual,
  helpstring("IDigester Interface"),
  pointer_default(unique)
 ]
 interface IDigester : IDispatch
 {
  [propget, id(1), helpstring("property Catenation")] HRESULT
    Catenation([out, retval] BSTR *pVal);
  [id(2), helpstring("method CatGeneric")] HRESULT
   CatGeneric([in]SAFEARRAY(VARIANT) *array, [out, retval] LONG* processed);
  [id(3), helpstring("method CatSpecific")] HRESULT
   CatSpecific([in]SAFEARRAY(IFoo*) *array, [out, retval] LONG* processed);
 };


Methods CatGeneric and CatSpecific of the Digester object are identical,
in fact their C++ implementations are:

STDMETHODIMP CDigester::CatGeneric(SAFEARRAY **array, LONG *processed)
{
    return aux(array, processed, this->Catenation);
}

STDMETHODIMP CDigester::CatSpecific(SAFEARRAY **array, LONG *processed)
{
    return aux(array, processed, this->Catenation);
}

for some appropriate auxiliary function aux that goes through
the array, etc, etc.


Now, in Python...:

D:\>python
Python 2.0 (#8, Oct 16 2000, 17:27:58) [MSC 32 bit (Intel)] on win32
Type "copyright", "credits" or "license" for more information.
>>> from win32com.client.gencache import EnsureDispatch as disp
>>> foomaker = disp('comtoy.FooMaker')
>>> dir(foomaker.__class__)
['CLSID', 'MakeFoo', '__doc__', '__module__', '_prop_map_get_',
'_prop_map_put_'
]
>>> a=foomaker.MakeFoo("uno")
>>> b=foomaker.MakeFoo("due")
>>> c=foomaker.MakeFoo("tre")
>>> foolist=[a,b,c]
>>> digester = disp('comtoy.Digester')
>>> dir(digester.__class__)
['CLSID', 'CatGeneric', 'CatSpecific', '__doc__', '__module__',
'_prop_map_get_'
, '_prop_map_put_']
>>> digester.CatGeneric(foolist)
3
>>> digester.CatSpecific(foolist)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File
"d:\python20\win32com\gen_py\8078B161-2AA6-11D5-9E61-0060B0EB1D67x0x1x0\I
Digester.py", line 34, in CatSpecific
    return self._oleobj_.InvokeTypes(0x3, LCID, 1, (3, 0), ((24585,
1),),array)
pywintypes.com_error: (-2147352571, 'Type mismatch.', None, 1)
>>>

i.e.: method CatGeneric is fine and peach; method CatSpecific, I
seem to be just unable to call -- there's a Type mismatch com_error
somewhere in the infrastructure.

How CAN I somehow massage the foolist in order to pass it to the
CatSpecific method...?  Because, in the actual server I must drive,
there IS no 'CatGeneric' equivalent...:-(


Alex






More information about the Python-list mailing list