示例#1
0
def _make_safearray_type(itemtype):
    # Create and return a subclass of tagSAFEARRAY
    from comtypes.automation import _ctype_to_vartype, VT_RECORD, \
         VT_UNKNOWN, IDispatch, VT_DISPATCH

    meta = type(_safearray.tagSAFEARRAY)
    sa_type = meta.__new__(meta, "SAFEARRAY_%s" % itemtype.__name__,
                           (_safearray.tagSAFEARRAY, ), {})

    try:
        vartype = _ctype_to_vartype[itemtype]
        extra = None
    except KeyError:
        if issubclass(itemtype, Structure):
            try:
                guids = itemtype._recordinfo_
            except AttributeError:
                extra = None
            else:
                from comtypes.typeinfo import GetRecordInfoFromGuids
                extra = GetRecordInfoFromGuids(*guids)
            vartype = VT_RECORD
        elif issubclass(itemtype, POINTER(IDispatch)):
            vartype = VT_DISPATCH
            extra = pointer(itemtype._iid_)
        elif issubclass(itemtype, POINTER(IUnknown)):
            vartype = VT_UNKNOWN
            extra = pointer(itemtype._iid_)
        else:
            raise TypeError(itemtype)

    @Patch(POINTER(sa_type))
    class _(object):
        # Should explain the ideas how SAFEARRAY is used in comtypes
        _itemtype_ = itemtype  # a ctypes type
        _vartype_ = vartype  # a VARTYPE value: VT_...
        _needsfree = False

        @classmethod
        def create(cls, value, extra=None):
            """Create a POINTER(SAFEARRAY_...) instance of the correct
            type; value is an object containing the items to store.

            Python lists, tuples, and array.array instances containing
            compatible item types can be passed to create
            one-dimensional arrays.  To create multidimensional arrys,
            numpy arrays must be passed.
            """
            if npsupport.isndarray(value):
                return cls.create_from_ndarray(value, extra)

            # 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.

            # XXX How to specify the lbound (3. parameter to CreateVectorEx)?
            # XXX How to write tests for lbound != 0?
            pa = _safearray.SafeArrayCreateVectorEx(cls._vartype_, 0,
                                                    len(value), extra)
            if not pa:
                if cls._vartype_ == VT_RECORD and extra is None:
                    raise TypeError(
                        "Cannot create SAFEARRAY type VT_RECORD without IRecordInfo."
                    )
                # Hm, there may be other reasons why the creation fails...
                raise MemoryError()
            # We now have a POINTER(tagSAFEARRAY) instance which we must cast
            # to the correct type:
            pa = cast(pa, cls)
            # Now, fill the data in:
            ptr = POINTER(cls._itemtype_)()  # container for the values
            _safearray.SafeArrayAccessData(pa, byref(ptr))
            try:
                if isinstance(value, array.array):
                    addr, n = value.buffer_info()
                    nbytes = len(value) * sizeof(cls._itemtype_)
                    memmove(ptr, addr, nbytes)
                else:
                    for index, item in enumerate(value):
                        ptr[index] = item
            finally:
                _safearray.SafeArrayUnaccessData(pa)
            return pa

        @classmethod
        def create_from_ndarray(cls, value, extra, lBound=0):
            from comtypes.automation import VARIANT
            # If processing VARIANT, makes sure the array type is correct.
            if cls._itemtype_ is VARIANT:
                if value.dtype != npsupport.VARIANT_dtype:
                    value = _ndarray_to_variant_array(value)
            else:
                ai = value.__array_interface__
                if ai["version"] != 3:
                    raise TypeError(
                        "only __array_interface__ version 3 supported")
                if cls._itemtype_ != numpy.ctypeslib._typecodes[ai["typestr"]]:
                    raise TypeError("Wrong array item type")

            # SAFEARRAYs have Fortran order; convert the numpy array if needed
            if not value.flags.f_contiguous:
                value = numpy.array(value, order="F")

            # 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.
            rgsa = (_safearray.SAFEARRAYBOUND * value.ndim)()
            nitems = 1
            for i, d in enumerate(value.shape):
                nitems *= d
                rgsa[i].cElements = d
                rgsa[i].lBound = lBound
            pa = _safearray.SafeArrayCreateEx(
                cls._vartype_,
                value.ndim,  # cDims
                rgsa,  # rgsaBound
                extra)  # pvExtra
            if not pa:
                if cls._vartype_ == VT_RECORD and extra is None:
                    raise TypeError(
                        "Cannot create SAFEARRAY type VT_RECORD without IRecordInfo."
                    )
                # Hm, there may be other reasons why the creation fails...
                raise MemoryError()
            # We now have a POINTER(tagSAFEARRAY) instance which we must cast
            # to the correct type:
            pa = cast(pa, cls)
            # Now, fill the data in:
            ptr = POINTER(cls._itemtype_)()  # pointer to the item values
            _safearray.SafeArrayAccessData(pa, byref(ptr))
            try:
                nbytes = nitems * sizeof(cls._itemtype_)
                memmove(ptr, value.ctypes.data, nbytes)
            finally:
                _safearray.SafeArrayUnaccessData(pa)
            return pa

        @classmethod
        def from_param(cls, value):
            if not isinstance(value, cls):
                value = cls.create(value, extra)
                value._needsfree = True
            return value

        def __getitem__(self, index):
            # pparray[0] returns the whole array contents.
            if index != 0:
                raise IndexError("Only index 0 allowed")
            return self.unpack()

        def __setitem__(self, index, value):
            # XXX Need this to implement [in, out] safearrays in COM servers!
            ##            print "__setitem__", index, value
            raise TypeError("Setting items not allowed")

        def __ctypes_from_outparam__(self):
            self._needsfree = True
            return self[0]

        def __del__(self):
            if self._needsfree:
                _safearray.SafeArrayDestroy(self)

        def _get_size(self, dim):
            "Return the number of elements for dimension 'dim'"
            ub = _safearray.SafeArrayGetUBound(self, dim) + 1
            lb = _safearray.SafeArrayGetLBound(self, dim)
            return ub - lb

        def unpack(self):
            """Unpack a POINTER(SAFEARRAY_...) into a Python tuple or ndarray."""
            dim = _safearray.SafeArrayGetDim(self)

            if dim == 1:
                num_elements = self._get_size(1)
                result = self._get_elements_raw(num_elements)
                if safearray_as_ndarray:
                    import numpy
                    return numpy.asarray(result)
                return tuple(result)
            elif dim == 2:
                # get the number of elements in each dimension
                rows, cols = self._get_size(1), self._get_size(2)
                # get all elements
                result = self._get_elements_raw(rows * cols)
                # this must be reshaped and transposed because it is
                # flat, and in VB order
                if safearray_as_ndarray:
                    import numpy
                    return numpy.asarray(result).reshape((cols, rows)).T
                result = [tuple(result[r::rows]) for r in range(rows)]
                return tuple(result)
            else:
                lowerbounds = [
                    _safearray.SafeArrayGetLBound(self, d)
                    for d in range(1, dim + 1)
                ]
                indexes = (c_long * dim)(*lowerbounds)
                upperbounds = [
                    _safearray.SafeArrayGetUBound(self, d)
                    for d in range(1, dim + 1)
                ]
                row = self._get_row(0, indexes, lowerbounds, upperbounds)
                if safearray_as_ndarray:
                    import numpy
                    return numpy.asarray(row)
                return row

        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 list(
                                numpy.ctypeslib._typecodes.values())):
                            arr = numpy.ctypeslib.as_array(
                                ptr, (num_elements, ))
                            return arr.copy()
                        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)

        def _get_row(self, dim, indices, lowerbounds, upperbounds):
            # loop over the index of dimension 'dim'
            # we have to restore the index of the dimension we're looping over
            restore = indices[dim]

            result = []
            obj = self._itemtype_()
            pobj = byref(obj)
            if dim + 1 == len(indices):
                # It should be faster to lock the array and get a whole row at once?
                # How to calculate the pointer offset?
                for i in range(indices[dim], upperbounds[dim] + 1):
                    indices[dim] = i
                    _safearray.SafeArrayGetElement(self, indices, pobj)
                    result.append(obj.value)
            else:
                for i in range(indices[dim], upperbounds[dim] + 1):
                    indices[dim] = i
                    result.append(
                        self._get_row(dim + 1, indices, lowerbounds,
                                      upperbounds))
            indices[dim] = restore
            return tuple(result)  # for compatibility with pywin32.

    @Patch(POINTER(POINTER(sa_type)))
    class __(object):
        @classmethod
        def from_param(cls, value):
            if isinstance(value, cls._type_):
                return byref(value)
            return byref(cls._type_.create(value, extra))

        def __setitem__(self, index, value):
            # create an LP_SAFEARRAY_... instance
            pa = self._type_.create(value, extra)
            # XXX Must we destroy the currently contained data?
            # fill it into self
            super(POINTER(POINTER(sa_type)), self).__setitem__(index, pa)

    return sa_type
