Re: [comtypes-users] comtypes and safearray of structs as out parameter

2009-09-09 Thread Eduardo Arias
 thanks for the detailed analysis and the clear explanation.  I've been
looking
 at the code and probably have another, even better, approach.
 
 The missing 'extra' parameter in the create(cls, value, extra=None)
implementaition
 in comtypes\safearray.py, line 62, that you retrieve from the 'value'
parameter
 is defined in an outer scope of this method, in line 44 in the enclosing
 '_make_safearray_type' function.  So it seems the easiest way to pass this
parameter
 to 'create(...)' is this simple patch:
 
 (...)

I've tried your approach and it works. You're right, your solution is
better, I did not see that the extra variable was bound in the
_make_safearray_type closure.

 This patch also has the advantage that you not only can pass a sequence
 of 'Pair' structures, in your case, as return value from your
ITest_Test(...)
 method, but you can also return simply a sequence of tuples like so:
 
  def ITest_Test(self, in, out):
return [(u'1', u'2'), (u'2', u'3')]

Right, that's how I wanted to write the return value originally, but because
I thought I needed to get a value for extra somehow, I had to return a list
of Pair instances.

Saludos,


--
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
___
comtypes-users mailing list
comtypes-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/comtypes-users


Re: [comtypes-users] comtypes and safearray of structs as out parameter

2009-09-09 Thread Thomas Heller
 So it seems the easiest way to pass this
 parameter
 to 'create(...)' is this simple patch:
 
 (...)
 
 I've tried your approach and it works. You're right, your solution is
 better, I did not see that the extra variable was bound in the
 _make_safearray_type closure.

Ok, I'll commit it into the repository and add some unittests for it.

  PS: Thinking about the code I'm wondering why I didn't use the outer
 definition
  of 'extra' in the create(...) method directly instead of passing it as a
 parameter...
 
 That could be another solution, to remove the 'extra' parameter from create
 (though I don't know whether someone may already be using it and this could
 break that code). Another one could be renaming the 'extra' parameter in
 create, and assign the bound 'extra' variable if None is provided as an
 argument (or filled in by the default value).

I'll leave this as it is to not break existing code.

-- 
Thanks,
Thomas


--
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with 
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
___
comtypes-users mailing list
comtypes-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/comtypes-users


Re: [comtypes-users] comtypes and safearray of structs as out parameter

2009-09-08 Thread Thomas Heller
Eduardo Arias schrieb:
 I've come into a problem when trying to implement an interface that has
 a single out parameter which happens to be a safearray of
 structs/VT_RECORD. I've been able to find a workaround to what looks
 like a limitation, which I'm submitting for your review.
 
 The interface I need to implement in Python receives a safearray of a
 Pair structs (defined below) and has a single out parameter which also
 provides a safearray of Pair structs.
 
   [
 uuid(41A8A003-C9FE-4ad8-866E-71CC5BAD0EA5)
   ]
   struct Pair {
 BSTR Key;
 BSTR Value;
   };
 
   [
 object,
 uuid(8232CB78-EEB8-4965-A275-2399F2EE497D),
 dual,
 nonextensible,
 helpstring(ITest Interface),
 pointer_default(unique)
   ]
   interface ITest : IDispatch{
 [id(1), helpstring(method Test)] HRESULT Test([in]
 SAFEARRAY(struct Pair) in, [out] SAFEARRAY(struct Pair)* out);
 
   };
 
 comtypes.client.GetModule generates the following code for the
 structure, that includes a _recordinfo_ member:
[...]
 
 The generated code for the interface is:
[...]
 
 The COM object that implements the interface tries to return a list of
 Pair objects:
 
   class Test(comtypes.COMObject):
 _com_interfaces_ = [test_tlb.ITest]
 
 # [id(1), helpstring(method Test)] HRESULT Test([in]
 SAFEARRAY(struct Pair) in, [out] SAFEARRAY(struct Pair)* out);
 def ITest_Test(self, in, out):
   l = []
   l.append(test_tlb.Pair(u'1', u'2'))
   l.append(test_tlb.Pair(u'2', u'3'))
   return l
 
 This triggers the following error:
 
   Traceback (most recent call last):
[...]
   TypeError: Cannot create SAFEARRAY type VT_RECORD without IRecordInfo.
 
  
 
 When _comobject.py tries to assign the method's return value to the
 single out argument:
 
 args[args_out_idx[0]][0] = result
 
 it ends up calling '__setitem__' which needs to create a saferray that
 contains the elements in the return value through the 'create' method:
 
 pa = self._type_.create(value)
 
 Then, because this is a safearray of structs, SafeArrayCreateVectorEx
 needs to receive an IRecordInfo interface to be able to allocate enough
 memory for the array elements:
 
 pa = _safearray.SafeArrayCreateVectorEx(cls._vartype_,
 0,
 len(value),
 extra)
 
 However, as shown in the call to create, no 'extra' parameter is
 specified and thus the call to SafeArrayCreateVectorEx fails.
 
 I've been able to workaround the issue by trying to obtain IRecordInfo
 inside the 'create' method, when no extra parameter is provided. Because
 the function will receive an array or container of the structs to be
 copied into the safearray, if there is at least one element in value, we
 can check whether it has a '_recordinfo_' member and, if that's
 available, use comtypes.typeinfo.GetRecordInfoFromGuids to obtain the
 missing IRecordInfo for SafeArrayCreateVectorEx.
 
 The change in comtypes/safearray.py is shown below (just before the call
 to SafeArrayCreateVectorEx).
 
 # (...)
 # try to obtain IRecordInfo if it's a SAFEARRAY struct of
 VT_RECORD and IRecordInfo
 # has not been provided through 'extra'. check whether an
 element in value contains
 # _recordinfo_ and if that's the case, use
 comtypes.typeinfo.GetRecordInfoFromGuids
 # to obtain IRecordInfo
 
 if cls._vartype_ == VT_RECORD and extra is None and
 len(value)  0 and hasattr(value[0], '_recordinfo_'):
 import comtypes.typeinfo
 extra =
 comtypes.typeinfo.GetRecordInfoFromGuids(*value[0]._recordinfo_)
 # For VT_UNKNOWN or VT_DISPATCH, extra must be a pointer to
 # the GUID of the interface.
 #
 
 # For VT_RECORD, extra must be a pointer to an IRecordInfo
 # describing the record.
 
 pa = _safearray.SafeArrayCreateVectorEx(cls._vartype_,
 0,
 len(value),
 extra)
 # (...)
 
  
 
 I'd like to know whether you think this approach is ok, or if there's
 any other way I'd have been able to have an out parameter provide a
 safearray of structs/VT_RECORD which doesn't require this change.

Eduardo,

thanks for the detailed analysis and the clear explanation.  I've been looking
at the code and probably have another, even better, approach.

The missing 'extra' parameter in the create(cls, value, extra=None) 
implementaition
in comtypes\safearray.py, line 62, that you retrieve from the 'value' parameter
is defined in an outer scope of