diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst --- a/Doc/library/ctypes.rst +++ b/Doc/library/ctypes.rst @@ -16,10 +16,6 @@ ctypes tutorial --------------- -Note: The code samples in this tutorial use :mod:`doctest` to make sure that -they actually work. Since some code samples behave differently under Linux, -Windows, or Mac OS X, they contain doctest directives in comments. - Note: Some code samples reference the ctypes :class:`c_int` type. This type is an alias for the :class:`c_long` type on 32-bit systems. So, you should not be confused if :class:`c_long` is printed if you would expect :class:`c_int` --- @@ -51,12 +47,12 @@ library containing most standard C functions, and uses the cdecl calling convention:: - >>> from ctypes import * - >>> print(windll.kernel32) # doctest: +WINDOWS + >>> from ctypes import * #doctest: +SKIP + >>> windll.kernel32 #doctest: +SKIP - >>> print(cdll.msvcrt) # doctest: +WINDOWS + >>> cdll.msvcrt #doctest: +SKIP - >>> libc = cdll.msvcrt # doctest: +WINDOWS + >>> libc = cdll.msvcrt #doctest: +SKIP >>> Windows appends the usual ``.dll`` file suffix automatically. @@ -66,10 +62,10 @@ :meth:`LoadLibrary` method of the dll loaders should be used, or you should load the library by creating an instance of CDLL by calling the constructor:: - >>> cdll.LoadLibrary("libc.so.6") # doctest: +LINUX + >>> cdll.LoadLibrary("libc.so.6") #doctest: +SKIP - >>> libc = CDLL("libc.so.6") # doctest: +LINUX - >>> libc # doctest: +LINUX + >>> libc = CDLL("libc.so.6") #doctest: +SKIP + >>> libc #doctest: +SKIP >>> @@ -84,11 +80,11 @@ Functions are accessed as attributes of dll objects:: >>> from ctypes import * - >>> libc.printf + >>> libc.printf #doctest: +SKIP <_FuncPtr object at 0x...> - >>> print(windll.kernel32.GetModuleHandleA) # doctest: +WINDOWS + >>> windll.kernel32.GetModuleHandleA #doctest: +SKIP <_FuncPtr object at 0x...> - >>> print(windll.kernel32.MyOwnFunction) # doctest: +WINDOWS + >>> windll.kernel32.MyOwnFunction #doctest: +SKIP Traceback (most recent call last): File "", line 1, in ? File "ctypes.py", line 239, in __getattr__ @@ -117,16 +113,16 @@ identifiers, like ``"??2@YAPAXI@Z"``. In this case you have to use :func:`getattr` to retrieve the function:: - >>> getattr(cdll.msvcrt, "??2@YAPAXI@Z") # doctest: +WINDOWS + >>> getattr(cdll.msvcrt, "??2@YAPAXI@Z") #doctest: +SKIP <_FuncPtr object at 0x...> >>> On Windows, some dlls export functions not by name but by ordinal. These functions can be accessed by indexing the dll object with the ordinal number:: - >>> cdll.kernel32[1] # doctest: +WINDOWS + >>> cdll.kernel32[1] #doctest: +SKIP <_FuncPtr object at 0x...> - >>> cdll.kernel32[0] # doctest: +WINDOWS + >>> cdll.kernel32[0] #doctest: +SKIP Traceback (most recent call last): File "", line 1, in ? File "ctypes.py", line 310, in __getitem__ @@ -148,10 +144,10 @@ This example calls both functions with a NULL pointer (``None`` should be used as the NULL pointer):: - >>> print(libc.time(None)) # doctest: +SKIP + >>> libc.time(None) #doctest: +SKIP 1150640792 - >>> print(hex(windll.kernel32.GetModuleHandleA(None))) # doctest: +WINDOWS - 0x1d000000 + >>> hex(windll.kernel32.GetModuleHandleA(None)) #doctest: +SKIP + '0x1d000000' >>> :mod:`ctypes` tries to protect you from calling functions with the wrong number @@ -159,11 +155,11 @@ Windows. It does this by examining the stack after the function returns, so although an error is raised the function *has* been called:: - >>> windll.kernel32.GetModuleHandleA() # doctest: +WINDOWS + >>> windll.kernel32.GetModuleHandleA() #doctest: +SKIP Traceback (most recent call last): File "", line 1, in ? ValueError: Procedure probably called with not enough arguments (4 bytes missing) - >>> windll.kernel32.GetModuleHandleA(0, 0) # doctest: +WINDOWS + >>> windll.kernel32.GetModuleHandleA(0, 0) #doctest: +SKIP Traceback (most recent call last): File "", line 1, in ? ValueError: Procedure probably called with too many arguments (4 bytes in excess) @@ -172,13 +168,13 @@ The same exception is raised when you call an ``stdcall`` function with the ``cdecl`` calling convention, or vice versa:: - >>> cdll.kernel32.GetModuleHandleA(None) # doctest: +WINDOWS + >>> cdll.kernel32.GetModuleHandleA(None) #doctest: +SKIP Traceback (most recent call last): File "", line 1, in ? ValueError: Procedure probably called with not enough arguments (4 bytes missing) >>> - >>> windll.msvcrt.printf(b"spam") # doctest: +WINDOWS + >>> windll.msvcrt.printf(b"spam") #doctest: +SKIP Traceback (most recent call last): File "", line 1, in ? ValueError: Procedure probably called with too many arguments (4 bytes in excess) @@ -191,7 +187,7 @@ crashes from general protection faults when functions are called with invalid argument values:: - >>> windll.kernel32.GetModuleHandleA(32) # doctest: +WINDOWS + >>> windll.kernel32.GetModuleHandleA(32) #doctest: +SKIP Traceback (most recent call last): File "", line 1, in ? OSError: exception: access violation reading 0x00000020 @@ -283,12 +279,12 @@ Since these types are mutable, their value can also be changed afterwards:: >>> i = c_int(42) - >>> print(i) + >>> i c_long(42) - >>> print(i.value) + >>> i.value 42 >>> i.value = -99 - >>> print(i.value) + >>> i.value -99 >>> @@ -299,13 +295,13 @@ >>> s = "Hello, World" >>> c_s = c_wchar_p(s) - >>> print(c_s) + >>> c_s c_wchar_p('Hello, World') >>> c_s.value = "Hi, there" - >>> print(c_s) + >>> c_s c_wchar_p('Hi, there') - >>> print(s) # first object is unchanged - Hello, World + >>> s # first object is unchanged + 'Hello, World' >>> You should be careful, however, not to pass them to functions expecting pointers @@ -322,7 +318,7 @@ >>> p = create_string_buffer(b"Hello") # create a buffer containing a NUL terminated string >>> print(sizeof(p), repr(p.raw)) 6 b'Hello\x00' - >>> print(repr(p.value)) + >>> p.value b'Hello' >>> p = create_string_buffer(b"Hello", 10) # create a 10 byte buffer >>> print(sizeof(p), repr(p.raw)) @@ -348,17 +344,17 @@ :data:`sys.stdout`, so these examples will only work at the console prompt, not from within *IDLE* or *PythonWin*:: - >>> printf = libc.printf - >>> printf(b"Hello, %s\n", b"World!") + >>> printf = libc.printf #doctest: +SKIP + >>> printf(b"Hello, %s\n", b"World!") #doctest: +SKIP Hello, World! 14 - >>> printf(b"Hello, %S\n", "World!") + >>> printf(b"Hello, %S\n", "World!") #doctest: +SKIP Hello, World! 14 - >>> printf(b"%d bottles of beer\n", 42) + >>> printf(b"%d bottles of beer\n", 42) #doctest: +SKIP 42 bottles of beer 19 - >>> printf(b"%f bottles of beer\n", 42.5) + >>> printf(b"%f bottles of beer\n", 42.5) #doctest: +SKIP Traceback (most recent call last): File "", line 1, in ? ArgumentError: argument 2: exceptions.TypeError: Don't know how to convert parameter 2 @@ -368,7 +364,7 @@ bytes objects have to be wrapped in their corresponding :mod:`ctypes` type, so that they can be converted to the required C data type:: - >>> printf(b"An int %d, a double %f\n", 1234, c_double(3.14)) + >>> printf(b"An int %d, a double %f\n", 1234, c_double(3.14)) #doctest: +SKIP An int 1234, a double 3.140000 31 >>> @@ -389,7 +385,7 @@ ... self._as_parameter_ = number ... >>> bottles = Bottles(42) - >>> printf(b"%d bottles of beer\n", bottles) + >>> printf(b"%d bottles of beer\n", bottles) #doctest: +SKIP 42 bottles of beer 19 >>> @@ -412,8 +408,8 @@ different types of parameters depending on the format string, on the other hand this is quite handy to experiment with this feature):: - >>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double] - >>> printf(b"String '%s', Int %d, Double %f\n", b"Hi", 10, 2.2) + >>> printf.argtypes = [c_char_p, c_char_p, c_int, c_double] #doctest: +SKIP + >>> printf(b"String '%s', Int %d, Double %f\n", b"Hi", 10, 2.2) #doctest: +SKIP String 'Hi', Int 10, Double 2.200000 37 >>> @@ -421,11 +417,11 @@ Specifying a format protects against incompatible argument types (just as a prototype for a C function), and tries to convert the arguments to valid types:: - >>> printf(b"%d %d %d", 1, 2, 3) + >>> printf(b"%d %d %d", 1, 2, 3) #doctest: +SKIP Traceback (most recent call last): File "", line 1, in ? ArgumentError: argument 2: exceptions.TypeError: wrong type - >>> printf(b"%s %d %f\n", b"X", 2, 3) + >>> printf(b"%s %d %f\n", b"X", 2, 3) #doctest: +SKIP X 2 3.000000 13 >>> @@ -453,13 +449,13 @@ Here is a more advanced example, it uses the ``strchr`` function, which expects a string pointer and a char, and returns a pointer to a string:: - >>> strchr = libc.strchr - >>> strchr(b"abcdef", ord("d")) # doctest: +SKIP + >>> strchr = libc.strchr #doctest: +SKIP + >>> strchr(b"abcdef", ord("d")) #doctest: +SKIP 8059983 - >>> strchr.restype = c_char_p # c_char_p is a pointer to a string - >>> strchr(b"abcdef", ord("d")) + >>> strchr.restype = c_char_p # c_char_p is a pointer to a string #doctest: +SKIP + >>> strchr(b"abcdef", ord("d")) #doctest: +SKIP b'def' - >>> print(strchr(b"abcdef", ord("x"))) + >>> print(strchr(b"abcdef", ord("x"))) #doctest: +SKIP None >>> @@ -467,17 +463,17 @@ :attr:`argtypes` attribute, and the second argument will be converted from a single character Python bytes object into a C char:: - >>> strchr.restype = c_char_p - >>> strchr.argtypes = [c_char_p, c_char] - >>> strchr(b"abcdef", b"d") + >>> strchr.restype = c_char_p #doctest: +SKIP + >>> strchr.argtypes = [c_char_p, c_char] #doctest: +SKIP + >>> strchr(b"abcdef", b"d") #doctest: +SKIP 'def' - >>> strchr(b"abcdef", b"def") + >>> strchr(b"abcdef", b"def") #doctest: +SKIP Traceback (most recent call last): File "", line 1, in ? ArgumentError: argument 2: exceptions.TypeError: one character string expected - >>> print(strchr(b"abcdef", b"x")) + >>> print(strchr(b"abcdef", b"x")) #doctest: +SKIP None - >>> strchr(b"abcdef", b"d") + >>> strchr(b"abcdef", b"d") #doctest: +SKIP 'def' >>> @@ -487,17 +483,17 @@ result of this call will be used as the result of your function call. This is useful to check for error return values and automatically raise an exception:: - >>> GetModuleHandle = windll.kernel32.GetModuleHandleA # doctest: +WINDOWS + >>> GetModuleHandle = windll.kernel32.GetModuleHandleA #doctest: +SKIP >>> def ValidHandle(value): ... if value == 0: ... raise WinError() ... return value ... >>> - >>> GetModuleHandle.restype = ValidHandle # doctest: +WINDOWS - >>> GetModuleHandle(None) # doctest: +WINDOWS + >>> GetModuleHandle.restype = ValidHandle #doctest: +SKIP + >>> GetModuleHandle(None) #doctest: +SKIP 486539264 - >>> GetModuleHandle("something silly") # doctest: +WINDOWS + >>> GetModuleHandle("something silly") #doctest: +SKIP Traceback (most recent call last): File "", line 1, in ? File "", line 3, in ValidHandle @@ -534,10 +530,10 @@ >>> print(i.value, f.value, repr(s.value)) 0 0.0 b'' >>> libc.sscanf(b"1 3.14 Hello", b"%d %f %s", - ... byref(i), byref(f), s) + ... byref(i), byref(f), s) #doctest: +SKIP 3 - >>> print(i.value, f.value, repr(s.value)) - 1 3.1400001049 b'Hello' + >>> print(i.value, f.value, repr(s.value)) #doctest: +SKIP + 1 3.140000104904175 b'Hello' >>> @@ -571,7 +567,7 @@ >>> POINT(1, 2, 3) Traceback (most recent call last): File "", line 1, in ? - ValueError: too many initializers + TypeError: too many initializers >>> You can, however, build much more complicated structures. A structure can @@ -599,9 +595,9 @@ Field :term:`descriptor`\s can be retrieved from the *class*, they are useful for debugging because they can provide useful information:: - >>> print(POINT.x) + >>> POINT.x - >>> print(POINT.y) + >>> POINT.y >>> @@ -644,9 +640,9 @@ ... _fields_ = [("first_16", c_int, 16), ... ("second_16", c_int, 16)] ... - >>> print(Int.first_16) + >>> Int.first_16 - >>> print(Int.second_16) + >>> Int.second_16 >>> @@ -675,7 +671,7 @@ ... ("b", c_float), ... ("point_array", POINT * 4)] >>> - >>> print(len(MyStruct().point_array)) + >>> len(MyStruct().point_array) 4 >>> @@ -693,9 +689,9 @@ >>> from ctypes import * >>> TenIntegers = c_int * 10 >>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) - >>> print(ii) - - >>> for i in ii: print(i, end=" ") + >>> ii #doctest: +ELLIPSIS + <__main__.c_long_Array_10 object at 0x...> + >>> for i in ii: print(i, end=" ") #doctest: +NORMALIZE_WHITESPACE ... 1 2 3 4 5 6 7 8 9 10 >>> @@ -750,10 +746,10 @@ Assigning to an integer index changes the pointed to value:: - >>> print(i) + >>> i c_long(99) >>> pi[0] = 22 - >>> print(i) + >>> i c_long(22) >>> @@ -770,20 +766,20 @@ >>> PI = POINTER(c_int) >>> PI - + >>> PI(42) Traceback (most recent call last): File "", line 1, in ? TypeError: expected c_long instead of int - >>> PI(c_int(42)) - + >>> PI(c_int(42)) #doctest: +ELLIPSIS + <__main__.LP_c_long object at 0x...> >>> Calling the pointer type without an argument creates a ``NULL`` pointer. ``NULL`` pointers have a ``False`` boolean value:: >>> null_ptr = POINTER(c_int)() - >>> print(bool(null_ptr)) + >>> bool(null_ptr) False >>> @@ -862,8 +858,8 @@ the same memory block as the first argument:: >>> a = (c_byte * 4)() - >>> cast(a, POINTER(c_int)) - + >>> cast(a, POINTER(c_int)) #doctest: +ELLIPSIS + <__main__.LP_c_long object at ...> >>> So, :func:`cast` can be used to assign to the ``values`` field of ``Bar`` the @@ -871,7 +867,7 @@ >>> bar = Bar() >>> bar.values = cast((c_byte * 4)(), POINTER(c_int)) - >>> print(bar.values[0]) + >>> bar.values[0] 0 >>> @@ -921,17 +917,17 @@ other, and finally follow the pointer chain a few times:: >>> c1 = cell() - >>> c1.name = "foo" + >>> c1.name = b"foo" >>> c2 = cell() - >>> c2.name = "bar" + >>> c2.name = b"bar" >>> c1.next = pointer(c2) >>> c2.next = pointer(c1) >>> p = c1 - >>> for i in range(8): - ... print(p.name, end=" ") + >>> for i in range(6): + ... print(p.name, end=" ") #doctest: +NORMALIZE_WHITESPACE ... p = p.next[0] ... - foo bar foo bar foo bar foo bar + b'foo' b'bar' b'foo' b'bar' b'foo' b'bar' >>> @@ -962,8 +958,8 @@ >>> IntArray5 = c_int * 5 >>> ia = IntArray5(5, 1, 7, 33, 99) - >>> qsort = libc.qsort - >>> qsort.restype = None + >>> qsort = libc.qsort #doctest: +SKIP + >>> qsort.restype = None #doctest: +SKIP >>> :func:`qsort` must be called with a pointer to the data to sort, the number of @@ -990,7 +986,7 @@ The result:: - >>> qsort(ia, len(ia), sizeof(c_int), cmp_func) # doctest: +LINUX + >>> qsort(ia, len(ia), sizeof(c_int), cmp_func) #doctest: +SKIP py_cmp_func 5 1 py_cmp_func 33 99 py_cmp_func 7 33 @@ -1005,7 +1001,7 @@ ... return a[0] - b[0] ... >>> - >>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func)) # doctest: +LINUX + >>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func)) # doctest: +SKIP py_cmp_func 5 1 py_cmp_func 33 99 py_cmp_func 7 33 @@ -1015,7 +1011,7 @@ As we can easily check, our array is sorted now:: - >>> for i in ia: print(i, end=" ") + >>> for i in ia: print(i, end=" ") #doctest: +SKIP ... 1 5 7 33 99 >>> @@ -1042,7 +1038,7 @@ api:: >>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag") - >>> print(opt_flag) + >>> opt_flag c_long(0) >>> @@ -1086,13 +1082,14 @@ hit the NULL entry:: >>> for item in table: - ... print(item.name, item.size) - ... if item.name is None: - ... break + ... print(item.name, item.size) + ... if item.name is None: + ... break ... - __hello__ 104 - __phello__ -104 - __phello__.spam 104 + b'_frozen_importlib' 58358 + b'__hello__' 161 + b'__phello__' -161 + b'__phello__.spam' 161 None 0 >>> @@ -1150,9 +1147,9 @@ Another example that may behave different from what one would expect is this:: >>> s = c_char_p() - >>> s.value = "abc def ghi" + >>> s.value = b"abc def ghi" >>> s.value - 'abc def ghi' + b'abc def ghi' >>> s.value is s.value False >>> @@ -1178,7 +1175,7 @@ :exc:`ValueError` is raised if this is tried:: >>> short_array = (c_short * 4)() - >>> print(sizeof(short_array)) + >>> sizeof(short_array) 8 >>> resize(short_array, 4) Traceback (most recent call last): @@ -1247,11 +1244,11 @@ returns the filename of the library file. Here are some examples:: >>> from ctypes.util import find_library - >>> find_library("m") + >>> find_library("m") #doctest: +SKIP 'libm.so.6' - >>> find_library("c") + >>> find_library("c") #doctest: +SKIP 'libc.so.6' - >>> find_library("bz2") + >>> find_library("bz2") #doctest: +SKIP 'libbz2.so.1.0' >>> @@ -1259,13 +1256,13 @@ to locate the library, and returns a full pathname if successful:: >>> from ctypes.util import find_library - >>> find_library("c") + >>> find_library("c") #doctest: +SKIP '/usr/lib/libc.dylib' - >>> find_library("m") + >>> find_library("m") #doctest: +SKIP '/usr/lib/libm.dylib' - >>> find_library("bz2") + >>> find_library("bz2") #doctest: +SKIP '/usr/lib/libbz2.dylib' - >>> find_library("AGL") + >>> find_library("AGL") #doctest: +SKIP '/System/Library/Frameworks/AGL.framework/AGL' >>> @@ -1656,18 +1653,18 @@ Here is the wrapping with :mod:`ctypes`:: - >>> from ctypes import c_int, WINFUNCTYPE, windll - >>> from ctypes.wintypes import HWND, LPCSTR, UINT - >>> prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT) - >>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0) - >>> MessageBox = prototype(("MessageBoxA", windll.user32), paramflags) + >>> from ctypes import c_int, WINFUNCTYPE, windll #doctest: +SKIP + >>> from ctypes.wintypes import HWND, LPCSTR, UINT #doctest: +SKIP + >>> prototype = WINFUNCTYPE(c_int, HWND, LPCSTR, LPCSTR, UINT) #doctest: +SKIP + >>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", None), (1, "flags", 0) #doctest: +SKIP + >>> MessageBox = prototype(("MessageBoxA", windll.user32), paramflags) #doctest: +SKIP >>> The MessageBox foreign function can now be called in these ways:: - >>> MessageBox() - >>> MessageBox(text="Spam, spam, spam") - >>> MessageBox(flags=2, text="foo bar") + >>> MessageBox() #doctest: +SKIP + >>> MessageBox(text="Spam, spam, spam") #doctest: +SKIP + >>> MessageBox(flags=2, text="foo bar") #doctest: +SKIP >>> A second example demonstrates output parameters. The win32 ``GetWindowRect`` @@ -1681,11 +1678,11 @@ Here is the wrapping with :mod:`ctypes`:: - >>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError - >>> from ctypes.wintypes import BOOL, HWND, RECT - >>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT)) - >>> paramflags = (1, "hwnd"), (2, "lprect") - >>> GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags) + >>> from ctypes import POINTER, WINFUNCTYPE, windll, WinError #doctest: +SKIP + >>> from ctypes.wintypes import BOOL, HWND, RECT #doctest: +SKIP + >>> prototype = WINFUNCTYPE(BOOL, HWND, POINTER(RECT)) #doctest: +SKIP + >>> paramflags = (1, "hwnd"), (2, "lprect") #doctest: +SKIP + >>> GetWindowRect = prototype(("GetWindowRect", windll.user32), paramflags) #doctest: +SKIP >>> Functions with output parameters will automatically return the output parameter @@ -1703,7 +1700,7 @@ ... raise WinError() ... return args ... - >>> GetWindowRect.errcheck = errcheck + >>> GetWindowRect.errcheck = errcheck #doctest: +SKIP >>> If the :attr:`errcheck` function returns the argument tuple it receives @@ -1718,7 +1715,7 @@ ... rc = args[1] ... return rc.left, rc.top, rc.bottom, rc.right ... - >>> GetWindowRect.errcheck = errcheck + >>> GetWindowRect.errcheck = errcheck #doctest: +SKIP >>>