From 0681ffe78c4d23cab1a75da0f8620488c450849a Mon Sep 17 00:00:00 2001 From: mementum Date: Sat, 9 Apr 2016 11:21:21 +0200 Subject: [PATCH] Addresses #63 by unpacking VT_ARRAYs of VT_RECORDs --- comtypes/_safearray.py | 12 ++++++++++++ comtypes/automation.py | 27 +++++++++++++++++++++++++-- comtypes/safearray.py | 9 +++++++-- 3 files changed, 44 insertions(+), 4 deletions(-) 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)