예제 #1
0
        def _get_elements_raw(self, num_elements):
            """Returns a flat list or ndarray containing ALL elements in
            the safearray."""
            from comtypes.automation import VARIANT
            # XXX Not sure this is true:
            # For VT_UNKNOWN and VT_DISPATCH, we should retrieve the
            # interface iid by SafeArrayGetIID().
            ptr = POINTER(self._itemtype_)()  # container for the values
            _safearray.SafeArrayAccessData(self, byref(ptr))
            try:
                if self._itemtype_ == VARIANT:
                    # We have to loop over each item, so we get no
                    # speedup by creating an ndarray here.
                    return [i.value for i in ptr[:num_elements]]
                elif issubclass(self._itemtype_, POINTER(IUnknown)):
                    iid = _safearray.SafeArrayGetIID(self)
                    itf = com_interface_registry[str(iid)]
                    # COM interface pointers retrieved from array
                    # must be AddRef()'d if non-NULL.
                    elems = ptr[:num_elements]
                    result = []
                    # We have to loop over each item, so we get no
                    # speedup by creating an ndarray here.
                    for p in elems:
                        if bool(p):
                            p.AddRef()
                            result.append(p.QueryInterface(itf))
                        else:
                            # return a NULL-interface pointer.
                            result.append(POINTER(itf)())
                    return result
                else:
                    # If the safearray element are NOT native python
                    # objects, the containing safearray must be kept
                    # alive until all the elements are destroyed.
                    if not issubclass(self._itemtype_, Structure):
                        # Create an ndarray if requested. This is where
                        # we can get the most speed-up.
                        # XXX Only try to convert types known to
                        #     numpy.ctypeslib.
                        if (safearray_as_ndarray and self._itemtype_ in
                                numpy.ctypeslib._typecodes.values()):
                            arr = numpy.ctypeslib.as_array(ptr,
                                                           (num_elements,))
                            return arr.copy()
                        return ptr[:num_elements]

                    def keep_safearray(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)
예제 #2
0
        def _get_elements_raw(self, num_elements):
            """Returns a flat list containing ALL elements in the safearray."""
            from comtypes.automation import VARIANT
            # XXX Not sure this is true:
            # For VT_UNKNOWN and VT_DISPATCH, we should retrieve the
            # interface iid by SafeArrayGetIID().
            ptr = POINTER(self._itemtype_)()  # container for the values
            _safearray.SafeArrayAccessData(self, byref(ptr))
            try:
                if self._itemtype_ == VARIANT:
                    return [i.value for i in ptr[:num_elements]]
                elif issubclass(self._itemtype_, POINTER(IUnknown)):
                    iid = _safearray.SafeArrayGetIID(self)
                    itf = com_interface_registry[str(iid)]
                    # COM interface pointers retrieved from array
                    # must be AddRef()'d if non-NULL.
                    elems = ptr[:num_elements]
                    result = []
                    for p in elems:
                        if bool(p):
                            p.AddRef()
                            result.append(p.QueryInterface(itf))
                        else:
                            # return a NULL-interface pointer.
                            result.append(POINTER(itf)())
                    return result
                else:
                    # If the safearray element are NOT native python
                    # objects, the containing safearray must be kept
                    # alive until all the elements are destroyed.
                    if not issubclass(self._itemtype_, Structure):
                        # Creating and returning numpy arrays instead
                        # of Python tuple from a safearray is a lot faster,
                        # but only for large arrays because of a certain overhead.
                        # Also, for backwards compatibility, some clients expect
                        # a Python tuple - so there should be a way to select
                        # what should be returned.  How could that work?
                        ##                        # A hack which would return numpy arrays
                        ##                        # instead of Python lists.  To be effective,
                        ##                        # the result must not converted into a tuple
                        ##                        # in the caller so there must be changes as
                        ##                        # well!
                        ##
                        ##                        # Crude hack to create and attach an
                        ##                        # __array_interface__ property to the
                        ##                        # pointer instance
                        ##                        array_type = ptr._type_ * num_elements
                        ##                        if not hasattr(array_type, "__array_interface__"):
                        ##                            import numpy.ctypeslib
                        ##                            numpy.ctypeslib.prep_array(array_type)
                        ##                        # use the array_type's __array_interface__, ...
                        ##                        aif = array_type.__array_interface__.__get__(ptr)
                        ##                        # overwrite the 'data' member so that it points to the
                        ##                        # address we want to use
                        ##                        aif["data"] = (cast(ptr, c_void_p).value, False)
                        ##                        ptr.__array_interface__ = aif
                        ##                        return numpy.array(ptr, copy=True)
                        return ptr[:num_elements]

                    def keep_safearray(v):
                        v.__keepref = self
                        return v

                    return [keep_safearray(x) for x in ptr[:num_elements]]
            finally:
                _safearray.SafeArrayUnaccessData(self)