mirror of https://github.com/python/cpython
Merge changes from the upstream version:
- cast is implemented as a foreign function now - On Windows, it is now possible to access functions exported by ordinal only
This commit is contained in:
parent
f4b066084a
commit
b03cb602e8
|
@ -304,10 +304,11 @@ class CDLL(object):
|
||||||
raise AttributeError, name
|
raise AttributeError, name
|
||||||
return self.__getitem__(name)
|
return self.__getitem__(name)
|
||||||
|
|
||||||
def __getitem__(self, name):
|
def __getitem__(self, name_or_ordinal):
|
||||||
func = self._FuncPtr(name, self)
|
func = self._FuncPtr((name_or_ordinal, self))
|
||||||
func.__name__ = name
|
if not isinstance(name_or_ordinal, (int, long)):
|
||||||
setattr(self, name, func)
|
func.__name__ = name_or_ordinal
|
||||||
|
setattr(self, name_or_ordinal, func)
|
||||||
return func
|
return func
|
||||||
|
|
||||||
class PyDLL(CDLL):
|
class PyDLL(CDLL):
|
||||||
|
@ -384,21 +385,29 @@ if _os.name in ("nt", "ce"):
|
||||||
|
|
||||||
_pointer_type_cache[None] = c_void_p
|
_pointer_type_cache[None] = c_void_p
|
||||||
|
|
||||||
# functions
|
|
||||||
|
|
||||||
from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, cast
|
|
||||||
|
|
||||||
if sizeof(c_uint) == sizeof(c_void_p):
|
if sizeof(c_uint) == sizeof(c_void_p):
|
||||||
c_size_t = c_uint
|
c_size_t = c_uint
|
||||||
elif sizeof(c_ulong) == sizeof(c_void_p):
|
elif sizeof(c_ulong) == sizeof(c_void_p):
|
||||||
c_size_t = c_ulong
|
c_size_t = c_ulong
|
||||||
|
|
||||||
|
# functions
|
||||||
|
|
||||||
|
from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, _cast_addr
|
||||||
|
|
||||||
## void *memmove(void *, const void *, size_t);
|
## void *memmove(void *, const void *, size_t);
|
||||||
memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr)
|
memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr)
|
||||||
|
|
||||||
## void *memset(void *, int, size_t)
|
## void *memset(void *, int, size_t)
|
||||||
memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr)
|
memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr)
|
||||||
|
|
||||||
|
def PYFUNCTYPE(restype, *argtypes):
|
||||||
|
class CFunctionType(_CFuncPtr):
|
||||||
|
_argtypes_ = argtypes
|
||||||
|
_restype_ = restype
|
||||||
|
_flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI
|
||||||
|
return CFunctionType
|
||||||
|
cast = PYFUNCTYPE(py_object, c_void_p, py_object)(_cast_addr)
|
||||||
|
|
||||||
_string_at = CFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
|
_string_at = CFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr)
|
||||||
def string_at(ptr, size=0):
|
def string_at(ptr, size=0):
|
||||||
"""string_at(addr[, size]) -> string
|
"""string_at(addr[, size]) -> string
|
||||||
|
|
|
@ -2,6 +2,7 @@ import sys, unittest, struct, math
|
||||||
from binascii import hexlify
|
from binascii import hexlify
|
||||||
|
|
||||||
from ctypes import *
|
from ctypes import *
|
||||||
|
from ctypes.test import is_resource_enabled
|
||||||
|
|
||||||
def bin(s):
|
def bin(s):
|
||||||
return hexlify(buffer(s)).upper()
|
return hexlify(buffer(s)).upper()
|
||||||
|
@ -149,7 +150,7 @@ class Test(unittest.TestCase):
|
||||||
self.failUnless(c_char.__ctype_le__ is c_char)
|
self.failUnless(c_char.__ctype_le__ is c_char)
|
||||||
self.failUnless(c_char.__ctype_be__ is c_char)
|
self.failUnless(c_char.__ctype_be__ is c_char)
|
||||||
|
|
||||||
def test_struct_fields(self):
|
def test_struct_fields_1(self):
|
||||||
if sys.byteorder == "little":
|
if sys.byteorder == "little":
|
||||||
base = BigEndianStructure
|
base = BigEndianStructure
|
||||||
else:
|
else:
|
||||||
|
@ -198,17 +199,20 @@ class Test(unittest.TestCase):
|
||||||
pass
|
pass
|
||||||
self.assertRaises(TypeError, setattr, S, "_fields_", [("s", T)])
|
self.assertRaises(TypeError, setattr, S, "_fields_", [("s", T)])
|
||||||
|
|
||||||
# crashes on solaris with a core dump.
|
def test_struct_fields_2(self):
|
||||||
def X_test_struct_fields(self):
|
# standard packing in struct uses no alignment.
|
||||||
|
# So, we have to align using pad bytes.
|
||||||
|
#
|
||||||
|
# Unaligned accesses will crash Python (on those platforms that
|
||||||
|
# don't allow it, like sparc solaris).
|
||||||
if sys.byteorder == "little":
|
if sys.byteorder == "little":
|
||||||
base = BigEndianStructure
|
base = BigEndianStructure
|
||||||
fmt = ">bhid"
|
fmt = ">bxhid"
|
||||||
else:
|
else:
|
||||||
base = LittleEndianStructure
|
base = LittleEndianStructure
|
||||||
fmt = "<bhid"
|
fmt = "<bxhid"
|
||||||
|
|
||||||
class S(base):
|
class S(base):
|
||||||
_pack_ = 1 # struct with '<' or '>' uses standard alignment.
|
|
||||||
_fields_ = [("b", c_byte),
|
_fields_ = [("b", c_byte),
|
||||||
("h", c_short),
|
("h", c_short),
|
||||||
("i", c_int),
|
("i", c_int),
|
||||||
|
@ -218,5 +222,54 @@ class Test(unittest.TestCase):
|
||||||
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
|
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
|
||||||
self.failUnlessEqual(bin(s1), bin(s2))
|
self.failUnlessEqual(bin(s1), bin(s2))
|
||||||
|
|
||||||
|
if is_resource_enabled("unaligned_access"):
|
||||||
|
|
||||||
|
def test_unaligned_nonnative_struct_fields(self):
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
base = BigEndianStructure
|
||||||
|
fmt = ">b h xi xd"
|
||||||
|
else:
|
||||||
|
base = LittleEndianStructure
|
||||||
|
fmt = "<b h xi xd"
|
||||||
|
|
||||||
|
class S(base):
|
||||||
|
_pack_ = 1
|
||||||
|
_fields_ = [("b", c_byte),
|
||||||
|
|
||||||
|
("h", c_short),
|
||||||
|
|
||||||
|
("_1", c_byte),
|
||||||
|
("i", c_int),
|
||||||
|
|
||||||
|
("_2", c_byte),
|
||||||
|
("d", c_double)]
|
||||||
|
|
||||||
|
s1 = S(0x12, 0x1234, 0, 0x12345678, 0, 3.14)
|
||||||
|
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
|
||||||
|
self.failUnlessEqual(bin(s1), bin(s2))
|
||||||
|
|
||||||
|
def test_unaligned_native_struct_fields(self):
|
||||||
|
if sys.byteorder == "little":
|
||||||
|
fmt = "<b h xi xd"
|
||||||
|
else:
|
||||||
|
base = LittleEndianStructure
|
||||||
|
fmt = ">b h xi xd"
|
||||||
|
|
||||||
|
class S(Structure):
|
||||||
|
_pack_ = 1
|
||||||
|
_fields_ = [("b", c_byte),
|
||||||
|
|
||||||
|
("h", c_short),
|
||||||
|
|
||||||
|
("_1", c_byte),
|
||||||
|
("i", c_int),
|
||||||
|
|
||||||
|
("_2", c_byte),
|
||||||
|
("d", c_double)]
|
||||||
|
|
||||||
|
s1 = S(0x12, 0x1234, 0, 0x12345678, 0, 3.14)
|
||||||
|
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
|
||||||
|
self.failUnlessEqual(bin(s1), bin(s2))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -179,7 +179,7 @@ else:
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
if name[:2] == '__' and name[-2:] == '__':
|
if name[:2] == '__' and name[-2:] == '__':
|
||||||
raise AttributeError, name
|
raise AttributeError, name
|
||||||
func = self._FuncPtr("s_" + name, self)
|
func = self._FuncPtr(("s_" + name, self))
|
||||||
setattr(self, name, func)
|
setattr(self, name, func)
|
||||||
return func
|
return func
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,11 @@ class LoaderTest(unittest.TestCase):
|
||||||
name = "libc.so"
|
name = "libc.so"
|
||||||
elif sys.platform == "sunos5":
|
elif sys.platform == "sunos5":
|
||||||
name = "libc.so"
|
name = "libc.so"
|
||||||
|
elif sys.platform.startswith("netbsd"):
|
||||||
|
name = "libc.so"
|
||||||
else:
|
else:
|
||||||
name = "libc.so.6"
|
name = "libc.so.6"
|
||||||
|
## print (sys.platform, os.name)
|
||||||
cdll.load(name)
|
cdll.load(name)
|
||||||
self.assertRaises(OSError, cdll.load, self.unknowndll)
|
self.assertRaises(OSError, cdll.load, self.unknowndll)
|
||||||
|
|
||||||
|
@ -37,5 +40,31 @@ class LoaderTest(unittest.TestCase):
|
||||||
cdll.find(name)
|
cdll.find(name)
|
||||||
self.assertRaises(OSError, cdll.find, self.unknowndll)
|
self.assertRaises(OSError, cdll.find, self.unknowndll)
|
||||||
|
|
||||||
|
def test_load_library(self):
|
||||||
|
if os.name == "nt":
|
||||||
|
windll.load_library("kernel32").GetModuleHandleW
|
||||||
|
windll.LoadLibrary("kernel32").GetModuleHandleW
|
||||||
|
WinDLL("kernel32").GetModuleHandleW
|
||||||
|
elif os.name == "ce":
|
||||||
|
windll.load_library("coredll").GetModuleHandleW
|
||||||
|
windll.LoadLibrary("coredll").GetModuleHandleW
|
||||||
|
WinDLL("coredll").GetModuleHandleW
|
||||||
|
|
||||||
|
def test_load_ordinal_functions(self):
|
||||||
|
if os.name in ("nt", "ce"):
|
||||||
|
import _ctypes_test
|
||||||
|
dll = WinDLL(_ctypes_test.__file__)
|
||||||
|
# We load the same function both via ordinal and name
|
||||||
|
func_ord = dll[2]
|
||||||
|
func_name = dll.GetString
|
||||||
|
# addressof gets the address where the function pointer is stored
|
||||||
|
a_ord = addressof(func_ord)
|
||||||
|
a_name = addressof(func_name)
|
||||||
|
f_ord_addr = c_void_p.from_address(a_ord).value
|
||||||
|
f_name_addr = c_void_p.from_address(a_name).value
|
||||||
|
self.failUnlessEqual(hex(f_ord_addr), hex(f_name_addr))
|
||||||
|
|
||||||
|
self.failUnlessRaises(AttributeError, dll.__getitem__, 1234)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -20,5 +20,8 @@ class SizesTestCase(unittest.TestCase):
|
||||||
self.failUnlessEqual(8, sizeof(c_int64))
|
self.failUnlessEqual(8, sizeof(c_int64))
|
||||||
self.failUnlessEqual(8, sizeof(c_uint64))
|
self.failUnlessEqual(8, sizeof(c_uint64))
|
||||||
|
|
||||||
|
def test_size_t(self):
|
||||||
|
self.failUnlessEqual(sizeof(c_void_p), sizeof(c_size_t))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -2388,6 +2388,11 @@ static PPROC FindAddress(void *handle, char *name, PyObject *type)
|
||||||
address = (PPROC)GetProcAddress(handle, name);
|
address = (PPROC)GetProcAddress(handle, name);
|
||||||
if (address)
|
if (address)
|
||||||
return address;
|
return address;
|
||||||
|
|
||||||
|
if (((size_t)name & ~0xFFFF) == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* It should not happen that dict is NULL, but better be safe */
|
/* It should not happen that dict is NULL, but better be safe */
|
||||||
if (dict==NULL || dict->flags & FUNCFLAG_CDECL)
|
if (dict==NULL || dict->flags & FUNCFLAG_CDECL)
|
||||||
return address;
|
return address;
|
||||||
|
@ -2493,6 +2498,28 @@ _validate_paramflags(PyTypeObject *type, PyObject *paramflags)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_get_name(PyObject *obj, char **pname)
|
||||||
|
{
|
||||||
|
#ifdef MS_WIN32
|
||||||
|
if (PyInt_Check(obj) || PyLong_Check(obj)) {
|
||||||
|
/* We have to use MAKEINTRESOURCEA for Windows CE.
|
||||||
|
Works on Windows as well, of course.
|
||||||
|
*/
|
||||||
|
*pname = MAKEINTRESOURCEA(PyInt_AsUnsignedLongMask(obj) & 0xFFFF);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (PyString_Check(obj) || PyUnicode_Check(obj)) {
|
||||||
|
*pname = PyString_AsString(obj);
|
||||||
|
return pname ? 1 : 0;
|
||||||
|
}
|
||||||
|
PyErr_SetString(PyExc_TypeError,
|
||||||
|
"function name must be string or integer");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
{
|
{
|
||||||
|
@ -2504,7 +2531,7 @@ CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
void *handle;
|
void *handle;
|
||||||
PyObject *paramflags = NULL;
|
PyObject *paramflags = NULL;
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "sO|O", &name, &dll, ¶mflags))
|
if (!PyArg_ParseTuple(args, "(O&O)|O", _get_name, &name, &dll, ¶mflags))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (paramflags == Py_None)
|
if (paramflags == Py_None)
|
||||||
paramflags = NULL;
|
paramflags = NULL;
|
||||||
|
@ -2529,9 +2556,14 @@ CFuncPtr_FromDll(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
#ifdef MS_WIN32
|
#ifdef MS_WIN32
|
||||||
address = FindAddress(handle, name, (PyObject *)type);
|
address = FindAddress(handle, name, (PyObject *)type);
|
||||||
if (!address) {
|
if (!address) {
|
||||||
PyErr_Format(PyExc_AttributeError,
|
if ((size_t)name & ~0xFFFF)
|
||||||
"function '%s' not found",
|
PyErr_Format(PyExc_AttributeError,
|
||||||
name);
|
"function '%s' not found",
|
||||||
|
name);
|
||||||
|
else
|
||||||
|
PyErr_Format(PyExc_AttributeError,
|
||||||
|
"function ordinal %d not found",
|
||||||
|
name);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -2608,8 +2640,9 @@ CFuncPtr_FromVtblIndex(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
"O" - must be a callable, creates a C callable function
|
"O" - must be a callable, creates a C callable function
|
||||||
|
|
||||||
two or more argument forms (the third argument is a paramflags tuple)
|
two or more argument forms (the third argument is a paramflags tuple)
|
||||||
"sO|O" - function name, dll object (with an integer handle)
|
"(sO)|..." - (function name, dll object (with an integer handle)), paramflags
|
||||||
"is|O" - vtable index, method name, creates callable calling COM vtbl
|
"(iO)|..." - (function ordinal, dll object (with an integer handle)), paramflags
|
||||||
|
"is|..." - vtable index, method name, creates callable calling COM vtbl
|
||||||
*/
|
*/
|
||||||
static PyObject *
|
static PyObject *
|
||||||
CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
|
@ -2622,14 +2655,13 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
||||||
if (PyTuple_GET_SIZE(args) == 0)
|
if (PyTuple_GET_SIZE(args) == 0)
|
||||||
return GenericCData_new(type, args, kwds);
|
return GenericCData_new(type, args, kwds);
|
||||||
|
|
||||||
/* Shouldn't the following better be done in __init__? */
|
if (1 <= PyTuple_GET_SIZE(args) && PyTuple_Check(PyTuple_GET_ITEM(args, 0)))
|
||||||
if (2 <= PyTuple_GET_SIZE(args)) {
|
|
||||||
#ifdef MS_WIN32
|
|
||||||
if (PyInt_Check(PyTuple_GET_ITEM(args, 0)))
|
|
||||||
return CFuncPtr_FromVtblIndex(type, args, kwds);
|
|
||||||
#endif
|
|
||||||
return CFuncPtr_FromDll(type, args, kwds);
|
return CFuncPtr_FromDll(type, args, kwds);
|
||||||
}
|
|
||||||
|
#ifdef MS_WIN32
|
||||||
|
if (2 <= PyTuple_GET_SIZE(args) && PyInt_Check(PyTuple_GET_ITEM(args, 0)))
|
||||||
|
return CFuncPtr_FromVtblIndex(type, args, kwds);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (1 == PyTuple_GET_SIZE(args)
|
if (1 == PyTuple_GET_SIZE(args)
|
||||||
&& (PyInt_Check(PyTuple_GET_ITEM(args, 0))
|
&& (PyInt_Check(PyTuple_GET_ITEM(args, 0))
|
||||||
|
@ -4351,6 +4383,42 @@ string_at(const char *ptr, Py_ssize_t size)
|
||||||
return PyString_FromStringAndSize(ptr, size);
|
return PyString_FromStringAndSize(ptr, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cast_check_pointertype(PyObject *arg)
|
||||||
|
{
|
||||||
|
StgDictObject *dict;
|
||||||
|
|
||||||
|
if (PointerTypeObject_Check(arg))
|
||||||
|
return 1;
|
||||||
|
dict = PyType_stgdict(arg);
|
||||||
|
if (dict) {
|
||||||
|
if (PyString_Check(dict->proto)
|
||||||
|
&& (strchr("sPzUZXO", PyString_AS_STRING(dict->proto)[0]))) {
|
||||||
|
/* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
"cast() argument 2 must be a pointer type, not %s",
|
||||||
|
PyType_Check(arg)
|
||||||
|
? ((PyTypeObject *)arg)->tp_name
|
||||||
|
: arg->ob_type->tp_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
cast(void *ptr, PyObject *ctype)
|
||||||
|
{
|
||||||
|
CDataObject *result;
|
||||||
|
if (0 == cast_check_pointertype(ctype))
|
||||||
|
return NULL;
|
||||||
|
result = (CDataObject *)PyObject_CallFunctionObjArgs(ctype, NULL);
|
||||||
|
if (result == NULL)
|
||||||
|
return NULL;
|
||||||
|
/* Should we assert that result is a pointer type? */
|
||||||
|
memcpy(result->b_ptr, &ptr, sizeof(void *));
|
||||||
|
return (PyObject *)result;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CTYPES_UNICODE
|
#ifdef CTYPES_UNICODE
|
||||||
static PyObject *
|
static PyObject *
|
||||||
|
@ -4486,6 +4554,7 @@ init_ctypes(void)
|
||||||
PyModule_AddObject(m, "_memmove_addr", PyLong_FromVoidPtr(memmove));
|
PyModule_AddObject(m, "_memmove_addr", PyLong_FromVoidPtr(memmove));
|
||||||
PyModule_AddObject(m, "_memset_addr", PyLong_FromVoidPtr(memset));
|
PyModule_AddObject(m, "_memset_addr", PyLong_FromVoidPtr(memset));
|
||||||
PyModule_AddObject(m, "_string_at_addr", PyLong_FromVoidPtr(string_at));
|
PyModule_AddObject(m, "_string_at_addr", PyLong_FromVoidPtr(string_at));
|
||||||
|
PyModule_AddObject(m, "_cast_addr", PyLong_FromVoidPtr(cast));
|
||||||
#ifdef CTYPES_UNICODE
|
#ifdef CTYPES_UNICODE
|
||||||
PyModule_AddObject(m, "_wstring_at_addr", PyLong_FromVoidPtr(wstring_at));
|
PyModule_AddObject(m, "_wstring_at_addr", PyLong_FromVoidPtr(wstring_at));
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1423,71 +1423,7 @@ set_conversion_mode(PyObject *self, PyObject *args)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static char cast_doc[] =
|
|
||||||
"cast(cobject, ctype) -> ctype-instance\n\
|
|
||||||
\n\
|
|
||||||
Create an instance of ctype, and copy the internal memory buffer\n\
|
|
||||||
of cobject to the new instance. Should be used to cast one type\n\
|
|
||||||
of pointer to another type of pointer.\n\
|
|
||||||
Doesn't work correctly with ctypes integers.\n";
|
|
||||||
|
|
||||||
static int cast_check_pointertype(PyObject *arg, PyObject **pobj)
|
|
||||||
{
|
|
||||||
StgDictObject *dict;
|
|
||||||
|
|
||||||
if (PointerTypeObject_Check(arg)) {
|
|
||||||
*pobj = arg;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
dict = PyType_stgdict(arg);
|
|
||||||
if (dict) {
|
|
||||||
if (PyString_Check(dict->proto)
|
|
||||||
&& (strchr("sPzUZXO", PyString_AS_STRING(dict->proto)[0]))) {
|
|
||||||
/* simple pointer types, c_void_p, c_wchar_p, BSTR, ... */
|
|
||||||
*pobj = arg;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (PyType_Check(arg)) {
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"cast() argument 2 must be a pointer type, not %s",
|
|
||||||
((PyTypeObject *)arg)->tp_name);
|
|
||||||
} else {
|
|
||||||
PyErr_Format(PyExc_TypeError,
|
|
||||||
"cast() argument 2 must be a pointer type, not a %s",
|
|
||||||
arg->ob_type->tp_name);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *cast(PyObject *self, PyObject *args)
|
|
||||||
{
|
|
||||||
PyObject *obj, *ctype;
|
|
||||||
struct argument a;
|
|
||||||
CDataObject *result;
|
|
||||||
|
|
||||||
/* We could and should allow array types for the second argument
|
|
||||||
also, but we cannot use the simple memcpy below for them. */
|
|
||||||
if (!PyArg_ParseTuple(args, "OO&:cast", &obj, &cast_check_pointertype, &ctype))
|
|
||||||
return NULL;
|
|
||||||
if (-1 == ConvParam(obj, 1, &a))
|
|
||||||
return NULL;
|
|
||||||
result = (CDataObject *)PyObject_CallFunctionObjArgs(ctype, NULL);
|
|
||||||
if (result == NULL) {
|
|
||||||
Py_XDECREF(a.keep);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
// result->b_size
|
|
||||||
// a.ffi_type->size
|
|
||||||
memcpy(result->b_ptr, &a.value,
|
|
||||||
min(result->b_size, (int)a.ffi_type->size));
|
|
||||||
Py_XDECREF(a.keep);
|
|
||||||
return (PyObject *)result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyMethodDef module_methods[] = {
|
PyMethodDef module_methods[] = {
|
||||||
{"cast", cast, METH_VARARGS, cast_doc},
|
|
||||||
#ifdef CTYPES_UNICODE
|
#ifdef CTYPES_UNICODE
|
||||||
{"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc},
|
{"set_conversion_mode", set_conversion_mode, METH_VARARGS, set_conversion_mode_doc},
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue