fake to enable this test on linux in python 2 3 this raises typeerror mro conflict among bases classes in python 2 2 it works but in early versions of ctypes c the result of tpnew wasn t checked and it even crashed python found by greg chapman test the error message when converting an incompatible type to ccharp proto cfunctypecint ccharp def callbackargs return 0 callback protocallback self assertequalcallbackbabc 0 with self assertraisesargumenterror as cm callback10 self assertequalstrcm exception argument 1 typeerror int object cannot be interpreted as ctypes ccharp def testcwcharpparmself test the error message when converting an incompatible type to cvoidp proto cfunctypecint cvoidp def callbackargs return 0 callback protocallback self assertequalcallback5 0 with self assertraisesargumenterror as cm callback2 5 self assertequalstrcm exception argument 1 typeerror float object cannot be interpreted as ctypes cvoidp def testwcharresultself f dll testfuncibhilfd f argtypes cbyte cshort cint clong cfloat cdouble f restype cwchar result f0 0 0 0 0 0 self assertequalresult x00 def testvoidresultself f dll testfuncv f restype none f argtypes cint cint pointercint result cint self assertequalnone f1 2 byrefresult self assertequalresult value 3 def testintresultself f dll testfuncibhilfd f argtypes cbyte cshort cint clong cfloat cdouble f restype cint result f1 2 3 4 5 0 6 0 self assertequalresult 21 self assertequaltyperesult int result f1 2 3 4 5 0 6 0 self assertequalresult 21 self assertequaltyperesult int if we declare the function to return a short is the high part split off f restype cshort result f1 2 3 4 5 0 6 0 self assertequalresult 21 self assertequaltyperesult int result f1 2 3 0x10004 5 0 6 0 self assertequalresult 21 self assertequaltyperesult int you cannot assign character format codes as restype any longer self assertraisestypeerror setattr f restype i def testfloatresultself f dll testfuncfbhilfd f argtypes cbyte cshort cint clong cfloat cdouble f restype cfloat result f1 2 3 4 5 0 6 0 self assertequalresult 21 self assertequaltyperesult float result f1 2 3 4 5 0 6 0 self assertequalresult 21 self assertequaltyperesult float def testdoubleresultself f dll testfuncdbhilfd f argtypes cbyte cshort cint clong cfloat cdouble f restype cdouble result f1 2 3 4 5 0 6 0 self assertequalresult 21 self assertequaltyperesult float result f1 2 3 4 5 0 6 0 self assertequalresult 21 self assertequaltyperesult float def testlongdoubleresultself f dll testfuncdbhilfd f argtypes cbyte cshort cint clong cfloat clongdouble f restype clongdouble result f1 2 3 4 5 0 6 0 self assertequalresult 21 self assertequaltyperesult float result f1 2 3 4 5 0 6 0 self assertequalresult 21 self assertequaltyperesult float def testlonglongresultself f dll testfuncqbhilfd f restype clonglong f argtypes cbyte cshort cint clong cfloat cdouble result f1 2 3 4 5 0 6 0 self assertequalresult 21 f dll testfuncqbhilfdq f restype clonglong f argtypes cbyte cshort cint clong cfloat cdouble clonglong result f1 2 3 4 5 0 6 0 21 self assertequalresult 42 def teststringresultself f dll testfuncpp f argtypes none f restype ccharp result fb123 self assertequalresult b123 result fnone self assertequalresult none def testpointersself f dll testfuncpp f restype pointercint f argtypes pointercint this only works if the value cint42 passed to the function is still alive while the pointer the result is used v cint42 self assertequalpointerv contents value 42 result fpointerv self assertequaltyperesult pointercint self assertequalresult contents value 42 this on works result fpointerv self assertequalresult contents value v value p pointercint99 result fp self assertequalresult contents value 99 arg byrefv result farg self assertnotequalresult contents v value self assertraisesargumenterror f byrefcshort22 it is dangerous however because you don t control the lifetime of the pointer result fbyrefcint99 self assertnotequalresult contents 99 def testshortsself f dll testfunccallbackiif args expected 262144 131072 65536 32768 16384 8192 4096 2048 1024 512 256 128 64 32 16 8 4 2 1 def callbackv args appendv return v callback cfunctypecint cint cb callbackcallback f218 cb self assertequalargs expected def testcallbacksself f dll testfunccallbackiif f restype cint f argtypes none mycallback cfunctypecint cint def callbackvalue return value cb mycallbackcallback result f10 cb self assertequalresult 18 test with prototype f argtypes cint mycallback cb mycallbackcallback result f10 cb self assertequalresult 18 anothercallback winfunctypecint cint cint cint cint check that the prototype works we call f with wrong argument types cb anothercallbackcallback self assertraisesargumenterror f 10 cb def testcallbacks2self can also use simple datatypes as argument type specifiers for the callback function in this case the call receives an instance of that type f dll testfunccallbackiif f restype cint mycallback cfunctypecint cint f argtypes cint mycallback def callbackvalue self assertequaltypevalue int return value cb mycallbackcallback result f10 cb self assertequalresult 18 def testlonglongcallbacksself f dll testfunccallbackqqf f restype clonglong mycallback cfunctypeclonglong clonglong f argtypes clonglong mycallback def callbackvalue self assertisinstancevalue int return value 0x7fffffff cb mycallbackcallback self assertequal13577625587 f1000000000000 cb def testerrorsself self assertraisesattributeerror getattr dll xxxyyy self assertraisesvalueerror cint indll dll xxxyyy def testbyvalself without prototype ptin point1 2 ptout point export int testfuncbyvalpoint in point pout result dll testfuncbyvalptin byrefptout got result ptout x ptout y expected 3 1 2 self assertequalgot expected with prototype ptin point101 102 ptout point dll testfuncbyval argtypes point pointerpoint dll testfuncbyval restype cint result dll testfuncbyvalptin byrefptout got result ptout x ptout y expected 203 101 102 self assertequalgot expected def teststructreturn2hself class s2hstructure fields x cshort y cshort dll ret2hfunc restype s2h dll ret2hfunc argtypes s2h inp s2h99 88 s2h dll ret2hfuncinp self assertequals2h x s2h y 992 883 unittest skipunlesssys platform win32 windowsspecific test def teststructreturn2hstdcallself class s2hstructure fields x cshort y cshort windll sret2hfunc restype s2h windll sret2hfunc argtypes s2h s2h windll sret2hfuncs2h99 88 self assertequals2h x s2h y 992 883 def teststructreturn8hself class s8istructure fields a cint b cint c cint d cint e cint f cint g cint h cint dll ret8ifunc restype s8i dll ret8ifunc argtypes s8i inp s8i9 8 7 6 5 4 3 2 s8i dll ret8ifuncinp self assertequals8i a s8i b s8i c s8i d s8i e s8i f s8i g s8i h 92 83 74 65 56 47 38 29 unittest skipunlesssys platform win32 windowsspecific test def teststructreturn8hstdcallself class s8istructure fields a cint b cint c cint d cint e cint f cint g cint h cint windll sret8ifunc restype s8i windll sret8ifunc argtypes s8i inp s8i9 8 7 6 5 4 3 2 s8i windll sret8ifuncinp self assertequal s8i a s8i b s8i c s8i d s8i e s8i f s8i g s8i h 92 83 74 65 56 47 38 29 def testsf1651235self see https bugs python orgissue1651235 proto cfunctypecint rect point def callbackargs return 0 callback protocallback self assertraisesargumenterror lambda callback1 2 3 4 point if name main unittest main fake to enable this test on linux in python 2 3 this raises typeerror mro conflict among bases classes in python 2 2 it works but in early versions of _ctypes c the result of tp_new wasn t checked and it even crashed python found by greg chapman test the error message when converting an incompatible type to c_char_p test the error message when converting an incompatible type to c_wchar_p test the error message when converting an incompatible type to c_void_p if we declare the function to return a short is the high part split off you cannot assign character format codes as restype any longer this only works if the value c_int 42 passed to the function is still alive while the pointer the result is used this on works it is dangerous however because you don t control the lifetime of the pointer test with prototype check that the prototype works we call f with wrong argument types can also use simple datatypes as argument type specifiers for the callback function in this case the call receives an instance of that type without prototype export int _testfunc_byval point in point pout with prototype see https bugs python org issue1651235
import _ctypes_test
import ctypes
import sys
import unittest
from ctypes import (CDLL, Structure, Array, CFUNCTYPE,
                    byref, POINTER, pointer, ArgumentError,
                    c_char, c_wchar, c_byte, c_char_p, c_wchar_p,
                    c_short, c_int, c_long, c_longlong, c_void_p,
                    c_float, c_double, c_longdouble)
