diff --git a/comtypes/_safearray.py b/comtypes/_safearray.py index 76e41b9d..668d0731 100644 --- a/comtypes/_safearray.py +++ b/comtypes/_safearray.py @@ -69,6 +69,18 @@ def SafeArrayGetVartype(pa): _SafeArrayGetVartype(pa, result) return result.value +def SafeArrayGetRecordInfo(pa): + # Defined here to avoid a circular import + from comtypes.typeinfo import IRecordInfo + + _SafeArrayGetRecordInfo = _oleaut32.SafeArrayGetRecordInfo + _SafeArrayGetRecordInfo.restype = HRESULT + _SafeArrayGetRecordInfo.argtypes = [POINTER(SAFEARRAY), POINTER(POINTER(IRecordInfo))] + + result = POINTER(IRecordInfo)() + _SafeArrayGetRecordInfo(pa, byref(result)) + return result.value + SafeArrayGetElement = _oleaut32.SafeArrayGetElement SafeArrayGetElement.restype = HRESULT SafeArrayGetElement.argtypes = [POINTER(SAFEARRAY), POINTER(LONG), c_void_p] diff --git a/comtypes/automation.py b/comtypes/automation.py index 7b709826..32ed8c57 100644 --- a/comtypes/automation.py +++ b/comtypes/automation.py @@ -454,8 +454,31 @@ def _get_value(self, dynamic=False): return value elif self.vt & VT_ARRAY: - typ = _vartype_to_ctype[self.vt & ~VT_ARRAY] - return cast(self._.pparray, _midlSAFEARRAY(typ)).unpack() + try: + typ = _vartype_to_ctype[self.vt & ~VT_ARRAY] + return cast(self._.pparray, _midlSAFEARRAY(typ)).unpack() + except KeyError: + pass + + if self.vt & VT_RECORD: + from comtypes.client import GetModule + from comtypes.typeinfo import IRecordInfo + + # Get generic safearray and its IRecordInfo + ri0 = cast(self._.pparray, POINTER(_safearray.SAFEARRAY)) + ri1 = _safearray.SafeArrayGetRecordInfo(ri0) + # QUESTION: Do we need to add a ref ? + ri2 = ri1.QueryInterface(IRecordInfo) + + # Now containing typelib and through it the right class type + mod = GetModule(ri2.GetTypeInfo().GetContainingTypeLib()[0]) + ricls = getattr(mod, ri2.GetName()) + + # Cast the array to the right safearray(type), unpack -> return + return cast(self._.pparray, _midlSAFEARRAY(ricls)).unpack() + + # Else we cannot unpack the array + raise NotImplementedError("typecode %d = 0x%x)" % (vt, vt)) else: raise NotImplementedError("typecode %d = 0x%x)" % (vt, vt)) diff --git a/comtypes/safearray.py b/comtypes/safearray.py index bef10137..7881c2fe 100644 --- a/comtypes/safearray.py +++ b/comtypes/safearray.py @@ -315,8 +315,13 @@ def _get_elements_raw(self, num_elements): return ptr[:num_elements] def keep_safearray(v): - v.__keepref = self - return v + # Simply keeping a reference to self does not keep the + # internal addresses of BSTR safe and strings will be + # overwritten. A copy of the bytes solves the problem + v1 = v.__class__() + memmove(byref(v1), byref(v), sizeof(v)) + return v1 + return [keep_safearray(x) for x in ptr[:num_elements]] finally: _safearray.SafeArrayUnaccessData(self)