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
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
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)