from _ctypes import _Pointer,  _SimpleCData


try:
    WINFUNCTYPE = ctypes.WINFUNCTYPE
except AttributeError:
    
    WINFUNCTYPE = CFUNCTYPE

dll = CDLL(_ctypes_test.__file__)
if sys.platform == "win32":
    windll = ctypes.WinDLL(_ctypes_test.__file__)


class POINT(Structure):
    _fields_ = [("x", c_int), ("y", c_int)]


class RECT(Structure):
    _fields_ = [("left", c_int), ("top", c_int),
                ("right", c_int), ("bottom", c_int)]


class FunctionTestCase(unittest.TestCase):

    def test_mro(self):
        
        
        
        
        
        

        with self.assertRaises(TypeError):
            class X(object, Array):
                _length_ = 5
                _type_ = "i"

        with self.assertRaises(TypeError):
            class X2(object, _Pointer):
                pass

        with self.assertRaises(TypeError):
            class X3(object, _SimpleCData):
                _type_ = "i"

        with self.assertRaises(TypeError):
            class X4(object, Structure):
                _fields_ = []

    def test_c_char_parm(self):
        proto = CFUNCTYPE(c_int, c_char)
        def callback(*args):
            return 0

        callback = proto(callback)

        self.assertEqual(callback(b"a"), 0)

        with self.assertRaises(ArgumentError) as cm:
            callback(b"abc")

        self.assertEqual(str(cm.exception),
                         "argument 1: TypeError: one character bytes, "
                         "bytearray or integer expected")

    def test_wchar_parm(self):
        f = dll._testfunc_i_bhilfd
        f.argtypes = [c_byte, c_wchar, c_int, c_long, c_float, c_double]
        result = f(1, "x", 3, 4, 5.0, 6.0)
        self.assertEqual(result, 139)
        self.assertEqual(type(result), int)

        with self.assertRaises(ArgumentError) as cm:
            f(1, 2, 3, 4, 5.0, 6.0)
        self.assertEqual(str(cm.exception),
                         "argument 2: TypeError: unicode string expected "
                         "instead of int instance")

        with self.assertRaises(ArgumentError) as cm:
            f(1, "abc", 3, 4, 5.0, 6.0)
        self.assertEqual(str(cm.exception),
                         "argument 2: TypeError: one character unicode string "
                         "expected")

    def test_c_char_p_parm(self):
        
        proto = CFUNCTYPE(c_int, c_char_p)
        def callback(*args):
            return 0

        callback = proto(callback)
        self.assertEqual(callback(b"abc"), 0)

        with self.assertRaises(ArgumentError) as cm:
            callback(10)

        self.assertEqual(str(cm.exception),
                         "argument 1: TypeError: 'int' object cannot be "
                         "interpreted as ctypes.c_char_p")

    def test_c_wchar_p_parm(self):
        
        proto = CFUNCTYPE(c_int, c_wchar_p)
        def callback(*args):
            return 0

        callback = proto(callback)
        self.assertEqual(callback("abc"), 0)

        with self.assertRaises(ArgumentError) as cm:
            callback(10)

        self.assertEqual(str(cm.exception),
                         "argument 1: TypeError: 'int' object cannot be "
                         "interpreted as ctypes.c_wchar_p")

    def test_c_void_p_parm(self):
        
        proto = CFUNCTYPE(c_int, c_void_p)
        def callback(*args):
            return 0

        callback = proto(callback)
        self.assertEqual(callback(5), 0)

        with self.assertRaises(ArgumentError) as cm:
            callback(2.5)

        self.assertEqual(str(cm.exception),
                         "argument 1: TypeError: 'float' object cannot be "
                         "interpreted as ctypes.c_void_p")

    def test_wchar_result(self):
        f = dll._testfunc_i_bhilfd
        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
        f.restype = c_wchar
        result = f(0, 0, 0, 0, 0, 0)
        self.assertEqual(result, '\x00')

    def test_voidresult(self):
        f = dll._testfunc_v
        f.restype = None
        f.argtypes = [c_int, c_int, POINTER(c_int)]
        result = c_int()
        self.assertEqual(None, f(1, 2, byref(result)))
        self.assertEqual(result.value, 3)

    def test_intresult(self):
        f = dll._testfunc_i_bhilfd
        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
        f.restype = c_int
        result = f(1, 2, 3, 4, 5.0, 6.0)
        self.assertEqual(result, 21)
        self.assertEqual(type(result), int)

        result = f(-1, -2, -3, -4, -5.0, -6.0)
        self.assertEqual(result, -21)
        self.assertEqual(type(result), int)

        
        
        f.restype = c_short
        result = f(1, 2, 3, 4, 5.0, 6.0)
        self.assertEqual(result, 21)
        self.assertEqual(type(result), int)

        result = f(1, 2, 3, 0x10004, 5.0, 6.0)
        self.assertEqual(result, 21)
        self.assertEqual(type(result), int)

        
        self.assertRaises(TypeError, setattr, f, "restype", "i")

    def test_floatresult(self):
        f = dll._testfunc_f_bhilfd
        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
        f.restype = c_float
        result = f(1, 2, 3, 4, 5.0, 6.0)
        self.assertEqual(result, 21)
        self.assertEqual(type(result), float)

        result = f(-1, -2, -3, -4, -5.0, -6.0)
        self.assertEqual(result, -21)
        self.assertEqual(type(result), float)

    def test_doubleresult(self):
        f = dll._testfunc_d_bhilfd
        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
        f.restype = c_double
        result = f(1, 2, 3, 4, 5.0, 6.0)
        self.assertEqual(result, 21)
        self.assertEqual(type(result), float)

        result = f(-1, -2, -3, -4, -5.0, -6.0)
        self.assertEqual(result, -21)
        self.assertEqual(type(result), float)

    def test_longdoubleresult(self):
        f = dll._testfunc_D_bhilfD
        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_longdouble]
        f.restype = c_longdouble
        result = f(1, 2, 3, 4, 5.0, 6.0)
        self.assertEqual(result, 21)
        self.assertEqual(type(result), float)

        result = f(-1, -2, -3, -4, -5.0, -6.0)
        self.assertEqual(result, -21)
        self.assertEqual(type(result), float)

    def test_longlongresult(self):
        f = dll._testfunc_q_bhilfd
        f.restype = c_longlong
        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double]
        result = f(1, 2, 3, 4, 5.0, 6.0)
        self.assertEqual(result, 21)

        f = dll._testfunc_q_bhilfdq
        f.restype = c_longlong
        f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double, c_longlong]
        result = f(1, 2, 3, 4, 5.0, 6.0, 21)
        self.assertEqual(result, 42)

    def test_stringresult(self):
        f = dll._testfunc_p_p
        f.argtypes = None
        f.restype = c_char_p
        result = f(b"123")
        self.assertEqual(result, b"123")

        result = f(None)
        self.assertEqual(result, None)

    def test_pointers(self):
        f = dll._testfunc_p_p
        f.restype = POINTER(c_int)
        f.argtypes = [POINTER(c_int)]

        
        
        

        v = c_int(42)

        self.assertEqual(pointer(v).contents.value, 42)
        result = f(pointer(v))
        self.assertEqual(type(result), POINTER(c_int))
        self.assertEqual(result.contents.value, 42)

        
        result = f(pointer(v))
        self.assertEqual(result.contents.value, v.value)

        p = pointer(c_int(99))
        result = f(p)
        self.assertEqual(result.contents.value, 99)

        arg = byref(v)
        result = f(arg)
        self.assertNotEqual(result.contents, v.value)

        self.assertRaises(ArgumentError, f, byref(c_short(22)))

        
        
        result = f(byref(c_int(99)))
        self.assertNotEqual(result.contents, 99)

    def test_shorts(self):
        f = dll._testfunc_callback_i_if

        args = []
        expected = [262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048,
                    1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1]

        def callback(v):
            args.append(v)
            return v

        CallBack = CFUNCTYPE(c_int, c_int)

        cb = CallBack(callback)
        f(2**18, cb)
        self.assertEqual(args, expected)

    def test_callbacks(self):
        f = dll._testfunc_callback_i_if
        f.restype = c_int
        f.argtypes = None

        MyCallback = CFUNCTYPE(c_int, c_int)

        def callback(value):
            return value

        cb = MyCallback(callback)
        result = f(-10, cb)
        self.assertEqual(result, -18)

        
        f.argtypes = [c_int, MyCallback]
        cb = MyCallback(callback)
        result = f(-10, cb)
        self.assertEqual(result, -18)

        AnotherCallback = WINFUNCTYPE(c_int, c_int, c_int, c_int, c_int)

        
        
        cb = AnotherCallback(callback)
        self.assertRaises(ArgumentError, f, -10, cb)


    def test_callbacks_2(self):
        
        
        
        f = dll._testfunc_callback_i_if
        f.restype = c_int

        MyCallback = CFUNCTYPE(c_int, c_int)

        f.argtypes = [c_int, MyCallback]

        def callback(value):
            self.assertEqual(type(value), int)
            return value

        cb = MyCallback(callback)
        result = f(-10, cb)
        self.assertEqual(result, -18)

    def test_longlong_callbacks(self):

        f = dll._testfunc_callback_q_qf
        f.restype = c_longlong

        MyCallback = CFUNCTYPE(c_longlong, c_longlong)

        f.argtypes = [c_longlong, MyCallback]

        def callback(value):
            self.assertIsInstance(value, int)
            return value & 0x7FFFFFFF

        cb = MyCallback(callback)

        self.assertEqual(13577625587, f(1000000000000, cb))

    def test_errors(self):
        self.assertRaises(AttributeError, getattr, dll, "_xxx_yyy")
        self.assertRaises(ValueError, c_int.in_dll, dll, "_xxx_yyy")

    def test_byval(self):

        
        ptin = POINT(1, 2)
        ptout = POINT()
        
        result = dll._testfunc_byval(ptin, byref(ptout))
        got = result, ptout.x, ptout.y
        expected = 3, 1, 2
        self.assertEqual(got, expected)

        
        ptin = POINT(101, 102)
        ptout = POINT()
        dll._testfunc_byval.argtypes = (POINT, POINTER(POINT))
        dll._testfunc_byval.restype = c_int
        result = dll._testfunc_byval(ptin, byref(ptout))
        got = result, ptout.x, ptout.y
        expected = 203, 101, 102
        self.assertEqual(got, expected)

    def test_struct_return_2H(self):
        class S2H(Structure):
            _fields_ = [("x", c_short),
                        ("y", c_short)]
        dll.ret_2h_func.restype = S2H
        dll.ret_2h_func.argtypes = [S2H]
        inp = S2H(99, 88)
        s2h = dll.ret_2h_func(inp)
        self.assertEqual((s2h.x, s2h.y), (99*2, 88*3))

    @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
    def test_struct_return_2H_stdcall(self):
        class S2H(Structure):
            _fields_ = [("x", c_short),
                        ("y", c_short)]

        windll.s_ret_2h_func.restype = S2H
        windll.s_ret_2h_func.argtypes = [S2H]
        s2h = windll.s_ret_2h_func(S2H(99, 88))
        self.assertEqual((s2h.x, s2h.y), (99*2, 88*3))

    def test_struct_return_8H(self):
        class S8I(Structure):
            _fields_ = [("a", c_int),
                        ("b", c_int),
                        ("c", c_int),
                        ("d", c_int),
                        ("e", c_int),
                        ("f", c_int),
                        ("g", c_int),
                        ("h", c_int)]
        dll.ret_8i_func.restype = S8I
        dll.ret_8i_func.argtypes = [S8I]
        inp = S8I(9, 8, 7, 6, 5, 4, 3, 2)
        s8i = dll.ret_8i_func(inp)
        self.assertEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
                             (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))

    @unittest.skipUnless(sys.platform == "win32", 'Windows-specific test')
    def test_struct_return_8H_stdcall(self):
        class S8I(Structure):
            _fields_ = [("a", c_int),
                        ("b", c_int),
                        ("c", c_int),
                        ("d", c_int),
                        ("e", c_int),
                        ("f", c_int),
                        ("g", c_int),
                        ("h", c_int)]
        windll.s_ret_8i_func.restype = S8I
        windll.s_ret_8i_func.argtypes = [S8I]
        inp = S8I(9, 8, 7, 6, 5, 4, 3, 2)
        s8i = windll.s_ret_8i_func(inp)
        self.assertEqual(
                (s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h),
                (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9))

    def test_sf1651235(self):
        

        proto = CFUNCTYPE(c_int, RECT, POINT)
        def callback(*args):
            return 0

        callback = proto(callback)
        self.assertRaises(ArgumentError, lambda: callback((1, 2, 3, 4), POINT()))


if __name__ == '__main__':
    unittest.main()