[python-win32] COM problem with SAFEARRAY type conversion

Mark Hammond mhammond@skippinet.com.au
Mon, 20 Jan 2003 10:37:09 +1100


> return self._ApplyTypes_(0x3, 1, (24, 0), ((16396, 1), (16396, 2),
> (16387, 2)), 'AusspielenAQL', None,p_PatternLine, p_pValue,
> p_plResult)

The numbers are:
(24, 0), ((16396, 1), (16396, 2), (16387, 2))

Return type (24,0), and a tuple of the args (3 in this case).

Each tuple is "param_type, param_flags"

24 = VT_VOID
16396 = VT_BYREF | VT_VARIANT - ie, a byref variant.

1 = PARAMFLAG_FIN, 2 = PARAMFLAG_FOUT

> - What does the magic numbers of the constants mean?
> - How can I verify which types are used?
> - If they are wrong, how can I modify it?

If it is wrong, then we have a bug reading the type information.  If the
type info is actually what is wrong, then that must be fixed.

> - Is something wrong with the interface declaration of the COM object?

I don't know, but arrays are hard, and we may not be covering all bases.

> _C++ client reference application:_
> An existing small C++ client application is the reference for
> using the
> COM Interface (see the code -> #C++_client). It sends string pattern
> line by line and shows the following correct results.
> Put an object on the stack with string pattern:
> io::PZGruppeOhneLED[type:: ProductCompilation][content::MatrixInit]
> gives back: 00000000
> Accessing the object on the stack with string pattern:
> content(Name)
> gives back the property, eg. Name: PZGruppeOhneLED
>
>
> _Python 2.22 (win32-all 152):_
> If I try the same with Python (dynamic or static binding
> doesn’t matter):
>
> class easyAql:
> def __init__(self):
> win32com.client.gencache.EnsureModule
> ('{987FCC41-EF6B-11D3-B21E-0050DA5E31BB}',0,1,0)
> aql = win32com.client.Dispatch('AMLAusspielen.AMLSteuerung')
>
> aql = easyAql()
> Input1 = (): Input2 = (): Output = (): Result = 0
> # declaring Output as string or unicode doesn’t matter
> Input1 =
> (("io::PZGruppeOhneLED[type::ProductCompilation][content::Matr
> ixInit]",),)
> Input2 = (("content(Name)",),)
> pz1 = aql.AusspielenAQL(myPatternLine1, myOutput, myResult)
> pz2 = aql.AusspielenAQL(myPatternLine2, myOutput, myResult)

Note that you do not need to present the last 2 params in this case.  This
is really a bug in win32com that we accept "out" params at all.  However, it
doesn't hurt.

> Returns:
> ((u'',), 1)
> ((u'',), 1)

These are the 2 "out" params we saw above.

> # Delivering the string pattern as a tuple of characters with dim and
> SAFEARRYBOUND returns the same result.
> # Declaring input as string doesn’t work, the code in
> oleargs.cpp seem
> to refuse it too,
> # oleargs.cpp line 491: OleSetTypeError("Objects for
> SAFEARRAYS must be
> sequences (of sequences), or a buffer object.")

This probably will have no effect.  The framework should be correctly
setting up an empty variant to pass to the function.

Regardless, we dont accept strings as safearrays, as a safe array of
characters is unlikely to be what you mean.

Eg:

SomeArrayFunc("foo")

Will *not* work directly from Python, as it is unlikely you really wanted
Python to auto-translate this to:

SomeArrayFunc( ("f", "o", "o"), )

> _C++ client reference application code:_
>
> COleVariant Input;
> COleVariant Output;
>
> // Wrap input for COM transactios
> SAFEARRAYBOUND Border = { aInputLine.GetSize(), 0};
> SAFEARRAY* paStringArray = SafeArrayCreate (VT_BSTR, 1, &Border);

Python will be creating a safe array of VT_VARIANT here, as it has no better
indication of the types (other than examining them at runtime, and I don't
think it desirable that Python's behaviour changes based purely on the input
params passed at runtime)

> for (LONG i = 0;i < aInputLine.GetSize(); i++)
> {
> SafeArrayPutElement( paStringArray, &i,
> (BSTR)(CComBSTR)aInputLine[i]);

Meaning each element of the array becomes its own VARIANT.

> Serverside COM application converts input variant in CstringArray and
> back in variant for output.

It seems to me that your code is more along the lines of SAFEARRAY(BSTR)
than a simple variant.  Can you change your C++ code to try more generic
arrays?

How does VB handle things?

Mark.