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:
Thomas Heller 2006-03-17 15:52:58 +00:00
parent f4b066084a
commit b03cb602e8
7 changed files with 191 additions and 92 deletions

View file

@ -304,10 +304,11 @@ class CDLL(object):
raise AttributeError, name
return self.__getitem__(name)
def __getitem__(self, name):
func = self._FuncPtr(name, self)
func.__name__ = name
setattr(self, name, func)
def __getitem__(self, name_or_ordinal):
func = self._FuncPtr((name_or_ordinal, self))
if not isinstance(name_or_ordinal, (int, long)):
func.__name__ = name_or_ordinal
setattr(self, name_or_ordinal, func)
return func
class PyDLL(CDLL):
@ -384,21 +385,29 @@ if _os.name in ("nt", "ce"):
_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):
c_size_t = c_uint
elif sizeof(c_ulong) == sizeof(c_void_p):
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);
memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr)
## void *memset(void *, int, size_t)
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)
def string_at(ptr, size=0):
"""string_at(addr[, size]) -> string

View file

@ -2,6 +2,7 @@ import sys, unittest, struct, math
from binascii import hexlify
from ctypes import *
from ctypes.test import is_resource_enabled
def bin(s):
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_be__ is c_char)
def test_struct_fields(self):
def test_struct_fields_1(self):
if sys.byteorder == "little":
base = BigEndianStructure
else:
@ -198,17 +199,20 @@ class Test(unittest.TestCase):
pass
self.assertRaises(TypeError, setattr, S, "_fields_", [("s", T)])
# crashes on solaris with a core dump.
def X_test_struct_fields(self):
def test_struct_fields_2(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":
base = BigEndianStructure
fmt = ">bhid"
fmt = ">bxhid"
else:
base = LittleEndianStructure
fmt = "<bhid"
fmt = "<bxhid"
class S(base):
_pack_ = 1 # struct with '<' or '>' uses standard alignment.
_fields_ = [("b", c_byte),
("h", c_short),
("i", c_int),
@ -218,5 +222,54 @@ class Test(unittest.TestCase):
s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14)
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__":
unittest.main()

View file

@ -179,7 +179,7 @@ else:
def __getattr__(self, name):
if name[:2] == '__' and name[-2:] == '__':
raise AttributeError, name
func = self._FuncPtr("s_" + name, self)
func = self._FuncPtr(("s_" + name, self))
setattr(self, name, func)
return func

View file

@ -17,8 +17,11 @@ class LoaderTest(unittest.TestCase):
name = "libc.so"
elif sys.platform == "sunos5":
name = "libc.so"
elif sys.platform.startswith("netbsd"):
name = "libc.so"
else:
name = "libc.so.6"
## print (sys.platform, os.name)
cdll.load(name)
self.assertRaises(OSError, cdll.load, self.unknowndll)
@ -37,5 +40,31 @@ class LoaderTest(unittest.TestCase):
cdll.find(name)
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__":
unittest.main()

View file

@ -20,5 +20,8 @@ class SizesTestCase(unittest.TestCase):
self.failUnlessEqual(8, sizeof(c_int64))
self.failUnlessEqual(8, sizeof(c_uint64))
def test_size_t(self):
self.failUnlessEqual(sizeof(c_void_p), sizeof(c_size_t))
if __name__ == "__main__":
unittest.main()