1import unittest 2from ctypes import * 3 4try: 5 WINFUNCTYPE 6except NameError: 7 # fake to enable this test on Linux 8 WINFUNCTYPE = CFUNCTYPE 9 10import _ctypes_test 11lib = CDLL(_ctypes_test.__file__) 12 13class CFuncPtrTestCase(unittest.TestCase): 14 def test_basic(self): 15 X = WINFUNCTYPE(c_int, c_int, c_int) 16 17 def func(*args): 18 return len(args) 19 20 x = X(func) 21 self.assertEqual(x.restype, c_int) 22 self.assertEqual(x.argtypes, (c_int, c_int)) 23 self.assertEqual(sizeof(x), sizeof(c_voidp)) 24 self.assertEqual(sizeof(X), sizeof(c_voidp)) 25 26 def test_first(self): 27 StdCallback = WINFUNCTYPE(c_int, c_int, c_int) 28 CdeclCallback = CFUNCTYPE(c_int, c_int, c_int) 29 30 def func(a, b): 31 return a + b 32 33 s = StdCallback(func) 34 c = CdeclCallback(func) 35 36 self.assertEqual(s(1, 2), 3) 37 self.assertEqual(c(1, 2), 3) 38 # The following no longer raises a TypeError - it is now 39 # possible, as in C, to call cdecl functions with more parameters. 40 #self.assertRaises(TypeError, c, 1, 2, 3) 41 self.assertEqual(c(1, 2, 3, 4, 5, 6), 3) 42 if not WINFUNCTYPE is CFUNCTYPE: 43 self.assertRaises(TypeError, s, 1, 2, 3) 44 45 def test_structures(self): 46 WNDPROC = WINFUNCTYPE(c_long, c_int, c_int, c_int, c_int) 47 48 def wndproc(hwnd, msg, wParam, lParam): 49 return hwnd + msg + wParam + lParam 50 51 HINSTANCE = c_int 52 HICON = c_int 53 HCURSOR = c_int 54 LPCTSTR = c_char_p 55 56 class WNDCLASS(Structure): 57 _fields_ = [("style", c_uint), 58 ("lpfnWndProc", WNDPROC), 59 ("cbClsExtra", c_int), 60 ("cbWndExtra", c_int), 61 ("hInstance", HINSTANCE), 62 ("hIcon", HICON), 63 ("hCursor", HCURSOR), 64 ("lpszMenuName", LPCTSTR), 65 ("lpszClassName", LPCTSTR)] 66 67 wndclass = WNDCLASS() 68 wndclass.lpfnWndProc = WNDPROC(wndproc) 69 70 WNDPROC_2 = WINFUNCTYPE(c_long, c_int, c_int, c_int, c_int) 71 72 # This is no longer true, now that WINFUNCTYPE caches created types internally. 73 ## # CFuncPtr subclasses are compared by identity, so this raises a TypeError: 74 ## self.assertRaises(TypeError, setattr, wndclass, 75 ## "lpfnWndProc", WNDPROC_2(wndproc)) 76 # instead: 77 78 self.assertIs(WNDPROC, WNDPROC_2) 79 # 'wndclass.lpfnWndProc' leaks 94 references. Why? 80 self.assertEqual(wndclass.lpfnWndProc(1, 2, 3, 4), 10) 81 82 83 f = wndclass.lpfnWndProc 84 85 del wndclass 86 del wndproc 87 88 self.assertEqual(f(10, 11, 12, 13), 46) 89 90 def test_dllfunctions(self): 91 92 def NoNullHandle(value): 93 if not value: 94 raise WinError() 95 return value 96 97 strchr = lib.my_strchr 98 strchr.restype = c_char_p 99 strchr.argtypes = (c_char_p, c_char) 100 self.assertEqual(strchr(b"abcdefghi", b"b"), b"bcdefghi") 101 self.assertEqual(strchr(b"abcdefghi", b"x"), None) 102 103 104 strtok = lib.my_strtok 105 strtok.restype = c_char_p 106 # Neither of this does work: strtok changes the buffer it is passed 107## strtok.argtypes = (c_char_p, c_char_p) 108## strtok.argtypes = (c_string, c_char_p) 109 110 def c_string(init): 111 size = len(init) + 1 112 return (c_char*size)(*init) 113 114 s = b"a\nb\nc" 115 b = c_string(s) 116 117## b = (c_char * (len(s)+1))() 118## b.value = s 119 120## b = c_string(s) 121 self.assertEqual(strtok(b, b"\n"), b"a") 122 self.assertEqual(strtok(None, b"\n"), b"b") 123 self.assertEqual(strtok(None, b"\n"), b"c") 124 self.assertEqual(strtok(None, b"\n"), None) 125 126 def test_abstract(self): 127 from ctypes import _CFuncPtr 128 129 self.assertRaises(TypeError, _CFuncPtr, 13, "name", 42, "iid") 130 131if __name__ == '__main__': 132 unittest.main() 133