示例#2
0
def _make_safearray_type(itemtype):
    # Create and return a subclass of tagSAFEARRAY
    from comtypes.automation import _ctype_to_vartype, VT_RECORD, \
         VT_UNKNOWN, IDispatch, VT_DISPATCH

    meta = type(_safearray.tagSAFEARRAY)
    sa_type = meta.__new__(meta, "SAFEARRAY_%s" % itemtype.__name__,
                           (_safearray.tagSAFEARRAY, ), {})

    try:
        vartype = _ctype_to_vartype[itemtype]
        extra = None
    except KeyError:
        if issubclass(itemtype, Structure):
            try:
                guids = itemtype._recordinfo_
            except AttributeError:
                extra = None
            else:
                from comtypes.typeinfo import GetRecordInfoFromGuids
                extra = GetRecordInfoFromGuids(*guids)
            vartype = VT_RECORD
        elif issubclass(itemtype, POINTER(IDispatch)):
            vartype = VT_DISPATCH
            extra = pointer(itemtype._iid_)
        elif issubclass(itemtype, POINTER(IUnknown)):
            vartype = VT_UNKNOWN
            extra = pointer(itemtype._iid_)
        else:
            raise TypeError(itemtype)

    class _(partial, POINTER(sa_type)):
        # Should explain the ideas how SAFEARRAY is used in comtypes
        _itemtype_ = itemtype  # a ctypes type
        _vartype_ = vartype  # a VARTYPE value: VT_...
        _needsfree = False

        ##        @classmethod
        def create(cls, value, extra=None):
            """Create a POINTER(SAFEARRAY_...) instance of the correct
            type; value is an object containing the items to store.

            Python lists, tuples, and array.array instances containing
            compatible item types can be passed to create
            one-dimensional arrays.  To create multidimensional arrys,
            numpy arrays must be passed.
            """

            if "numpy" in sys.modules:
                numpy = sys.modules["numpy"]
                if isinstance(value, numpy.ndarray):
                    return cls.create_from_ndarray(value, extra)

            # 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.

            # XXX How to specify the lbound (3. parameter to CreateVectorEx)?
            # XXX How to write tests for lbound != 0?
            pa = _safearray.SafeArrayCreateVectorEx(cls._vartype_, 0,
                                                    len(value), extra)
            if not pa:
                if cls._vartype_ == VT_RECORD and extra is None:
                    raise TypeError(
                        "Cannot create SAFEARRAY type VT_RECORD without IRecordInfo."
                    )
                # Hm, there may be other reasons why the creation fails...
                raise MemoryError()
            # We now have a POINTER(tagSAFEARRAY) instance which we must cast
            # to the correct type:
            pa = cast(pa, cls)
            # Now, fill the data in:
            ptr = POINTER(cls._itemtype_)()  # container for the values
            _safearray.SafeArrayAccessData(pa, byref(ptr))
            try:
                if isinstance(value, array.array):
                    addr, n = value.buffer_info()
                    nbytes = len(value) * sizeof(cls._itemtype_)
                    memmove(ptr, addr, nbytes)
                else:
                    for index, item in enumerate(value):
                        ptr[index] = item
            finally:
                _safearray.SafeArrayUnaccessData(pa)
            return pa

        create = classmethod(create)

        ##        @classmethod
        def create_from_ndarray(cls, value, extra, lBound=0):
            #c:/python25/lib/site-packages/numpy/ctypeslib.py
            numpy = __import__("numpy.ctypeslib")

            # SAFEARRAYs have Fortran order; convert the numpy array if needed
            if not value.flags.f_contiguous:
                value = numpy.array(value, order="F")

            ai = value.__array_interface__
            if ai["version"] != 3:
                raise TypeError("only __array_interface__ version 3 supported")
            if cls._itemtype_ != numpy.ctypeslib._typecodes[ai["typestr"]]:
                raise TypeError("Wrong array item type")

            # 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.
            rgsa = (_safearray.SAFEARRAYBOUND * value.ndim)()
            nitems = 1
            for i, d in enumerate(value.shape):
                nitems *= d
                rgsa[i].cElements = d
                rgsa[i].lBound = lBound
            pa = _safearray.SafeArrayCreateEx(
                cls._vartype_,
                value.ndim,  # cDims
                rgsa,  # rgsaBound
                extra)  # pvExtra
            if not pa:
                if cls._vartype_ == VT_RECORD and extra is None:
                    raise TypeError(
                        "Cannot create SAFEARRAY type VT_RECORD without IRecordInfo."
                    )
                # Hm, there may be other reasons why the creation fails...
                raise MemoryError()
            # We now have a POINTER(tagSAFEARRAY) instance which we must cast
            # to the correct type:
            pa = cast(pa, cls)
            # Now, fill the data in:
            ptr = POINTER(cls._itemtype_)()  # pointer to the item values
            _safearray.SafeArrayAccessData(pa, byref(ptr))
            try:
                nbytes = nitems * sizeof(cls._itemtype_)
                memmove(ptr, value.ctypes.data, nbytes)
            finally:
                _safearray.SafeArrayUnaccessData(pa)
            return pa

        create_from_ndarray = classmethod(create_from_ndarray)

        ##        @classmethod
        def from_param(cls, value):
            if not isinstance(value, cls):
                value = cls.create(value, extra)
                value._needsfree = True
            return value

        from_param = classmethod(from_param)

        def __getitem__(self, index):
            # pparray[0] returns the whole array contents.
            if index != 0:
                raise IndexError("Only index 0 allowed")
            return self.unpack()

        def __setitem__(self, index, value):
            # XXX Need this to implement [in, out] safearrays in COM servers!
            ##            print "__setitem__", index, value
            raise TypeError("Setting items not allowed")

        def __ctypes_from_outparam__(self):
            self._needsfree = True
            return self[0]

        def __del__(self):
            if self._needsfree:
                _safearray.SafeArrayDestroy(self)

        def _get_size(self, dim):
            "Return the number of elements for dimension 'dim'"
            return _safearray.SafeArrayGetUBound(
                self, dim) + 1 - _safearray.SafeArrayGetLBound(self, dim)

        def unpack(self):
            """Unpack a POINTER(SAFEARRAY_...) into a Python tuple."""
            dim = _safearray.SafeArrayGetDim(self)

            if dim == 1:
                num_elements = self._get_size(1)
                return tuple(self._get_elements_raw(num_elements))
            elif dim == 2:
                # get the number of elements in each dimension
                rows, cols = self._get_size(1), self._get_size(2)
                # get all elements
                result = self._get_elements_raw(rows * cols)
                # transpose the result, because it is in VB order
                result = [tuple(result[r::rows]) for r in range(rows)]
                return tuple(result)
            else:
                lowerbounds = [
                    _safearray.SafeArrayGetLBound(self, d)
                    for d in range(1, dim + 1)
                ]
                indexes = (c_long * dim)(*lowerbounds)
                upperbounds = [
                    _safearray.SafeArrayGetUBound(self, d)
                    for d in range(1, dim + 1)
                ]
                return self._get_row(0, indexes, lowerbounds, upperbounds)

        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)

        def _get_row(self, dim, indices, lowerbounds, upperbounds):
            # loop over the index of dimension 'dim'
            # we have to restore the index of the dimension we're looping over
            restore = indices[dim]

            result = []
            obj = self._itemtype_()
            pobj = byref(obj)
            if dim + 1 == len(indices):
                # It should be faster to lock the array and get a whole row at once?
                # How to calculate the pointer offset?
                for i in range(indices[dim], upperbounds[dim] + 1):
                    indices[dim] = i
                    _safearray.SafeArrayGetElement(self, indices, pobj)
                    result.append(obj.value)
            else:
                for i in range(indices[dim], upperbounds[dim] + 1):
                    indices[dim] = i
                    result.append(
                        self._get_row(dim + 1, indices, lowerbounds,
                                      upperbounds))
            indices[dim] = restore
            return tuple(result)  # for compatibility with pywin32.

    class _(partial, POINTER(POINTER(sa_type))):

        ##        @classmethod
        def from_param(cls, value):
            if isinstance(value, cls._type_):
                return byref(value)
            return byref(cls._type_.create(value, extra))

        from_param = classmethod(from_param)

        def __setitem__(self, index, value):
            # create an LP_SAFEARRAY_... instance
            pa = self._type_.create(value, extra)
            # XXX Must we destroy the currently contained data?
            # fill it into self
            super(POINTER(POINTER(sa_type)), self).__setitem__(index, pa)

    return sa_type
