def test_keepalive_temp_buffer(self): """ DLLEXPORT char* do_nothing(char* s) { return s; } """ from _rawffi.alt import CDLL, types import _rawffi libfoo = CDLL(self.libfoo_name) do_nothing = libfoo.getfunc('do_nothing', [types.char_p], types.char_p) CharArray = _rawffi.Array('c') # ptr = do_nothing('foobar') array = CharArray.fromaddress(ptr, 7) assert list(array) == list('foobar\00') do_nothing.free_temp_buffers()
def _wrap_result(self, restype, result): """ Convert from low-level repr of the result to the high-level python one. """ # hack for performance: if restype is a "simple" primitive type, don't # allocate the buffer because it's going to be thrown away immediately if self._is_primitive(restype) and not restype._is_pointer_like(): return result # shape = restype._ffishape if is_struct_shape(shape): buf = result else: buf = _rawffi.Array(shape)(1, autofree=True) buf[0] = result retval = restype._CData_retval(buf) return retval
def set_type(self, TP): if self._is_abstract(): raise TypeError('abstract class') ffiarray = _rawffi.Array('P') def __init__(self, value=None): if not hasattr(self, '_buffer'): self._buffer = ffiarray(1, autofree=True) if value is not None: self.contents = value def _init_no_arg_(self): self._buffer = ffiarray(1, autofree=True) self._ffiarray = ffiarray self.__init__ = __init__ self._init_no_arg_ = _init_no_arg_ self._type_ = TP
def test_nested_structures(self): import _rawffi S1 = _rawffi.Structure([('a', 'i'), ('b', 'P'), ('c', 'c')]) S = _rawffi.Structure([('x', 'c'), ('s1', (S1, 1))]) assert S.size == S1.alignment + S1.size assert S.alignment == S1.alignment assert S.fieldoffset('x') == 0 assert S.fieldoffset('s1') == S1.alignment s = S() s.x = b'G' raises(TypeError, 's.s1') assert s.fieldaddress('s1') == s.buffer + S.fieldoffset('s1') s1 = S1.fromaddress(s.fieldaddress('s1')) s1.c = b'H' rawbuf = _rawffi.Array('c').fromaddress(s.buffer, S.size) assert rawbuf[0] == b'G' assert rawbuf[S1.alignment + S1.fieldoffset('c')] == b'H' s.free()
def test_array(self): import _rawffi lib = _rawffi.CDLL(self.lib_name) A = _rawffi.Array('i') get_array_elem = lib.ptr('get_array_elem', ['P', 'i'], 'i') a = A(10) a[8] = 3 a[7] = 1 a[6] = 2 arg1 = a.byptr() arg2 = A(1) for i, expected in enumerate([0, 0, 0, 0, 0, 0, 2, 1, 3, 0]): arg2[0] = i res = get_array_elem(arg1, arg2) assert res[0] == expected arg1.free() arg2.free() assert a[3] == 0 a.free()
def test_raw_callable(self): import _rawffi lib = _rawffi.CDLL(self.lib_name) get_raw_pointer = lib.ptr('get_raw_pointer', [], 'P') ptr = get_raw_pointer() rawcall = _rawffi.FuncPtr(ptr[0], ['h', 'h'], 'H') A = _rawffi.Array('h') arg1 = A(1) arg2 = A(1) arg1[0] = 1 arg2[0] = 2 res = rawcall(arg1, arg2) assert res[0] == 3 arg1.free() arg2.free() assert rawcall.buffer == ptr[0] ptr = rawcall.byptr() assert ptr[0] == rawcall.buffer ptr.free()
def test_wcharp2rawunicode(self): import _rawffi A = _rawffi.Array('i') arg = A(1) arg[0] = 0x1234 u = _rawffi.wcharp2rawunicode(arg.itemaddress(0)) assert u == u'\u1234' u = _rawffi.wcharp2rawunicode(arg.itemaddress(0), 1) assert u == u'\u1234' arg[0] = -1 if _rawffi.sizeof('u') == 4: raises(ValueError, _rawffi.wcharp2rawunicode, arg.itemaddress(0)) raises(ValueError, _rawffi.wcharp2rawunicode, arg.itemaddress(0), 1) arg[0] = 0x110000 raises(ValueError, _rawffi.wcharp2rawunicode, arg.itemaddress(0)) raises(ValueError, _rawffi.wcharp2rawunicode, arg.itemaddress(0), 1) arg.free()
def test_variadic_sum(self): import _rawffi lib = _rawffi.CDLL(self.lib_name) A = _rawffi.Array('l') n = A(1) arg1 = A(1) arg2 = A(1) n[0] = 2 arg1[0] = 3 arg2[0] = 15 variadic_sum = lib.ptr('variadic_sum', ['l', 'l', 'l'], 'l', variadic_args=2) res = variadic_sum(n, arg1, arg2) assert res[0] == 3 + 15 arg1.free() arg2.free() n.free()
def test_buffer(self): import _rawffi S = _rawffi.Structure((40, 1)) s = S(autofree=True) b = buffer(s) assert len(b) == 40 b[4] = 'X' b[:3] = 'ABC' assert b[:6] == 'ABC\x00X\x00' A = _rawffi.Array('c') a = A(10, autofree=True) a[3] = 'x' b = buffer(a) assert len(b) == 10 assert b[3] == 'x' b[6] = 'y' assert a[6] == 'y' b[3:5] = 'zt' assert a[3] == 'z' assert a[4] == 't'
def test_returning_str(self): import _rawffi lib = _rawffi.CDLL(self.lib_name) char_check = lib.ptr('char_check', ['c', 'c'], 's') A = _rawffi.Array('c') arg1 = A(1) arg2 = A(1) arg1[0] = 'y' arg2[0] = 'x' res = char_check(arg1, arg2) assert _rawffi.charp2string(res[0]) == 'xxxxxx' assert _rawffi.charp2rawstring(res[0]) == 'xxxxxx' assert _rawffi.charp2rawstring(res[0], 3) == 'xxx' a = A(6, 'xx\x00\x00xx') assert _rawffi.charp2string(a.buffer) == 'xx' assert _rawffi.charp2rawstring(a.buffer, 4) == 'xx\x00\x00' arg1[0] = 'x' arg2[0] = 'y' res = char_check(arg1, arg2) assert res[0] == 0 assert _rawffi.charp2string(res[0]) is None arg1.free() arg2.free()
def test_convert_strings_to_char_p(self): """ long mystrlen(char* s) { long len = 0; while(*s++) len++; return len; } """ from _ffi import CDLL, types import _rawffi libfoo = CDLL(self.libfoo_name) mystrlen = libfoo.getfunc('mystrlen', [types.char_p], types.slong) # # first, try automatic conversion from a string assert mystrlen('foobar') == 6 # then, try to pass an explicit pointer CharArray = _rawffi.Array('c') mystr = CharArray(7, 'foobar') assert mystrlen(mystr.buffer) == 6 mystr.free() mystrlen.free_temp_buffers()
def __new__(self, name, bases, dct): try: tp = dct['_type_'] except KeyError: for base in bases: if hasattr(base, '_type_'): tp = base._type_ break else: raise AttributeError("cannot find _type_ attribute") if (not isinstance(tp, str) or not len(tp) == 1 or tp not in SIMPLE_TYPE_CHARS): raise ValueError('%s is not a type character' % (tp)) default = TP_TO_DEFAULT[tp] ffiarray = _rawffi.Array(tp) result = type.__new__(self, name, bases, dct) result._ffiargshape = tp result._ffishape = tp result._fficompositesize = None result._ffiarray = ffiarray if tp == 'z': # c_char_p from _ctypes import Array, _Pointer def _getvalue(self): addr = self._buffer[0] if addr == 0: return None else: return _rawffi.charp2string(addr) def _setvalue(self, value): if isinstance(value, basestring): if isinstance(value, unicode): value = value.encode(ConvMode.encoding, ConvMode.errors) #self._objects = value array = _rawffi.Array('c')(len(value)+1, value) value = array.buffer self._objects = {'0': CArgObject(array)} elif value is None: value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) elif tp == 'Z': # c_wchar_p from _ctypes import Array, _Pointer, _wstring_at_addr def _getvalue(self): addr = self._buffer[0] if addr == 0: return None else: return _wstring_at_addr(addr, -1) def _setvalue(self, value): if isinstance(value, basestring): if isinstance(value, str): value = value.decode(ConvMode.encoding, ConvMode.errors) #self._objects = value array = _rawffi.Array('u')(len(value)+1, value) value = array.buffer self._objects = {'0': CArgObject(array)} elif value is None: value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) elif tp == 'P': # c_void_p def _getvalue(self): addr = self._buffer[0] if addr == 0: return None return addr def _setvalue(self, value): if isinstance(value, str): array = _rawffi.Array('c')(len(value)+1, value) value = array.buffer self._objects = {'0': CArgObject(array)} elif value is None: value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) if tp in 'zZ': from _ctypes import Array, _Pointer # c_char_p def from_param(self, value): res = generic_xxx_p_from_param(self, value) if res is not None: return res if isinstance(value, (Array, _Pointer)): from ctypes import c_char, c_byte, c_wchar if type(value)._type_ in [c_char, c_byte, c_wchar]: return value return SimpleType.from_param(self, value) result.from_param = classmethod(from_param) elif tp == 'P': from _ctypes import Array, _Pointer # c_void_p def from_param(self, value): res = generic_xxx_p_from_param(self, value) if res is not None: return res if isinstance(value, Array): return value if isinstance(value, _Pointer): return self.from_address(value._buffer.buffer) return SimpleType.from_param(self, value) result.from_param = classmethod(from_param) elif tp == 'u': def _setvalue(self, val): if isinstance(val, str): val = val.decode(ConvMode.encoding, ConvMode.errors) # possible if we use 'ignore' if val: self._buffer[0] = val def _getvalue(self): return self._buffer[0] result.value = property(_getvalue, _setvalue) elif tp == 'c': def _setvalue(self, val): if isinstance(val, unicode): val = val.encode(ConvMode.encoding, ConvMode.errors) if val: self._buffer[0] = val def _getvalue(self): return self._buffer[0] result.value = property(_getvalue, _setvalue) elif tp == 'O': def _setvalue(self, val): num = pyobj_container.add(val) self._buffer[0] = num def _getvalue(self): return pyobj_container.get(self._buffer[0]) result.value = property(_getvalue, _setvalue) return result
def _subarray(self, fieldtype, name): """Return a _rawffi array of length 1 whose address is the same as the address of the field 'name' of self.""" address = self._buffer.fieldaddress(name) A = _rawffi.Array(fieldtype._ffishape_) return A.fromaddress(address, 1)
def __new__(self, name, bases, dct): try: tp = dct['_type_'] except KeyError: for base in bases: if hasattr(base, '_type_'): tp = base._type_ break else: raise AttributeError("cannot find _type_ attribute") if (not isinstance(tp, str) or not len(tp) == 1 or tp not in SIMPLE_TYPE_CHARS): raise ValueError('%s is not a type character' % (tp)) default = TP_TO_DEFAULT[tp] ffiarray = _rawffi.Array(tp) result = type.__new__(self, name, bases, dct) result._ffiargshape = tp result._ffishape = tp result._fficompositesize = None result._ffiarray = ffiarray if tp == 'z': # c_char_p def _getvalue(self): addr = self._buffer[0] if addr == 0: return None else: return _rawffi.charp2string(addr) def _setvalue(self, value): if isinstance(value, basestring): if isinstance(value, unicode): value = value.encode(ConvMode.encoding, ConvMode.errors) #self._objects = value array = _rawffi.Array('c')(len(value) + 1, value) self._objects = CArgObject(value, array) value = array.buffer elif value is None: value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) elif tp == 'Z': # c_wchar_p def _getvalue(self): addr = self._buffer[0] if addr == 0: return None else: return _rawffi.wcharp2unicode(addr) def _setvalue(self, value): if isinstance(value, basestring): if isinstance(value, str): value = value.decode(ConvMode.encoding, ConvMode.errors) #self._objects = value array = _rawffi.Array('u')(len(value) + 1, value) self._objects = CArgObject(value, array) value = array.buffer elif value is None: value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) elif tp == 'P': # c_void_p def _getvalue(self): addr = self._buffer[0] if addr == 0: return None return addr def _setvalue(self, value): if isinstance(value, str): array = _rawffi.Array('c')(len(value) + 1, value) self._objects = CArgObject(value, array) value = array.buffer elif value is None: value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) elif tp == 'u': def _setvalue(self, val): if isinstance(val, str): val = val.decode(ConvMode.encoding, ConvMode.errors) # possible if we use 'ignore' if val: self._buffer[0] = val def _getvalue(self): return self._buffer[0] result.value = property(_getvalue, _setvalue) elif tp == 'c': def _setvalue(self, val): if isinstance(val, unicode): val = val.encode(ConvMode.encoding, ConvMode.errors) if val: self._buffer[0] = val def _getvalue(self): return self._buffer[0] result.value = property(_getvalue, _setvalue) elif tp == 'O': def _setvalue(self, val): num = pyobj_container.add(val) self._buffer[0] = num def _getvalue(self): return pyobj_container.get(self._buffer[0]) result.value = property(_getvalue, _setvalue) elif tp == 'X': from ctypes import windll SysAllocStringLen = windll.oleaut32.SysAllocStringLen SysStringLen = windll.oleaut32.SysStringLen SysFreeString = windll.oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: return None else: size = SysStringLen(addr) return _rawffi.wcharp2rawunicode(addr, size) def _setvalue(self, value): if isinstance(value, basestring): if isinstance(value, str): value = value.decode(ConvMode.encoding, ConvMode.errors) array = _rawffi.Array('u')(len(value) + 1, value) value = SysAllocStringLen(array.buffer, len(value)) elif value is None: value = 0 if self._buffer[0]: SysFreeString(self._buffer[0]) self._buffer[0] = value result.value = property(_getvalue, _setvalue) elif tp == 'v': # VARIANT_BOOL type def _getvalue(self): return bool(self._buffer[0]) def _setvalue(self, value): if value: self._buffer[0] = -1 # VARIANT_TRUE else: self._buffer[0] = 0 # VARIANT_FALSE result.value = property(_getvalue, _setvalue) return result
def __init__(self, *args): self.name = None self._objects = {keepalive_key(0): self} self._needs_free = True # Empty function object -- this is needed for casts if not args: self._buffer = _rawffi.Array('P')(1) return argsl = list(args) argument = argsl.pop(0) # Direct construction from raw address if isinstance(argument, (int, long)) and not argsl: ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) self._ptr = _rawffi.FuncPtr(argument, ffiargs, ffires, self._flags_) self._buffer = self._ptr.byptr() return # A callback into Python if callable(argument) and not argsl: self.callable = argument ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) if self._restype_ is None: ffires = None self._ptr = _rawffi.CallbackPtr( self._wrap_callable(argument, self.argtypes), ffiargs, ffires, self._flags_) self._buffer = self._ptr.byptr() return # Function exported from a shared library if isinstance(argument, tuple) and len(argument) == 2: import ctypes self.name, dll = argument if isinstance(dll, str): self.dll = ctypes.CDLL(dll) else: self.dll = dll if argsl: self.paramflags = argsl.pop(0) if argsl: raise TypeError("Unknown constructor %s" % (args, )) # We need to check dll anyway ptr = self._getfuncptr([], ctypes.c_int) self._buffer = ptr.byptr() return # A COM function call, by index if (sys.platform == 'win32' and isinstance(argument, (int, long)) and argsl): ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) self._com_index = argument + 0x1000 self.name = argsl.pop(0) if argsl: self.paramflags = argsl.pop(0) if argsl: self._com_iid = argsl.pop(0) if argsl: raise TypeError("Unknown constructor %s" % (args, )) return raise TypeError("Unknown constructor %s" % (args, ))
def __new__(self, name, bases, dct): try: tp = dct['_type_'] except KeyError: for base in bases: if hasattr(base, '_type_'): tp = base._type_ break else: raise AttributeError("cannot find _type_ attribute") if tp == 'abstract': tp = 'i' if (not isinstance(tp, str) or not len(tp) == 1 or tp not in SIMPLE_TYPE_CHARS): raise ValueError('%s is not a type character' % (tp)) default = TP_TO_DEFAULT[tp] ffiarray = _rawffi.Array(tp) result = type.__new__(self, name, bases, dct) result._ffiargshape_ = tp result._ffishape_ = tp result._fficompositesize_ = None result._ffiarray = ffiarray if tp in CTYPES_TO_PEP3118_TABLE: pep_code = CTYPES_TO_PEP3118_TABLE[tp][_rawffi.sizeof(tp)] else: pep_code = tp result._format = byteorder[sys.byteorder] + pep_code if tp == 'z': # c_char_p def _getvalue(self): addr = self._buffer[0] if addr == 0: return None else: return _rawffi.charp2string(addr) def _setvalue(self, value): if isinstance(value, basestring): if isinstance(value, unicode): value = value.encode(ConvMode.encoding, ConvMode.errors) #self._objects = value array = _rawffi.Array('c')(len(value) + 1, value) self._objects = CArgObject(value, array) value = array.buffer elif value is None: value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) result._ffiargtype = _ffi.types.Pointer(_ffi.types.char) elif tp == 'Z': # c_wchar_p def _getvalue(self): addr = self._buffer[0] if addr == 0: return None else: return _rawffi.wcharp2unicode(addr) def _setvalue(self, value): if isinstance(value, basestring): if isinstance(value, str): value = value.decode(ConvMode.encoding, ConvMode.errors) #self._objects = value array = _rawffi.Array('u')(len(value) + 1, value) self._objects = CArgObject(value, array) value = array.buffer elif value is None: value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) result._ffiargtype = _ffi.types.Pointer(_ffi.types.unichar) elif tp == 'P': # c_void_p def _getvalue(self): addr = self._buffer[0] if addr == 0: return None return addr def _setvalue(self, value): if isinstance(value, str): array = _rawffi.Array('c')(len(value) + 1, value) self._objects = CArgObject(value, array) value = array.buffer elif value is None: value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) elif tp == 'u': def _setvalue(self, val): if isinstance(val, str): val = val.decode(ConvMode.encoding, ConvMode.errors) # possible if we use 'ignore' if val: self._buffer[0] = val def _getvalue(self): return self._buffer[0] result.value = property(_getvalue, _setvalue) elif tp == 'c': def _setvalue(self, val): if isinstance(val, unicode): val = val.encode(ConvMode.encoding, ConvMode.errors) if val: self._buffer[0] = val def _getvalue(self): return self._buffer[0] result.value = property(_getvalue, _setvalue) elif tp == 'O': def _setvalue(self, val): num = pyobj_container.add(val) self._buffer[0] = num def _getvalue(self): return pyobj_container.get(self._buffer[0]) result.value = property(_getvalue, _setvalue) elif tp == 'X': from ctypes import WinDLL # Use WinDLL("oleaut32") instead of windll.oleaut32 # because the latter is a shared (cached) object; and # other code may set their own restypes. We need out own # restype here. oleaut32 = WinDLL("oleaut32") SysAllocStringLen = oleaut32.SysAllocStringLen SysStringLen = oleaut32.SysStringLen SysFreeString = oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: return None else: size = SysStringLen(addr) return _rawffi.wcharp2rawunicode(addr, size) def _setvalue(self, value): if isinstance(value, basestring): if isinstance(value, str): value = value.decode(ConvMode.encoding, ConvMode.errors) array = _rawffi.Array('u')(len(value) + 1, value) value = SysAllocStringLen(array.buffer, len(value)) elif value is None: value = 0 if self._buffer[0]: SysFreeString(self._buffer[0]) self._buffer[0] = value result.value = property(_getvalue, _setvalue) elif tp == '?': # regular bool def _getvalue(self): return bool(self._buffer[0]) def _setvalue(self, value): self._buffer[0] = bool(value) result.value = property(_getvalue, _setvalue) elif tp == 'v': # VARIANT_BOOL type def _getvalue(self): return bool(self._buffer[0]) def _setvalue(self, value): if value: self._buffer[0] = -1 # VARIANT_TRUE else: self._buffer[0] = 0 # VARIANT_FALSE result.value = property(_getvalue, _setvalue) # make pointer-types compatible with the _ffi fast path if result._is_pointer_like(): def _as_ffi_pointer_(self, ffitype): return as_ffi_pointer(self, ffitype) result._as_ffi_pointer_ = _as_ffi_pointer_ if name[-2:] != '_p' and name[-3:] not in ('_le', '_be') \ and name not in ('c_wchar', '_SimpleCData', 'c_longdouble', 'c_bool', 'py_object'): if sys.byteorder == 'big': name += '_le' swapped = self.__new__(self, name, bases, dct) result.__ctype_le__ = swapped result.__ctype_be__ = result swapped.__ctype_be__ = result swapped.__ctype_le__ = swapped swapped._format = '<' + pep_code else: name += '_be' swapped = self.__new__(self, name, bases, dct) result.__ctype_be__ = swapped result.__ctype_le__ = result swapped.__ctype_le__ = result swapped.__ctype_be__ = swapped swapped._format = '>' + pep_code from _ctypes import sizeof def _getval(self): return swap_bytes(self._buffer[0], sizeof(self), name, 'get') def _setval(self, value): d = result() d.value = value self._buffer[0] = swap_bytes(d.value, sizeof(self), name, 'set') swapped.value = property(_getval, _setval) return result
class CFuncPtr(_CData): __metaclass__ = CFuncPtrType _argtypes_ = None _restype_ = None _flags_ = 0 _ffiargshape = 'P' _ffishape = 'P' _fficompositesize = None _ffiarray = _rawffi.Array('P') _needs_free = False callable = None _ptr = None _buffer = None # win32 COM properties _paramflags = None _com_index = None _com_iid = None def _getargtypes(self): return self._argtypes_ def _setargtypes(self, argtypes): self._ptr = None self._argtypes_ = argtypes argtypes = property(_getargtypes, _setargtypes) def _getrestype(self): return self._restype_ def _setrestype(self, restype): self._ptr = None from ctypes import c_char_p if restype is int: from ctypes import c_int restype = c_int if not isinstance(restype, _CDataMeta) and not restype is None and \ not callable(restype): raise TypeError("Expected ctypes type, got %s" % (restype, )) self._restype_ = restype def _delrestype(self): self._ptr = None del self._restype_ restype = property(_getrestype, _setrestype, _delrestype) def _ffishapes(self, args, restype): argtypes = [arg._ffiargshape for arg in args] if restype is not None: restype = restype._ffiargshape else: restype = 'O' # void return argtypes, restype def __init__(self, *args): self.name = None self._objects = {keepalive_key(0): self} self._needs_free = True argument = None if len(args) == 1: argument = args[0] if isinstance(argument, (int, long)): # direct construction from raw address ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) self._ptr = _rawffi.FuncPtr(argument, ffiargs, ffires, self._flags_) self._buffer = self._ptr.byptr() elif callable(argument): # A callback into python self.callable = argument ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) self._ptr = _rawffi.CallbackPtr( self._wrap_callable(argument, self.argtypes), ffiargs, ffires, self._flags_) self._buffer = self._ptr.byptr() elif isinstance(argument, tuple) and len(argument) == 2: # function exported from a shared library import ctypes self.name, self.dll = argument if isinstance(self.dll, str): self.dll = ctypes.CDLL(self.dll) # we need to check dll anyway ptr = self._getfuncptr([], ctypes.c_int) self._buffer = ptr.byptr() elif (sys.platform == 'win32' and len(args) >= 2 and isinstance(args[0], (int, long))): # A COM function call, by index ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) self._com_index = args[0] + 0x1000 self.name = args[1] if len(args) > 2: self._paramflags = args[2] # XXX ignored iid = args[3] elif len(args) == 0: # Empty function object. # this is needed for casts self._buffer = _rawffi.Array('P')(1) return else: raise TypeError("Unknown constructor %s" % (args, )) def _wrap_callable(self, to_call, argtypes): def f(*args): if argtypes: args = [ argtype._CData_retval(argtype.from_address(arg)._buffer) for argtype, arg in zip(argtypes, args) ] return to_call(*args) return f def __call__(self, *args): if self.callable is not None: try: res = self.callable(*args) except: exc_info = sys.exc_info() traceback.print_tb(exc_info[2], file=sys.stderr) print >> sys.stderr, "%s: %s" % (exc_info[0].__name__, exc_info[1]) return 0 if self._restype_ is not None: return res return argtypes = self._argtypes_ if self._com_index: from ctypes import cast, c_void_p, POINTER thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents argtypes = [c_void_p] + list(argtypes) args = list(args) args[0] = args[0].value else: thisarg = None if argtypes is None: argtypes = self._guess_argtypes(args) argtypes, argsandobjs = self._wrap_args(argtypes, args) restype = self._restype_ funcptr = self._getfuncptr(argtypes, restype, thisarg) resbuffer = funcptr(*[arg._buffer for _, arg in argsandobjs]) return self._build_result(restype, resbuffer, argtypes, argsandobjs) def _getfuncptr(self, argtypes, restype, thisarg=None): if self._ptr is not None: return self._ptr if restype is None or not isinstance(restype, _CDataMeta): import ctypes restype = ctypes.c_int argshapes = [arg._ffiargshape for arg in argtypes] resshape = restype._ffiargshape if self._buffer is not None: ptr = _rawffi.FuncPtr(self._buffer[0], argshapes, resshape, self._flags_) if argtypes is self._argtypes_: self._ptr = ptr return ptr if self._com_index: # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") ptr = thisarg[self._com_index - 0x1000] return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) cdll = self.dll._handle try: return cdll.ptr(self.name, argshapes, resshape, self._flags_) except AttributeError: if self._flags_ & _rawffi.FUNCFLAG_CDECL: raise # For stdcall, try mangled names: # funcname -> _funcname@<n> # where n is 0, 4, 8, 12, ..., 128 for i in range(33): mangled_name = "_%s@%d" % (self.name, i * 4) try: return cdll.ptr(mangled_name, argshapes, resshape, self._flags_) except AttributeError: pass raise @staticmethod def _guess_argtypes(args): from _ctypes import _CData from ctypes import c_char_p, c_wchar_p, c_void_p, c_int from ctypes import Array, Structure res = [] for arg in args: if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, str): res.append(c_char_p) elif isinstance(arg, unicode): res.append(c_wchar_p) elif isinstance(arg, _CData): res.append(type(arg)) elif arg is None: res.append(c_void_p) #elif arg == 0: # res.append(c_void_p) elif isinstance(arg, (int, long)): res.append(c_int) else: raise TypeError("Don't know how to handle %s" % (arg, )) return res def _wrap_args(self, argtypes, args): wrapped_args = [] consumed = 0 for i, argtype in enumerate(argtypes): defaultvalue = None if i > 0 and self._paramflags is not None: paramflag = self._paramflags[i - 1] if len(paramflag) == 2: idlflag, name = paramflag elif len(paramflag) == 3: idlflag, name, defaultvalue = paramflag else: idlflag = 0 idlflag &= (PARAMFLAG_FIN | PARAMFLAG_FOUT | PARAMFLAG_FLCID) if idlflag in (0, PARAMFLAG_FIN): pass elif idlflag == PARAMFLAG_FOUT: import ctypes val = argtype._type_() wrapped = (val, ctypes.byref(val)) wrapped_args.append(wrapped) continue elif idlflag == PARAMFLAG_FIN | PARAMFLAG_FLCID: # Always taken from defaultvalue if given, # else the integer 0. val = defaultvalue if val is None: val = 0 wrapped = argtype._CData_input(val) wrapped_args.append(wrapped) continue else: raise NotImplementedError("paramflags = %s" % (self._paramflags[i - 1], )) if consumed < len(args): arg = args[consumed] elif defaultvalue is not None: arg = defaultvalue else: raise TypeError("Not enough arguments") try: wrapped = argtype._CData_input(arg) except (UnicodeError, TypeError), e: raise ArgumentError(str(e)) wrapped_args.append(wrapped) consumed += 1 if len(wrapped_args) < len(args): extra = args[len(wrapped_args):] extra_types = self._guess_argtypes(extra) for arg, argtype in zip(extra, extra_types): try: wrapped = argtype._CData_input(arg) except (UnicodeError, TypeError), e: raise ArgumentError(str(e)) wrapped_args.append(wrapped) argtypes = list(argtypes) + extra_types
def __new__(self, name, cls, typedict): res = type.__new__(self, name, cls, typedict) if '_type_' in typedict: ffiarray = _rawffi.Array(typedict['_type_']._ffishape_) res._ffiarray = ffiarray subletter = getattr(typedict['_type_'], '_type_', None) if subletter == 'c': def getvalue(self): return _rawffi.charp2string(self._buffer.buffer, self._length_) def setvalue(self, val): # we don't want to have buffers here if len(val) > self._length_: raise ValueError("%r too long" % (val, )) if isinstance(val, str): _rawffi.rawstring2charp(self._buffer.buffer, val) else: for i in range(len(val)): self[i] = val[i] if len(val) < self._length_: self._buffer[len(val)] = '\x00' res.value = property(getvalue, setvalue) def getraw(self): return _rawffi.charp2rawstring(self._buffer.buffer, self._length_) def setraw(self, buffer): if len(buffer) > self._length_: raise ValueError("%r too long" % (buffer, )) _rawffi.rawstring2charp(self._buffer.buffer, buffer) res.raw = property(getraw, setraw) elif subletter == 'u': def getvalue(self): return _rawffi.wcharp2unicode(self._buffer.buffer, self._length_) def setvalue(self, val): # we don't want to have buffers here if len(val) > self._length_: raise ValueError("%r too long" % (val, )) if isinstance(val, unicode): target = self._buffer else: target = self for i in range(len(val)): target[i] = val[i] if len(val) < self._length_: target[len(val)] = u'\x00' res.value = property(getvalue, setvalue) if '_length_' in typedict: res._ffishape_ = (ffiarray, typedict['_length_']) res._fficompositesize_ = res._sizeofinstances() else: res._ffiarray = None return res
class CFuncPtr(_CData): __metaclass__ = CFuncPtrType _argtypes_ = None _restype_ = None _errcheck_ = None _flags_ = 0 _ffiargshape = 'P' _ffishape = 'P' _fficompositesize = None _ffiarray = _rawffi.Array('P') _needs_free = False callable = None _ptr = None _buffer = None # win32 COM properties _paramflags = None _com_index = None _com_iid = None __restype_set = False def _getargtypes(self): return self._argtypes_ def _setargtypes(self, argtypes): self._ptr = None if argtypes is None: self._argtypes_ = () else: for i, argtype in enumerate(argtypes): if not hasattr(argtype, 'from_param'): raise TypeError( "item %d in _argtypes_ has no from_param method" % (i + 1, )) self._argtypes_ = argtypes argtypes = property(_getargtypes, _setargtypes) def _getparamflags(self): return self._paramflags def _setparamflags(self, paramflags): if paramflags is None or not self._argtypes_: self._paramflags = None return if not isinstance(paramflags, tuple): raise TypeError("paramflags must be a tuple or None") if len(paramflags) != len(self._argtypes_): raise ValueError( "paramflags must have the same length as argtypes") for idx, paramflag in enumerate(paramflags): paramlen = len(paramflag) name = default = None if paramlen == 1: flag = paramflag[0] elif paramlen == 2: flag, name = paramflag elif paramlen == 3: flag, name, default = paramflag else: raise TypeError( "paramflags must be a sequence of (int [,string [,value]]) " "tuples") if not isinstance(flag, int): raise TypeError( "paramflags must be a sequence of (int [,string [,value]]) " "tuples") _flag = flag & PARAMFLAG_COMBINED if _flag == PARAMFLAG_FOUT: typ = self._argtypes_[idx] if getattr(typ, '_ffiargshape', None) not in ('P', 'z', 'Z'): raise TypeError( "'out' parameter %d must be a pointer type, not %s" % (idx + 1, type(typ).__name__)) elif _flag not in VALID_PARAMFLAGS: raise TypeError("paramflag value %d not supported" % flag) self._paramflags = paramflags paramflags = property(_getparamflags, _setparamflags) def _getrestype(self): return self._restype_ def _setrestype(self, restype): self.__restype_set = True self._ptr = None if restype is int: from ctypes import c_int restype = c_int if not (isinstance(restype, _CDataMeta) or restype is None or callable(restype)): raise TypeError("restype must be a type, a callable, or None") self._restype_ = restype def _delrestype(self): self._ptr = None del self._restype_ restype = property(_getrestype, _setrestype, _delrestype) def _geterrcheck(self): return getattr(self, '_errcheck_', None) def _seterrcheck(self, errcheck): if not callable(errcheck): raise TypeError("The errcheck attribute must be callable") self._errcheck_ = errcheck def _delerrcheck(self): try: del self._errcheck_ except AttributeError: pass errcheck = property(_geterrcheck, _seterrcheck, _delerrcheck) def _ffishapes(self, args, restype): if args is None: args = [] argtypes = [arg._ffiargshape for arg in args] if restype is not None: if not isinstance(restype, SimpleType): raise TypeError("invalid result type for callback function") restype = restype._ffiargshape else: restype = 'O' # void return argtypes, restype def __init__(self, *args): self.name = None self._objects = {keepalive_key(0): self} self._needs_free = True # Empty function object -- this is needed for casts if not args: self._buffer = _rawffi.Array('P')(1) return argsl = list(args) argument = argsl.pop(0) # Direct construction from raw address if isinstance(argument, (int, long)) and not argsl: ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) self._ptr = _rawffi.FuncPtr(argument, ffiargs, ffires, self._flags_) self._buffer = self._ptr.byptr() return # A callback into Python if callable(argument) and not argsl: self.callable = argument ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) if self._restype_ is None: ffires = None self._ptr = _rawffi.CallbackPtr( self._wrap_callable(argument, self.argtypes), ffiargs, ffires, self._flags_) self._buffer = self._ptr.byptr() return # Function exported from a shared library if isinstance(argument, tuple) and len(argument) == 2: import ctypes self.name, dll = argument if isinstance(dll, str): self.dll = ctypes.CDLL(dll) else: self.dll = dll if argsl: self.paramflags = argsl.pop(0) if argsl: raise TypeError("Unknown constructor %s" % (args, )) # We need to check dll anyway ptr = self._getfuncptr([], ctypes.c_int) self._buffer = ptr.byptr() return # A COM function call, by index if (sys.platform == 'win32' and isinstance(argument, (int, long)) and argsl): ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) self._com_index = argument + 0x1000 self.name = argsl.pop(0) if argsl: self.paramflags = argsl.pop(0) if argsl: self._com_iid = argsl.pop(0) if argsl: raise TypeError("Unknown constructor %s" % (args, )) return raise TypeError("Unknown constructor %s" % (args, )) def _wrap_callable(self, to_call, argtypes): def f(*args): if argtypes: args = [ argtype._CData_retval(argtype.from_address(arg)._buffer) for argtype, arg in zip(argtypes, args) ] return to_call(*args) return f def __call__(self, *args, **kwargs): argtypes = self._argtypes_ if self.callable is not None: if len(args) == len(argtypes): pass elif self._flags_ & _rawffi.FUNCFLAG_CDECL: if len(args) < len(argtypes): plural = len(argtypes) > 1 and "s" or "" raise TypeError( "This function takes at least %d argument%s (%s given)" % (len(argtypes), plural, len(args))) else: # For cdecl functions, we allow more actual arguments # than the length of the argtypes tuple. args = args[:len(self._argtypes_)] else: plural = len(argtypes) > 1 and "s" or "" raise TypeError( "This function takes %d argument%s (%s given)" % (len(argtypes), plural, len(args))) # check that arguments are convertible ## XXX Not as long as ctypes.cast is a callback function with ## py_object arguments... ## self._convert_args(argtypes, args, {}) try: res = self.callable(*args) except: exc_info = sys.exc_info() traceback.print_tb(exc_info[2], file=sys.stderr) print >> sys.stderr, "%s: %s" % (exc_info[0].__name__, exc_info[1]) return 0 if self._restype_ is not None: return res return if argtypes is None: warnings.warn('C function without declared arguments called', RuntimeWarning, stacklevel=2) argtypes = [] if not self.__restype_set: warnings.warn('C function without declared return type called', RuntimeWarning, stacklevel=2) if self._com_index: from ctypes import cast, c_void_p, POINTER if not args: raise ValueError( "native COM method call without 'this' parameter") thisarg = cast(args[0], POINTER(POINTER(c_void_p))).contents argtypes = [c_void_p] + list(argtypes) args = list(args) args[0] = args[0].value else: thisarg = None args, outargs = self._convert_args(argtypes, args, kwargs) argtypes = [type(arg) for arg in args] restype = self._restype_ funcptr = self._getfuncptr(argtypes, restype, thisarg) if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO: set_errno(_rawffi.get_errno()) if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR: set_last_error(_rawffi.get_last_error()) try: resbuffer = funcptr( *[arg._get_buffer_for_param()._buffer for arg in args]) finally: if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO: set_errno(_rawffi.get_errno()) if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR: set_last_error(_rawffi.get_last_error()) result = None if self._com_index: if resbuffer[0] & 0x80000000: raise get_com_error(resbuffer[0], self._com_iid, args[0]) else: result = int(resbuffer[0]) elif restype is not None: checker = getattr(self.restype, '_check_retval_', None) if checker: val = restype(resbuffer[0]) # the original ctypes seems to make the distinction between # classes defining a new type, and their subclasses if '_type_' in restype.__dict__: val = val.value result = checker(val) elif not isinstance(restype, _CDataMeta): result = restype(resbuffer[0]) else: result = restype._CData_retval(resbuffer) # The 'errcheck' protocol if self._errcheck_: v = self._errcheck_(result, self, args) # If the errcheck funtion failed, let it throw # If the errcheck function returned callargs unchanged, # continue normal processing. # If the errcheck function returned something else, # use that as result. if v is not args: result = v if not outargs: return result if len(outargs) == 1: return outargs[0] return tuple(outargs) def _getfuncptr(self, argtypes, restype, thisarg=None): if self._ptr is not None and argtypes is self._argtypes_: return self._ptr if restype is None or not isinstance(restype, _CDataMeta): import ctypes restype = ctypes.c_int argshapes = [arg._ffiargshape for arg in argtypes] resshape = restype._ffiargshape if self._buffer is not None: ptr = _rawffi.FuncPtr(self._buffer[0], argshapes, resshape, self._flags_) if argtypes is self._argtypes_: self._ptr = ptr return ptr if self._com_index: # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") ptr = thisarg[self._com_index - 0x1000] return _rawffi.FuncPtr(ptr, argshapes, resshape, self._flags_) cdll = self.dll._handle try: return cdll.ptr(self.name, argshapes, resshape, self._flags_) except AttributeError: if self._flags_ & _rawffi.FUNCFLAG_CDECL: raise # Win64 has no stdcall calling conv, so it should also not have the # name mangling of it. if WIN64: raise # For stdcall, try mangled names: # funcname -> _funcname@<n> # where n is 0, 4, 8, 12, ..., 128 for i in range(33): mangled_name = "_%s@%d" % (self.name, i * 4) try: return cdll.ptr(mangled_name, argshapes, resshape, self._flags_) except AttributeError: pass raise @staticmethod def _conv_param(argtype, arg): from ctypes import c_char_p, c_wchar_p, c_void_p, c_int if argtype is not None: arg = argtype.from_param(arg) if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, _CData): # The usual case when argtype is defined cobj = arg elif isinstance(arg, str): cobj = c_char_p(arg) elif isinstance(arg, unicode): cobj = c_wchar_p(arg) elif arg is None: cobj = c_void_p() elif isinstance(arg, (int, long)): cobj = c_int(arg) else: raise TypeError("Don't know how to handle %s" % (arg, )) return cobj def _convert_args(self, argtypes, args, kwargs, marker=object()): callargs = [] outargs = [] total = len(args) paramflags = self._paramflags if self._com_index: inargs_idx = 1 else: inargs_idx = 0 if not paramflags and total < len(argtypes): raise TypeError("not enough arguments") for i, argtype in enumerate(argtypes): flag = 0 name = None defval = marker if paramflags: paramflag = paramflags[i] paramlen = len(paramflag) name = None if paramlen == 1: flag = paramflag[0] elif paramlen == 2: flag, name = paramflag elif paramlen == 3: flag, name, defval = paramflag flag = flag & PARAMFLAG_COMBINED if flag == PARAMFLAG_FIN | PARAMFLAG_FLCID: val = defval if val is marker: val = 0 wrapped = self._conv_param(argtype, val) callargs.append(wrapped) elif flag in (0, PARAMFLAG_FIN): if inargs_idx < total: val = args[inargs_idx] inargs_idx += 1 elif kwargs and name in kwargs: val = kwargs[name] inargs_idx += 1 elif defval is not marker: val = defval elif name: raise TypeError("required argument '%s' missing" % name) else: raise TypeError("not enough arguments") wrapped = self._conv_param(argtype, val) callargs.append(wrapped) elif flag == PARAMFLAG_FOUT: if defval is not marker: outargs.append(defval) wrapped = self._conv_param(argtype, defval) else: import ctypes val = argtype._type_() outargs.append(val) wrapped = ctypes.byref(val) callargs.append(wrapped) else: raise ValueError("paramflag %d not yet implemented" % flag) else: try: wrapped = self._conv_param(argtype, args[i]) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) callargs.append(wrapped) inargs_idx += 1 if len(callargs) < total: extra = args[len(callargs):] for i, arg in enumerate(extra): try: wrapped = self._conv_param(None, arg) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) callargs.append(wrapped)
def _set_address(self, address): if not self._buffer: self._buffer = _rawffi.Array('P')(1) self._buffer[0] = address
class CFuncPtr(_CData, metaclass=CFuncPtrType): _argtypes_ = None _restype_ = None _errcheck_ = None _flags_ = 0 _ffiargshape_ = 'P' _ffishape_ = 'P' _fficompositesize_ = None _ffiarray = _rawffi.Array('P') _needs_free = False callable = None _ptr = None _buffer = None _address = None # win32 COM properties _paramflags = None _com_index = None _com_iid = None _is_fastpath = False def _getargtypes(self): return self._argtypes_ def _setargtypes(self, argtypes): self._ptr = None if argtypes is None: self._argtypes_ = () else: for i, argtype in enumerate(argtypes): if not hasattr(argtype, 'from_param'): raise TypeError( "item %d in _argtypes_ has no from_param method" % (i + 1, )) self._argtypes_ = list(argtypes) argtypes = property(_getargtypes, _setargtypes) def _getparamflags(self): return self._paramflags def _setparamflags(self, paramflags): if paramflags is None or not self._argtypes_: self._paramflags = None return if not isinstance(paramflags, tuple): raise TypeError("paramflags must be a tuple or None") if len(paramflags) != len(self._argtypes_): raise ValueError( "paramflags must have the same length as argtypes") for idx, paramflag in enumerate(paramflags): paramlen = len(paramflag) name = default = None if paramlen == 1: flag = paramflag[0] elif paramlen == 2: flag, name = paramflag elif paramlen == 3: flag, name, default = paramflag else: raise TypeError( "paramflags must be a sequence of (int [,string [,value]]) " "tuples") if not isinstance(flag, int): raise TypeError( "paramflags must be a sequence of (int [,string [,value]]) " "tuples") _flag = flag & PARAMFLAG_COMBINED if _flag == PARAMFLAG_FOUT: typ = self._argtypes_[idx] if getattr(typ, '_ffiargshape_', None) not in ('P', 'z', 'Z'): raise TypeError( "'out' parameter %d must be a pointer type, not %s" % (idx + 1, type(typ).__name__)) elif _flag not in VALID_PARAMFLAGS: raise TypeError("paramflag value %d not supported" % flag) self._paramflags = paramflags paramflags = property(_getparamflags, _setparamflags) def _getrestype(self): return self._restype_ def _setrestype(self, restype): self._ptr = None if restype is int: from ctypes import c_int restype = c_int if not (isinstance(restype, _CDataMeta) or restype is None or callable(restype)): raise TypeError("restype must be a type, a callable, or None") self._restype_ = restype def _delrestype(self): self._ptr = None del self._restype_ restype = property(_getrestype, _setrestype, _delrestype) def _geterrcheck(self): return getattr(self, '_errcheck_', None) def _seterrcheck(self, errcheck): if not callable(errcheck): raise TypeError("The errcheck attribute must be callable") self._errcheck_ = errcheck def _delerrcheck(self): try: del self._errcheck_ except AttributeError: pass errcheck = property(_geterrcheck, _seterrcheck, _delerrcheck) def _ffishapes(self, args, restype): if args is None: args = [] argtypes = [arg._ffiargshape_ for arg in args] if restype is not None: if not isinstance(restype, SimpleType): raise TypeError("invalid result type for callback function") restype = restype._ffiargshape_ else: restype = 'O' # void return argtypes, restype def _set_address(self, address): if not self._buffer: self._buffer = _rawffi.Array('P')(1) self._buffer[0] = address def _get_address(self): return self._buffer[0] def __init__(self, *args): self.name = None self._objects = {keepalive_key(0): self} self._needs_free = True # Empty function object -- this is needed for casts if not args: self._set_address(0) return argsl = list(args) argument = argsl.pop(0) # Direct construction from raw address if isinstance(argument, int) and not argsl: self._set_address(argument) restype = self._restype_ if restype is None: import ctypes restype = ctypes.c_int if self._argtypes_ is None: self._argtypes_ = [] self._ptr = self._getfuncptr_fromaddress(self._argtypes_, restype) return # A callback into python if callable(argument) and not argsl: self.callable = argument ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) if self._restype_ is None: ffires = None self._ptr = _rawffi.CallbackPtr( self._wrap_callable(argument, self.argtypes), ffiargs, ffires, self._flags_) self._buffer = self._ptr.byptr() return # Function exported from a shared library if isinstance(argument, tuple) and len(argument) == 2: import ctypes self.name, dll = argument if isinstance(dll, str): self.dll = ctypes.CDLL(self.dll) else: self.dll = dll if argsl: self.paramflags = argsl.pop(0) if argsl: raise TypeError("Unknown constructor %s" % (args, )) # We need to check dll anyway ptr = self._getfuncptr([], ctypes.c_int) self._set_address(ptr.getaddr()) return # A COM function call, by index if (sys.platform == 'win32' and isinstance(argument, int) and argsl): ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) self._com_index = argument + 0x1000 self.name = argsl.pop(0) if argsl: self.paramflags = argsl.pop(0) if argsl: self._com_iid = argsl.pop(0) if argsl: raise TypeError("Unknown constructor %s" % (args, )) return raise TypeError("Unknown constructor %s" % (args, )) _init_no_arg_ = __init__ def _wrap_callable(self, to_call, argtypes): def f(*args): if argtypes: args = [ argtype._CData_retval(argtype.from_address(arg)._buffer) for argtype, arg in zip(argtypes, args) ] try: return to_call(*args) except SystemExit as e: handle_system_exit(e) raise return f def __call__(self, *args, **kwargs): argtypes = self._argtypes_ if self.callable is not None: if len(args) == len(argtypes): pass elif self._flags_ & _rawffi.FUNCFLAG_CDECL: if len(args) < len(argtypes): plural = len(argtypes) > 1 and "s" or "" raise TypeError( "This function takes at least %d argument%s (%s given)" % (len(argtypes), plural, len(args))) else: # For cdecl functions, we allow more actual arguments # than the length of the argtypes tuple. args = args[:len(self._argtypes_)] else: plural = len(self._argtypes_) > 1 and "s" or "" raise TypeError( "This function takes %d argument%s (%s given)" % (len(self._argtypes_), plural, len(args))) try: newargs = self._convert_args_for_callback(argtypes, args) except (UnicodeError, TypeError, ValueError) as e: raise ArgumentError(str(e)) try: try: res = self.callable(*newargs) except SystemExit as e: handle_system_exit(e) raise except: exc_info = sys.exc_info() traceback.print_tb(exc_info[2], file=sys.stderr) print("%s: %s" % (exc_info[0].__name__, exc_info[1]), file=sys.stderr) return 0 if self._restype_ is not None: return res return if argtypes is None: # XXX this warning was originally meaning "it's going to be # really slow". Now we don't worry that much about slowness # of ctypes, and it's strange to get warnings for perfectly- # legal code. # warnings.warn('C function without declared arguments called', # RuntimeWarning, stacklevel=2) argtypes = [] if self._com_index: from ctypes import cast, c_void_p, POINTER if not args: raise ValueError( "native COM method call without 'this' parameter") thisvalue = args[0] thisarg = cast(thisvalue, POINTER(POINTER(c_void_p))) keepalives, newargs, argtypes, outargs, errcheckargs = ( self._convert_args(argtypes, args[1:], kwargs)) newargs.insert(0, thisarg) argtypes.insert(0, c_void_p) else: thisarg = None keepalives, newargs, argtypes, outargs, errcheckargs = ( self._convert_args(argtypes, args, kwargs)) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) result, forced = self._do_errcheck(result, errcheckargs) if not outargs or forced: return result from ctypes import c_void_p simple_cdata = type(c_void_p()).__bases__[0] outargs = [ x.value if type(x).__bases__[0] is simple_cdata else x for x in outargs ] if len(outargs) == 1: return outargs[0] return tuple(outargs) def _call_funcptr(self, funcptr, *newargs): if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO: tmp = _rawffi.get_errno() _rawffi.set_errno(get_errno()) set_errno(tmp) if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR: tmp = _rawffi.get_last_error() _rawffi.set_last_error(get_last_error()) set_last_error(tmp) try: result = funcptr(*newargs) finally: if self._flags_ & _rawffi.FUNCFLAG_USE_ERRNO: tmp = _rawffi.get_errno() _rawffi.set_errno(get_errno()) set_errno(tmp) if self._flags_ & _rawffi.FUNCFLAG_USE_LASTERROR: tmp = _rawffi.get_last_error() _rawffi.set_last_error(get_last_error()) set_last_error(tmp) # try: return self._build_result(self._restype_, result) finally: funcptr.free_temp_buffers() def _do_errcheck(self, result, args): # The 'errcheck' protocol if self._errcheck_: v = self._errcheck_(result, self, tuple(args)) # If the errcheck funtion failed, let it throw # If the errcheck function returned newargs unchanged, # continue normal processing. # If the errcheck function returned something else, # use that as result. if v is not args: return v, True return result, False def _getfuncptr_fromaddress(self, argtypes, restype): address = self._get_address() ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] ffires = restype.get_ffi_argtype() return _ffi.FuncPtr.fromaddr(address, '', ffiargs, ffires, self._flags_) def _getfuncptr(self, argtypes, restype, thisarg=None): if self._ptr is not None and (argtypes is self._argtypes_ or argtypes == self._argtypes_): return self._ptr if restype is None or not isinstance(restype, _CDataMeta): import ctypes restype = ctypes.c_int if self._buffer is not None: ptr = self._getfuncptr_fromaddress(argtypes, restype) if argtypes == self._argtypes_: self._ptr = ptr return ptr if self._com_index: # extract the address from the object's virtual table if not thisarg: raise ValueError("COM method call without VTable") ptr = thisarg[0][self._com_index - 0x1000] ffiargs = [argtype.get_ffi_argtype() for argtype in argtypes] ffires = restype.get_ffi_argtype() return _ffi.FuncPtr.fromaddr(ptr, '', ffiargs, ffires, self._flags_) cdll = self.dll.__pypy_dll__ try: ffi_argtypes = [argtype.get_ffi_argtype() for argtype in argtypes] ffi_restype = restype.get_ffi_argtype() self._ptr = cdll.getfunc(self.name, ffi_argtypes, ffi_restype) return self._ptr except AttributeError: if self._flags_ & _rawffi.FUNCFLAG_CDECL: raise # Win64 has no stdcall calling conv, so it should also not have the # name mangling of it. if WIN64: raise # For stdcall, try mangled names: # funcname -> _funcname@<n> # where n is 0, 4, 8, 12, ..., 128 for i in range(33): mangled_name = "_%s@%d" % (self.name, i * 4) try: return cdll.getfunc( mangled_name, ffi_argtypes, ffi_restype, # XXX self._flags_ ) except AttributeError: pass raise @classmethod def _conv_param(cls, argtype, arg): if argtype is not None: arg = argtype.from_param(arg) if hasattr(arg, '_as_parameter_'): arg = arg._as_parameter_ if isinstance(arg, _CData): return arg, arg._to_ffi_param(), type(arg) # # non-usual case: we do the import here to save a lot of code in the # jit trace of the normal case from ctypes import c_char_p, c_wchar_p, c_void_p, c_int # if isinstance(arg, bytes): cobj = c_char_p(arg) elif isinstance(arg, str): cobj = c_wchar_p(arg) elif arg is None: cobj = c_void_p() elif isinstance(arg, int): cobj = c_int(arg) else: raise TypeError("Don't know how to handle %s" % (arg, )) return cobj, cobj._to_ffi_param(), type(cobj) def _convert_args_for_callback(self, argtypes, args): from _ctypes.structure import StructOrUnion # assert len(argtypes) == len(args) newargs = [] for argtype, arg in zip(argtypes, args): param = argtype.from_param(arg) _type_ = getattr(argtype, '_type_', None) if _type_ == 'P': # special-case for c_void_p param = param._get_buffer_value() elif self._is_primitive(argtype): param = param.value elif isinstance(param, StructOrUnion): # not a *pointer* to struct newparam = StructOrUnion.__new__(type(param)) param._copy_to(newparam._buffer.buffer) param = newparam newargs.append(param) return newargs def _convert_args(self, argtypes, args, kwargs, marker=object()): newargs = [] outargs = [] keepalives = [] newargtypes = [] total = len(args) paramflags = self._paramflags if not paramflags and total < len(argtypes): raise TypeError("not enough arguments") if paramflags: errcheckargs = [] inargs_idx = 0 for i, argtype in enumerate(argtypes): flag = 0 defval = marker paramflag = paramflags[i] paramlen = len(paramflag) name = None if paramlen == 1: flag = paramflag[0] elif paramlen == 2: flag, name = paramflag elif paramlen == 3: flag, name, defval = paramflag flag = flag & PARAMFLAG_COMBINED if flag == PARAMFLAG_FIN | PARAMFLAG_FLCID: val = defval if val is marker: val = 0 errcheckargs.append(val) keepalive, newarg, newargtype = self._conv_param( argtype, val) keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag in (0, PARAMFLAG_FIN): if inargs_idx < total: val = args[inargs_idx] inargs_idx += 1 elif kwargs and name in kwargs: val = kwargs[name] inargs_idx += 1 elif defval is not marker: val = defval elif name: raise TypeError("required argument '%s' missing" % name) else: raise TypeError("not enough arguments") errcheckargs.append(val) keepalive, newarg, newargtype = self._conv_param( argtype, val) keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) elif flag == PARAMFLAG_FOUT: if defval is not marker: val = defval keepalive, newarg, newargtype = self._conv_param( argtype, defval) else: import ctypes val = argtype._type_._newowninstance_() keepalive = None newarg = ctypes.byref(val) newargtype = type(newarg) errcheckargs.append(val) outargs.append(val) keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) else: raise ValueError("paramflag %d not yet implemented" % flag) else: errcheckargs = args for i, argtype in enumerate(argtypes): try: keepalive, newarg, newargtype = self._conv_param( argtype, args[i]) except (UnicodeError, TypeError, ValueError) as e: raise ArgumentError(str(e)) keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) if len(newargs) < len(args): extra = args[len(newargs):] for i, arg in enumerate(extra): try: keepalive, newarg, newargtype = self._conv_param(None, arg) except (UnicodeError, TypeError, ValueError) as e: raise ArgumentError(str(e)) keepalives.append(keepalive) newargs.append(newarg) newargtypes.append(newargtype) return keepalives, newargs, newargtypes, outargs, errcheckargs @staticmethod def _is_primitive(argtype): return argtype.__bases__[0] is _SimpleCData def _wrap_result(self, restype, result): """ Convert from low-level repr of the result to the high-level python one. """ # hack for performance: if restype is a "simple" primitive type, don't # allocate the buffer because it's going to be thrown away immediately if (self._is_primitive(restype) and restype._type_ != '?' and not restype._is_pointer_like()): return result # shape = restype._ffishape_ if is_struct_shape(shape): buf = result else: buf = _rawffi.Array(shape)(1, autofree=True) buf[0] = result retval = restype._CData_retval(buf) return retval def _build_result(self, restype, result): """Build the function result: If there is no OUT parameter, return the actual function result If there is one OUT parameter, return it If there are many OUT parameters, return a tuple""" # XXX: note for the future: the function used to take a "resbuffer", # i.e. an array of ints. Now it takes a result, which is already a # python object. All places that do "resbuffer[0]" should check that # result is actually an int and just use it. retval = None if restype is not None: checker = getattr(self.restype, '_check_retval_', None) if checker: val = restype(result) # the original ctypes seems to make the distinction between # classes defining a new type, and their subclasses if '_type_' in restype.__dict__: val = val.value # XXX Raise a COMError when restype is HRESULT and # checker(val) fails. How to check for restype == HRESULT? if self._com_index: if result & 0x80000000: raise get_com_error(result, None, None) else: retval = checker(val) elif not isinstance(restype, _CDataMeta): retval = restype(result) else: retval = self._wrap_result(restype, result) return retval def __bool__(self): return self._com_index is not None or bool(self._buffer[0]) def __del__(self): if self._needs_free: # XXX we need to find a bad guy here if self._buffer is None: return self._buffer.free() self._buffer = None if isinstance(self._ptr, _rawffi.CallbackPtr): self._ptr.free() self._ptr = None self._needs_free = False
def test_negative_pointers(self): import _rawffi A = _rawffi.Array('P') a = A(1) a[0] = -1234 a.free()
def test_overflow_error(self): import _rawffi A = _rawffi.Array('d') arg1 = A(1) raises(OverflowError, "arg1[0] = 10**900") arg1.free()
def test_truncate(self): import _rawffi, struct a = _rawffi.Array('b')(1) a[0] = -5 assert a[0] == -5 a[0] = 123L assert a[0] == 123 a[0] = 0x97817182ab128111111111111171817d042 assert a[0] == 0x42 a[0] = 255 assert a[0] == -1 a[0] = -2 assert a[0] == -2 a[0] = -255 assert a[0] == 1 a.free() a = _rawffi.Array('B')(1) a[0] = 123L assert a[0] == 123 a[0] = 0x18329b1718b97d89b7198db817d042 assert a[0] == 0x42 a[0] = 255 assert a[0] == 255 a[0] = -2 assert a[0] == 254 a[0] = -255 assert a[0] == 1 a.free() a = _rawffi.Array('h')(1) a[0] = 123L assert a[0] == 123 a[0] = 0x9112cbc91bd91db19aaaaaaaaaaaaaa8170d42 assert a[0] == 0x0d42 a[0] = 65535 assert a[0] == -1 a[0] = -2 assert a[0] == -2 a[0] = -65535 assert a[0] == 1 a.free() a = _rawffi.Array('H')(1) a[0] = 123L assert a[0] == 123 a[0] = 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeee817d042 assert a[0] == 0xd042 a[0] = -2 assert a[0] == 65534 a.free() maxptr = (256**struct.calcsize("P")) - 1 a = _rawffi.Array('P')(1) a[0] = 123L assert a[0] == 123 a[0] = 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeee817d042 assert a[0] == 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeee817d042 & maxptr a[0] = -2 assert a[0] == maxptr - 1 a.free()
def __new__(self, name, cls, typedict): res = type.__new__(self, name, cls, typedict) if cls == (_CData, ): # this is the Array class defined below res._ffiarray = None return res if not hasattr(res, '_length_') or not isinstance( res._length_, (int, long)): raise AttributeError("class must define a '_length_' attribute, " "which must be a positive integer") ffiarray = res._ffiarray = _rawffi.Array(res._type_._ffishape_) subletter = getattr(res._type_, '_type_', None) if subletter == 'c': def getvalue(self): return _rawffi.charp2string(self._buffer.buffer, self._length_) def setvalue(self, val): # we don't want to have buffers here if len(val) > self._length_: raise ValueError("%r too long" % (val, )) if isinstance(val, str): _rawffi.rawstring2charp(self._buffer.buffer, val) else: for i in range(len(val)): self[i] = val[i] if len(val) < self._length_: self._buffer[len(val)] = b'\x00' res.value = property(getvalue, setvalue) def getraw(self): return _rawffi.charp2rawstring(self._buffer.buffer, self._length_) def setraw(self, buffer): if len(buffer) > self._length_: raise ValueError("%r too long" % (buffer, )) _rawffi.rawstring2charp(self._buffer.buffer, buffer) res.raw = property(getraw, setraw) elif subletter == 'u': def getvalue(self): return _rawffi.wcharp2unicode(self._buffer.buffer, self._length_) def setvalue(self, val): # we don't want to have buffers here if len(val) > self._length_: raise ValueError("%r too long" % (val, )) if isinstance(val, unicode): target = self._buffer else: target = self for i in range(len(val)): target[i] = val[i] if len(val) < self._length_: target[len(val)] = u'\x00' res.value = property(getvalue, setvalue) res._ffishape_ = (ffiarray, res._length_) res._fficompositesize_ = res._sizeofinstances() return res
class CFuncPtr(_CData): __metaclass__ = CFuncPtrType _argtypes_ = None _restype_ = None _errcheck_ = None _flags_ = 0 _ffiargshape = 'P' _ffishape = 'P' _fficompositesize = None _ffiarray = _rawffi.Array('P') _needs_free = False callable = None _ptr = None _buffer = None _address = None # win32 COM properties _paramflags = None _com_index = None _com_iid = None _is_fastpath = False def _getargtypes(self): return self._argtypes_ def _setargtypes(self, argtypes): self._ptr = None if argtypes is None: self._argtypes_ = () else: for i, argtype in enumerate(argtypes): if not hasattr(argtype, 'from_param'): raise TypeError( "item %d in _argtypes_ has no from_param method" % (i + 1, )) self._argtypes_ = list(argtypes) self._check_argtypes_for_fastpath() argtypes = property(_getargtypes, _setargtypes) def _check_argtypes_for_fastpath(self): if all( [hasattr(argtype, '_ffiargshape') for argtype in self._argtypes_]): fastpath_cls = make_fastpath_subclass(self.__class__) fastpath_cls.enable_fastpath_maybe(self) def _getparamflags(self): return self._paramflags def _setparamflags(self, paramflags): if paramflags is None or not self._argtypes_: self._paramflags = None return if not isinstance(paramflags, tuple): raise TypeError("paramflags must be a tuple or None") if len(paramflags) != len(self._argtypes_): raise ValueError( "paramflags must have the same length as argtypes") for idx, paramflag in enumerate(paramflags): paramlen = len(paramflag) name = default = None if paramlen == 1: flag = paramflag[0] elif paramlen == 2: flag, name = paramflag elif paramlen == 3: flag, name, default = paramflag else: raise TypeError( "paramflags must be a sequence of (int [,string [,value]]) " "tuples") if not isinstance(flag, int): raise TypeError( "paramflags must be a sequence of (int [,string [,value]]) " "tuples") _flag = flag & PARAMFLAG_COMBINED if _flag == PARAMFLAG_FOUT: typ = self._argtypes_[idx] if getattr(typ, '_ffiargshape', None) not in ('P', 'z', 'Z'): raise TypeError( "'out' parameter %d must be a pointer type, not %s" % (idx + 1, type(typ).__name__)) elif _flag not in VALID_PARAMFLAGS: raise TypeError("paramflag value %d not supported" % flag) self._paramflags = paramflags paramflags = property(_getparamflags, _setparamflags) def _getrestype(self): return self._restype_ def _setrestype(self, restype): self._ptr = None if restype is int: from ctypes import c_int restype = c_int if not (isinstance(restype, _CDataMeta) or restype is None or callable(restype)): raise TypeError("restype must be a type, a callable, or None") self._restype_ = restype def _delrestype(self): self._ptr = None del self._restype_ restype = property(_getrestype, _setrestype, _delrestype) def _geterrcheck(self): return getattr(self, '_errcheck_', None) def _seterrcheck(self, errcheck): if not callable(errcheck): raise TypeError("The errcheck attribute must be callable") self._errcheck_ = errcheck def _delerrcheck(self): try: del self._errcheck_ except AttributeError: pass errcheck = property(_geterrcheck, _seterrcheck, _delerrcheck) def _ffishapes(self, args, restype): if args is None: args = [] argtypes = [arg._ffiargshape for arg in args] if restype is not None: if not isinstance(restype, SimpleType): raise TypeError("invalid result type for callback function") restype = restype._ffiargshape else: restype = 'O' # void return argtypes, restype def _set_address(self, address): if not self._buffer: self._buffer = _rawffi.Array('P')(1) self._buffer[0] = address def _get_address(self): return self._buffer[0] def __init__(self, *args): self.name = None self._objects = {keepalive_key(0): self} self._needs_free = True # Empty function object -- this is needed for casts if not args: self._set_address(0) return argsl = list(args) argument = argsl.pop(0) # Direct construction from raw address if isinstance(argument, (int, long)) and not argsl: self._set_address(argument) restype = self._restype_ if restype is None: import ctypes restype = ctypes.c_int self._ptr = self._getfuncptr_fromaddress(self._argtypes_, restype) self._check_argtypes_for_fastpath() return # A callback into python if callable(argument) and not argsl: self.callable = argument ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) if self._restype_ is None: ffires = None self._ptr = _rawffi.CallbackPtr( self._wrap_callable(argument, self.argtypes), ffiargs, ffires, self._flags_) self._buffer = self._ptr.byptr() return # Function exported from a shared library if isinstance(argument, tuple) and len(argument) == 2: import ctypes self.name, dll = argument if isinstance(dll, str): self.dll = ctypes.CDLL(self.dll) else: self.dll = dll if argsl: self.paramflags = argsl.pop(0) if argsl: raise TypeError("Unknown constructor %s" % (args, )) # We need to check dll anyway ptr = self._getfuncptr([], ctypes.c_int) self._set_address(ptr.getaddr()) return # A COM function call, by index if (sys.platform == 'win32' and isinstance(argument, (int, long)) and argsl): ffiargs, ffires = self._ffishapes(self._argtypes_, self._restype_) self._com_index = argument + 0x1000 self.name = argsl.pop(0) if argsl: self.paramflags = argsl.pop(0) if argsl: self._com_iid = argsl.pop(0) if argsl: raise TypeError("Unknown constructor %s" % (args, )) return raise TypeError("Unknown constructor %s" % (args, )) def _wrap_callable(self, to_call, argtypes): def f(*args): if argtypes: args = [ argtype._CData_retval(argtype.from_address(arg)._buffer) for argtype, arg in zip(argtypes, args) ] return to_call(*args) return f def __call__(self, *args, **kwargs): argtypes = self._argtypes_ if self.callable is not None: if len(args) == len(argtypes): pass elif self._flags_ & _rawffi.FUNCFLAG_CDECL: if len(args) < len(argtypes): plural = len(argtypes) > 1 and "s" or "" raise TypeError( "This function takes at least %d argument%s (%s given)" % (len(argtypes), plural, len(args))) else: # For cdecl functions, we allow more actual arguments # than the length of the argtypes tuple. args = args[:len(self._argtypes_)] else: plural = len(self._argtypes_) > 1 and "s" or "" raise TypeError( "This function takes %d argument%s (%s given)" % (len(self._argtypes_), plural, len(args))) try: newargs = self._convert_args_for_callback(argtypes, args) except (UnicodeError, TypeError, ValueError), e: raise ArgumentError(str(e)) try: res = self.callable(*newargs) except: exc_info = sys.exc_info() traceback.print_tb(exc_info[2], file=sys.stderr) print >> sys.stderr, "%s: %s" % (exc_info[0].__name__, exc_info[1]) return 0 if self._restype_ is not None: return res return if argtypes is None: warnings.warn('C function without declared arguments called', RuntimeWarning, stacklevel=2) argtypes = [] if self._com_index: from ctypes import cast, c_void_p, POINTER if not args: raise ValueError( "native COM method call without 'this' parameter") thisarg = cast(args[0], POINTER(POINTER(c_void_p))) keepalives, newargs, argtypes, outargs = self._convert_args( argtypes, args[1:], kwargs) newargs.insert(0, args[0].value) argtypes.insert(0, c_void_p) else: thisarg = None keepalives, newargs, argtypes, outargs = self._convert_args( argtypes, args, kwargs) funcptr = self._getfuncptr(argtypes, self._restype_, thisarg) result = self._call_funcptr(funcptr, *newargs) result = self._do_errcheck(result, args) if not outargs: return result simple_cdata = type(c_void_p()).__bases__[0] outargs = [ x.value if type(x).__bases__[0] is simple_cdata else x for x in outargs ] if len(outargs) == 1: return outargs[0] return tuple(outargs)
def test_long_with_fromaddress(self): import _rawffi addr = -1 raises(ValueError, _rawffi.Array('u').fromaddress, addr, 100)
# the STDCALL calling convention may detect some errors import _rawffi lib = _rawffi.CDLL('kernel32') f = lib.ptr('SetLastError', [], 'i') try: f() except ValueError, e: assert "Procedure called with not enough arguments" in e.message else: assert 0, "Did not raise" f = lib.ptr('GetLastError', ['i'], None, flags=_rawffi.FUNCFLAG_STDCALL) arg = _rawffi.Array('i')(1) arg[0] = 1 try: f(arg) except ValueError, e: assert "Procedure called with too many arguments" in e.message else: assert 0, "Did not raise" arg.free() def test_struct_byvalue(self): import _rawffi, sys X_Y = _rawffi.Structure([('x', 'l'), ('y', 'l')]) x_y = X_Y() lib = _rawffi.CDLL(self.lib_name) print >> sys.stderr, "getting..."
def getprimitive(typecode, name): addr = lib.getaddressindll(name) return _rawffi.Array(typecode).fromaddress(addr, 1)
def __new__(self, name, bases, dct): try: tp = dct['_type_'] except KeyError: for base in bases: if hasattr(base, '_type_'): tp = base._type_ break else: raise AttributeError("cannot find _type_ attribute") if (not isinstance(tp, str) or not len(tp) == 1 or tp not in SIMPLE_TYPE_CHARS): raise ValueError('%s is not a type character' % (tp)) default = TP_TO_DEFAULT[tp] ffiarray = _rawffi.Array(tp) result = type.__new__(self, name, bases, dct) result._ffiargshape = tp result._ffishape = tp result._fficompositesize = None result._ffiarray = ffiarray if tp == 'z': # c_char_p def _getvalue(self): addr = self._buffer[0] if addr == 0: return None else: return _rawffi.charp2string(addr) def _setvalue(self, value): if isinstance(value, basestring): if isinstance(value, unicode): value = value.encode(ConvMode.encoding, ConvMode.errors) #self._objects = value array = _rawffi.Array('c')(len(value) + 1, value) self._objects = CArgObject(value, array) value = array.buffer elif value is None: value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) result._ffiargtype = _ffi.types.Pointer(_ffi.types.char) elif tp == 'Z': # c_wchar_p def _getvalue(self): addr = self._buffer[0] if addr == 0: return None else: return _rawffi.wcharp2unicode(addr) def _setvalue(self, value): if isinstance(value, basestring): if isinstance(value, str): value = value.decode(ConvMode.encoding, ConvMode.errors) #self._objects = value array = _rawffi.Array('u')(len(value) + 1, value) self._objects = CArgObject(value, array) value = array.buffer elif value is None: value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) result._ffiargtype = _ffi.types.Pointer(_ffi.types.unichar) elif tp == 'P': # c_void_p def _getvalue(self): addr = self._buffer[0] if addr == 0: return None return addr def _setvalue(self, value): if isinstance(value, str): array = _rawffi.Array('c')(len(value) + 1, value) self._objects = CArgObject(value, array) value = array.buffer elif value is None: value = 0 self._buffer[0] = value result.value = property(_getvalue, _setvalue) elif tp == 'u': def _setvalue(self, val): if isinstance(val, str): val = val.decode(ConvMode.encoding, ConvMode.errors) # possible if we use 'ignore' if val: self._buffer[0] = val def _getvalue(self): return self._buffer[0] result.value = property(_getvalue, _setvalue) elif tp == 'c': def _setvalue(self, val): if isinstance(val, unicode): val = val.encode(ConvMode.encoding, ConvMode.errors) if val: self._buffer[0] = val def _getvalue(self): return self._buffer[0] result.value = property(_getvalue, _setvalue) elif tp == 'O': def _setvalue(self, val): num = pyobj_container.add(val) self._buffer[0] = num def _getvalue(self): return pyobj_container.get(self._buffer[0]) result.value = property(_getvalue, _setvalue) elif tp == 'X': from ctypes import WinDLL # Use WinDLL("oleaut32") instead of windll.oleaut32 # because the latter is a shared (cached) object; and # other code may set their own restypes. We need out own # restype here. oleaut32 = WinDLL("oleaut32") SysAllocStringLen = oleaut32.SysAllocStringLen SysStringLen = oleaut32.SysStringLen SysFreeString = oleaut32.SysFreeString def _getvalue(self): addr = self._buffer[0] if addr == 0: return None else: size = SysStringLen(addr) return _rawffi.wcharp2rawunicode(addr, size) def _setvalue(self, value): if isinstance(value, basestring): if isinstance(value, str): value = value.decode(ConvMode.encoding, ConvMode.errors) array = _rawffi.Array('u')(len(value) + 1, value) value = SysAllocStringLen(array.buffer, len(value)) elif value is None: value = 0 if self._buffer[0]: SysFreeString(self._buffer[0]) self._buffer[0] = value result.value = property(_getvalue, _setvalue) elif tp == 'v': # VARIANT_BOOL type def _getvalue(self): return bool(self._buffer[0]) def _setvalue(self, value): if value: self._buffer[0] = -1 # VARIANT_TRUE else: self._buffer[0] = 0 # VARIANT_FALSE result.value = property(_getvalue, _setvalue) # make pointer-types compatible with the _ffi fast path if result._is_pointer_like(): def _as_ffi_pointer_(self, ffitype): return as_ffi_pointer(self, ffitype) result._as_ffi_pointer_ = _as_ffi_pointer_ return result