示例#3
0
 def _set_value(self, value):
     _VariantClear(self)
     if value is None:
         self.vt = VT_NULL
     elif hasattr(value, '__len__') and len(value) == 0:
         self.vt = VT_NULL
     # since bool is a subclass of int, this check must come before
     # the check for int
     elif isinstance(value, bool):
         self.vt = VT_BOOL
         self._.VT_BOOL = value
     elif isinstance(value, (int, c_int)):
         self.vt = VT_I4
         self._.VT_I4 = value
     elif isinstance(value, long):
         u = self._
         # try VT_I4 first.
         u.VT_I4 = value
         if u.VT_I4 == value:
             # it did work.
             self.vt = VT_I4
             return
         # try VT_UI4 next.
         if value >= 0:
             u.VT_UI4 = value
             if u.VT_UI4 == value:
                 # did work.
                 self.vt = VT_UI4
                 return
         # try VT_I8 next.
         if value >= 0:
             u.VT_I8 = value
             if u.VT_I8 == value:
                 # did work.
                 self.vt = VT_I8
                 return
         # try VT_UI8 next.
         if value >= 0:
             u.VT_UI8 = value
             if u.VT_UI8 == value:
                 # did work.
                 self.vt = VT_UI8
                 return
         # VT_R8 is last resort.
         self.vt = VT_R8
         u.VT_R8 = float(value)
     elif isinstance(value, (float, c_double)):
         self.vt = VT_R8
         self._.VT_R8 = value
     elif isinstance(value, (str, unicode)):
         self.vt = VT_BSTR
         # do the c_wchar_p auto unicode conversion
         self._.c_void_p = _SysAllocStringLen(value, len(value))
     elif isinstance(value, datetime.datetime):
         delta = value - _com_null_date
         # a day has 24 * 60 * 60 = 86400 seconds
         com_days = delta.days + (delta.seconds +
                                  delta.microseconds * 1e-6) / 86400.
         self.vt = VT_DATE
         self._.VT_R8 = com_days
     elif npsupport.isdatetime64(value):
         com_days = value - npsupport.com_null_date64
         com_days /= npsupport.numpy.timedelta64(1, 'D')
         self.vt = VT_DATE
         self._.VT_R8 = com_days
     elif decimal is not None and isinstance(value, decimal.Decimal):
         self._.VT_CY = int(round(value * 10000))
         self.vt = VT_CY
     elif isinstance(value, POINTER(IDispatch)):
         CopyComPointer(value, byref(self._))
         self.vt = VT_DISPATCH
     elif isinstance(value, POINTER(IUnknown)):
         CopyComPointer(value, byref(self._))
         self.vt = VT_UNKNOWN
     elif isinstance(value, (list, tuple)):
         obj = _midlSAFEARRAY(VARIANT).create(value)
         memmove(byref(self._), byref(obj), sizeof(obj))
         self.vt = VT_ARRAY | obj._vartype_
     elif isinstance(value, array.array):
         vartype = _arraycode_to_vartype[value.typecode]
         typ = _vartype_to_ctype[vartype]
         obj = _midlSAFEARRAY(typ).create(value)
         memmove(byref(self._), byref(obj), sizeof(obj))
         self.vt = VT_ARRAY | obj._vartype_
     elif npsupport.isndarray(value):
         # Try to convert a simple array of basic types.
         descr = value.dtype.descr[0][1]
         typ = npsupport.numpy.ctypeslib._typecodes.get(descr)
         if typ is None:
             # Try for variant
             obj = _midlSAFEARRAY(VARIANT).create(value)
         else:
             obj = _midlSAFEARRAY(typ).create(value)
         memmove(byref(self._), byref(obj), sizeof(obj))
         self.vt = VT_ARRAY | obj._vartype_
     elif isinstance(value, Structure) and hasattr(value, "_recordinfo_"):
         guids = value._recordinfo_
         from comtypes.typeinfo import GetRecordInfoFromGuids
         ri = GetRecordInfoFromGuids(*guids)
         self.vt = VT_RECORD
         # Assigning a COM pointer to a structure field does NOT
         # call AddRef(), have to call it manually:
         ri.AddRef()
         self._.pRecInfo = ri
         self._.pvRecord = ri.RecordCreateCopy(byref(value))
     elif isinstance(getattr(value, "_comobj", None), POINTER(IDispatch)):
         CopyComPointer(value._comobj, byref(self._))
         self.vt = VT_DISPATCH
     elif isinstance(value, VARIANT):
         _VariantCopy(self, value)
     elif isinstance(value, c_ubyte):
         self._.VT_UI1 = value
         self.vt = VT_UI1
     elif isinstance(value, c_char):
         self._.VT_UI1 = ord(value.value)
         self.vt = VT_UI1
     elif isinstance(value, c_byte):
         self._.VT_I1 = value
         self.vt = VT_I1
     elif isinstance(value, c_ushort):
         self._.VT_UI2 = value
         self.vt = VT_UI2
     elif isinstance(value, c_short):
         self._.VT_I2 = value
         self.vt = VT_I2
     elif isinstance(value, c_uint):
         self.vt = VT_UI4
         self._.VT_UI4 = value
     elif isinstance(value, c_float):
         self.vt = VT_R4
         self._.VT_R4 = value
     elif isinstance(value, c_int64):
         self.vt = VT_I8
         self._.VT_I8 = value
     elif isinstance(value, c_uint64):
         self.vt = VT_UI8
         self._.VT_UI8 = value
     elif isinstance(value, _byref_type):
         ref = value._obj
         self._.c_void_p = addressof(ref)
         self.__keepref = value
         self.vt = _ctype_to_vartype[type(ref)] | VT_BYREF
     elif isinstance(value, _Pointer):
         ref = value.contents
         self._.c_void_p = addressof(ref)
         self.__keepref = value
         self.vt = _ctype_to_vartype[type(ref)] | VT_BYREF
     else:
         raise TypeError("Cannot put %r in VARIANT" % value)