# `ctypes` — A foreign function library for Python

Source code: Lib/ctypes

`ctypes` — це бібліотека зовнішніх функцій для Python. Він надає C-сумісні типи даних і дозволяє викликати функції в DLL або спільних бібліотеках. Його можна використовувати, щоб обернути ці бібліотеки в чистий Python.

## підручник ctypes

Примітка: зразки коду в цьому підручнику використовують `doctest`, щоб переконатися, що вони справді працюють. Оскільки деякі зразки коду поводяться по-різному в Linux, Windows або macOS, вони містять директиви doctest у коментарях.

Примітка. Деякі зразки коду посилаються на тип ctypes `c_int`. На платформах, де `sizeof(long) == sizeof(int)`, це псевдонім `c_long`. Отже, вас не повинно бентежити, якщо надруковано `c_long`, якщо ви очікуєте `c_int` — вони насправді одного типу.

### Завантаження бібліотек динамічних посилань

`ctypes` експортує cdll, а в Windows об’єкти windll і oledll для завантаження бібліотек динамічних посилань.

You load libraries by accessing them as attributes of these objects. cdll loads libraries which export functions using the standard `cdecl` calling convention, while windll libraries call functions using the `stdcall` calling convention. oledll also uses the `stdcall` calling convention, and assumes the functions return a Windows `HRESULT` error code. The error code is used to automatically raise an `OSError` exception when the function call fails.

Змінено в версії 3.3: Помилки Windows викликали `WindowsError`, який тепер є псевдонімом `OSError`.

Here are some examples for Windows. Note that `msvcrt` is the MS standard C library containing most standard C functions, and uses the cdecl calling convention:

    >>> from ctypes import *
    >>> print(windll.kernel32)
    <WinDLL 'kernel32', handle ... at ...>
    >>> print(cdll.msvcrt)
    <CDLL 'msvcrt', handle ... at ...>
    >>> libc = cdll.msvcrt
    >>>

Windows автоматично додає звичайний суфікс файлу `.dll`.

Примітка

Доступ до стандартної бібліотеки C через `cdll.msvcrt` використовуватиме застарілу версію бібліотеки, яка може бути несумісною з тією, що використовується Python. Якщо можливо, використовуйте власні функції Python або імпортуйте та використовуйте модуль `msvcrt`.

On Linux, it is required to specify the filename including the extension to load a library, so attribute access can not be used to load libraries. Either the `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")
    <CDLL 'libc.so.6', handle ... at ...>
    >>> libc = CDLL("libc.so.6")
    >>> libc
    <CDLL 'libc.so.6', handle ... at ...>
    >>>

### Доступ до функцій із завантажених dll

Доступ до функцій здійснюється як атрибути об’єктів dll:

    >>> libc.printf
    <_FuncPtr object at 0x...>
    >>> print(windll.kernel32.GetModuleHandleA)
    <_FuncPtr object at 0x...>
    >>> print(windll.kernel32.MyOwnFunction)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "ctypes.py", line 239, in __getattr__
        func = _StdcallFuncPtr(name, self)
    AttributeError: function 'MyOwnFunction' not found
    >>>

Note that win32 system dlls like `kernel32` and `user32` often export ANSI as well as UNICODE versions of a function. The UNICODE version is exported with an `W` appended to the name, while the ANSI version is exported with an `A` appended to the name. The win32 `GetModuleHandle` function, which returns a module handle for a given module name, has the following C prototype, and a macro is used to expose one of them as `GetModuleHandle` depending on whether UNICODE is defined or not:

    /* ANSI version */
    HMODULE GetModuleHandleA(LPCSTR lpModuleName);
    /* UNICODE version */
    HMODULE GetModuleHandleW(LPCWSTR lpModuleName);

windll не намагається вибрати одну з них магією, ви повинні отримати доступ до потрібної вам версії, явно вказавши `GetModuleHandleA` або `GetModuleHandleW`, а потім викликати його за допомогою байтів або рядкових об’єктів відповідно.

Іноді бібліотеки dll експортують функції з іменами, які не є дійсними ідентифікаторами Python, наприклад `"??2@YAPAXI@Z"`. У цьому випадку ви повинні використовувати `getattr()`, щоб отримати функцію:

    >>> getattr(cdll.msvcrt, "??2@YAPAXI@Z")
    <_FuncPtr object at 0x...>
    >>>

У Windows деякі бібліотеки DLL експортують функції не за назвою, а за порядковим номером. Доступ до цих функцій можна отримати, проіндексувавши об’єкт dll з порядковим номером:

    >>> cdll.kernel32[1]
    <_FuncPtr object at 0x...>
    >>> cdll.kernel32[0]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "ctypes.py", line 310, in __getitem__
        func = _StdcallFuncPtr(name, self)
    AttributeError: function ordinal 0 not found
    >>>

### Функції виклику

You can call these functions like any other Python callable. This example uses the `time()` function, which returns system time in seconds since the Unix epoch, and the `GetModuleHandleA()` function, which returns a win32 module handle.

This example calls both functions with a `NULL` pointer (`None` should be used as the `NULL` pointer):

    >>> print(libc.time(None))
    1150640792
    >>> print(hex(windll.kernel32.GetModuleHandleA(None)))
    0x1d000000
    >>>

`ValueError` виникає, коли ви викликаєте функцію `stdcall` за угодою про виклик `cdecl`, або навпаки:

    >>> cdll.kernel32.GetModuleHandleA(None)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: Procedure probably called with not enough arguments (4 bytes missing)
    >>>

    >>> windll.msvcrt.printf(b"spam")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: Procedure probably called with too many arguments (4 bytes in excess)
    >>>

Щоб дізнатися правильну умову виклику, вам потрібно переглянути файл заголовка C або документацію для функції, яку ви хочете викликати.

У Windows `ctypes` використовує структуровану обробку винятків win32, щоб запобігти збоям через загальні помилки захисту, коли функції викликаються з недійсними значеннями аргументів:

    >>> windll.kernel32.GetModuleHandleA(32)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    OSError: exception: access violation reading 0x00000020
    >>>

Однак існує достатньо способів аварійно завершити роботу Python за допомогою `ctypes`, тому будьте обережні. Модуль `faulthandler` може бути корисним для усунення збоїв (наприклад, через помилки сегментації, спричинені помилковими викликами бібліотеки C).

`None`, integers, bytes objects and (unicode) strings are the only native Python objects that can directly be used as parameters in these function calls. `None` is passed as a C `NULL` pointer, bytes objects and strings are passed as pointer to the memory block that contains their data (char* or wchar_t*). Python integers are passed as the platforms default C int type, their value is masked to fit into the C type.

Перш ніж перейти до виклику функцій з іншими типами параметрів, ми повинні дізнатися більше про типи даних `ctypes`.

### Основні типи даних

`ctypes` визначає ряд примітивних C-сумісних типів даних:

тип ctypes | тип С | Тип Python
--- | --- | ---
`c_bool` | _Bool | bool (1)
`c_char` | char | 1-символьний об’єкт байтів
`c_wchar` | `wchar_t` | 1-символьний рядок
`c_byte` | char | внутр
`c_ubyte` | unsigned char | внутр
`c_short` | short | внутр
`c_ushort` | unsigned short | внутр
`c_int` | int | внутр
`c_uint` | unsigned int | внутр
`c_long` | long | внутр
`c_ulong` | unsigned long | внутр
`c_longlong` | __int64 or long long | внутр
`c_ulonglong` | unsigned __int64 or unsigned long long | внутр
`c_size_t` | `size_t` | внутр
`c_ssize_t` | `ssize_t` or Py_ssize_t | внутр
`c_float` | float | плавати
`c_double` | double | плавати
`c_longdouble` | long double | плавати
`c_char_p` | char* (NUL terminated) | bytes або `None`
`c_wchar_p` | wchar_t* (NUL terminated) | рядок або `None`
`c_void_p` | void* | int або `None`

1. Конструктор приймає будь-який об’єкт зі значенням істинності.

Усі ці типи можна створити, викликавши їх із необов’язковим ініціалізатором правильного типу та значення:

    >>> c_int()
    c_long(0)
    >>> c_wchar_p("Hello, World")
    c_wchar_p(140018365411392)
    >>> c_ushort(-3)
    c_ushort(65533)
    >>>

Оскільки ці типи є змінними, їх значення також можна змінити пізніше:

    >>> i = c_int(42)
    >>> print(i)
    c_long(42)
    >>> print(i.value)
    42
    >>> i.value = -99
    >>> print(i.value)
    -99
    >>>

Assigning a new value to instances of the pointer types `c_char_p`, `c_wchar_p`, and `c_void_p` changes the memory location they point to, not the contents of the memory block (of course not, because Python bytes objects are immutable):

    >>> s = "Hello, World"
    >>> c_s = c_wchar_p(s)
    >>> print(c_s)
    c_wchar_p(139966785747344)
    >>> print(c_s.value)
    Hello World
    >>> c_s.value = "Hi, there"
    >>> print(c_s)              # the memory location has changed
    c_wchar_p(139966783348904)
    >>> print(c_s.value)
    Hi, there
    >>> print(s)                # first object is unchanged
    Hello, World
    >>>

Однак ви повинні бути обережними, щоб не передавати їх функціям, які очікують покажчиків на змінну пам’ять. Якщо вам потрібні змінні блоки пам’яті, ctypes має функцію `create_string_buffer()`, яка створює їх різними способами. Доступ до поточного вмісту блоку пам’яті можна отримати (або змінити) за допомогою властивості `raw`; якщо ви бажаєте отримати до нього доступ як до рядка з закінченням NUL, використовуйте властивість `value`:

    >>> from ctypes import *
    >>> p = create_string_buffer(3)            # create a 3 byte buffer, initialized to NUL bytes
    >>> print(sizeof(p), repr(p.raw))
    3 b'\x00\x00\x00'
    >>> 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))
    b'Hello'
    >>> p = create_string_buffer(b"Hello", 10) # create a 10 byte buffer
    >>> print(sizeof(p), repr(p.raw))
    10 b'Hello\x00\x00\x00\x00\x00'
    >>> p.value = b"Hi"
    >>> print(sizeof(p), repr(p.raw))
    10 b'Hi\x00lo\x00\x00\x00\x00\x00'
    >>>

The `create_string_buffer()` function replaces the old `c_buffer()` function (which is still available as an alias). To create a mutable memory block containing unicode characters of the C type `wchar_t`, use the `create_unicode_buffer()` function.

### Функції виклику, продовження

Зауважте, що printf друкує на справжній стандартний канал виводу, а не на `sys.stdout`, тому ці приклади працюватимуть лише у підказці консолі, а не з IDLE або PythonWin:

    >>> printf = libc.printf
    >>> printf(b"Hello, %s\n", b"World!")
    Hello, World!
    14
    >>> printf(b"Hello, %S\n", "World!")
    Hello, World!
    14
    >>> printf(b"%d bottles of beer\n", 42)
    42 bottles of beer
    19
    >>> printf(b"%f bottles of beer\n", 42.5)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ArgumentError: argument 2: TypeError: Don't know how to convert parameter 2
    >>>

Як уже згадувалося раніше, усі типи Python, окрім цілих, рядкових і байтових об’єктів, мають бути загорнуті у відповідний тип `ctypes`, щоб їх можна було перетворити на необхідний тип даних C:

    >>> printf(b"An int %d, a double %f\n", 1234, c_double(3.14))
    An int 1234, a double 3.140000
    31
    >>>

### Calling variadic functions

On a lot of platforms calling variadic functions through ctypes is exactly the same as calling functions with a fixed number of parameters. On some platforms, and in particular ARM64 for Apple Platforms, the calling convention for variadic functions is different than that for regular functions.

On those platforms it is required to specify the argtypes attribute for the regular, non-variadic, function arguments:

    libc.printf.argtypes = [ctypes.c_char_p]

Because specifying the attribute does not inhibit portability it is advised to always specify `argtypes` for all variadic functions.

### Виклик функцій із власними типами даних

You can also customize `ctypes` argument conversion to allow instances of your own classes be used as function arguments. `ctypes` looks for an `_as_parameter_` attribute and uses this as the function argument. The attribute must be an integer, string, bytes, a `ctypes` instance, or an object with an `_as_parameter_` attribute:

    >>> class Bottles:
    ...     def __init__(self, number):
    ...         self._as_parameter_ = number
    ...
    >>> bottles = Bottles(42)
    >>> printf(b"%d bottles of beer\n", bottles)
    42 bottles of beer
    19
    >>>

If you don’t want to store the instance’s data in the `_as_parameter_` instance variable, you could define a `property` which makes the attribute available on request.

### Вказівка необхідних типів аргументів (прототипів функцій)

It is possible to specify the required argument types of functions exported from DLLs by setting the `argtypes` attribute.

`argtypes` must be a sequence of C data types (the `printf` function is probably not a good example here, because it takes a variable number and 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)
    String 'Hi', Int 10, Double 2.200000
    37
    >>>

Зазначення формату захищає від несумісних типів аргументів (як прототип для функції C) і намагається перетворити аргументи на дійсні типи:

    >>> printf(b"%d %d %d", 1, 2, 3)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ArgumentError: argument 2: TypeError: wrong type
    >>> printf(b"%s %d %f\n", b"X", 2, 3)
    X 2 3.000000
    13
    >>>

If you have defined your own classes which you pass to function calls, you have to implement a `from_param()` class method for them to be able to use them in the `argtypes` sequence. The `from_param()` class method receives the Python object passed to the function call, it should do a typecheck or whatever is needed to make sure this object is acceptable, and then return the object itself, its `_as_parameter_` attribute, or whatever you want to pass as the C function argument in this case. Again, the result should be an integer, string, bytes, a `ctypes` instance, or an object with an `_as_parameter_` attribute.

### Типи повернення

By default functions are assumed to return the C int type. Other return types can be specified by setting the `restype` attribute of the function object.

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"))
    8059983
    >>> strchr.restype = c_char_p    # c_char_p is a pointer to a string
    >>> strchr(b"abcdef", ord("d"))
    b'def'
    >>> print(strchr(b"abcdef", ord("x")))
    None
    >>>

If you want to avoid the `ord("x")` calls above, you can set the `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")
    'def'
    >>> strchr(b"abcdef", b"def")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ArgumentError: argument 2: TypeError: one character string expected
    >>> print(strchr(b"abcdef", b"x"))
    None
    >>> strchr(b"abcdef", b"d")
    'def'
    >>>

You can also use a callable Python object (a function or a class for example) as the `restype` attribute, if the foreign function returns an integer. The callable will be called with the integer the C function returns, and the 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
    >>> def ValidHandle(value):
    ...     if value == 0:
    ...         raise WinError()
    ...     return value
    ...
    >>>
    >>> GetModuleHandle.restype = ValidHandle
    >>> GetModuleHandle(None)
    486539264
    >>> GetModuleHandle("something silly")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 3, in ValidHandle
    OSError: [Errno 126] The specified module could not be found.
    >>>

`WinError` — це функція, яка викликає Windows `FormatMessage()` API, щоб отримати рядкове представлення коду помилки, і повертає виняткову ситуацію. `WinError` приймає додатковий параметр коду помилки, якщо ніхто не використовується, він викликає `GetLastError()`, щоб отримати його.

Please note that a much more powerful error checking mechanism is available through the `errcheck` attribute; see the reference manual for details.

### Передача покажчиків (або: передача параметрів за посиланням)

Іноді функція C API очікує вказівника на тип даних як параметр, ймовірно, для запису у відповідне розташування або якщо дані завеликі для передачі за значенням. Це також відомо як передача параметрів за посиланням.

`ctypes` експортує функцію `byref()`, яка використовується для передачі параметрів за посиланням. Такого ж ефекту можна досягти за допомогою функції `pointer()`, хоча `pointer()` виконує набагато більше роботи, оскільки створює справжній об’єкт-вказівник, тому використовувати `byref()` швидше не потрібен об’єкт покажчика в самому Python:

    >>> i = c_int()
    >>> f = c_float()
    >>> s = create_string_buffer(b'\000' * 32)
    >>> 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)
    3
    >>> print(i.value, f.value, repr(s.value))
    1 3.1400001049 b'Hello'
    >>>

### Структури та спілки

Structures and unions must derive from the `Structure` and `Union` base classes which are defined in the `ctypes` module. Each subclass must define a `_fields_` attribute. `_fields_` must be a list of 2-tuples, containing a field name and a field type.

Тип поля має бути типу `ctypes`, наприклад `c_int`, або будь-якого іншого похідного типу `ctypes`: структура, об’єднання, масив, покажчик.

Ось простий приклад структури POINT, яка містить два цілі числа з іменами x і y, а також показує, як ініціалізувати структуру в конструкторі:

    >>> from ctypes import *
    >>> class POINT(Structure):
    ...     _fields_ = [("x", c_int),
    ...                 ("y", c_int)]
    ...
    >>> point = POINT(10, 20)
    >>> print(point.x, point.y)
    10 20
    >>> point = POINT(y=5)
    >>> print(point.x, point.y)
    0 5
    >>> POINT(1, 2, 3)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: too many initializers
    >>>

Однак можна будувати набагато складніші конструкції. Структура може сама містити інші структури, використовуючи структуру як тип поля.

Ось структура RECT, яка містить дві ТОЧКИ з іменами upperleft і lowerright:

    >>> class RECT(Structure):
    ...     _fields_ = [("upperleft", POINT),
    ...                 ("lowerright", POINT)]
    ...
    >>> rc = RECT(point)
    >>> print(rc.upperleft.x, rc.upperleft.y)
    0 5
    >>> print(rc.lowerright.x, rc.lowerright.y)
    0 0
    >>>

Вкладені структури також можна ініціалізувати в конструкторі кількома способами:

    >>> r = RECT(POINT(1, 2), POINT(3, 4))
    >>> r = RECT((1, 2), (3, 4))

Поля descriptors можна отримати з класу, вони корисні для налагодження, оскільки можуть надати корисну інформацію:

    >>> print(POINT.x)
    <Field type=c_long, ofs=0, size=4>
    >>> print(POINT.y)
    <Field type=c_long, ofs=4, size=4>
    >>>

Попередження

`ctypes` не підтримує передачу об’єднань або структур із бітовими полями функціям за значенням. Хоча це може працювати на 32-розрядних x86, бібліотека не гарантує роботу в загальному випадку. Об’єднання та структури з бітовими полями слід завжди передавати функціям за вказівником.

### Вирівнювання структури/об’єднання та порядок байтів

By default, Structure and Union fields are aligned in the same way the C compiler does it. It is possible to override this behavior by specifying a `_pack_` class attribute in the subclass definition. This must be set to a positive integer and specifies the maximum alignment for the fields. This is what `#pragma pack(n)` also does in MSVC.

`ctypes` використовує власний порядок байтів для структур і об’єднань. Щоб створити структури з невласним порядком байтів, ви можете використовувати один із базових класів `BigEndianStructure`, `LittleEndianStructure`, `BigEndianUnion` і `LittleEndianUnion`. Ці класи не можуть містити поля вказівників.

### Бітові поля в структурах і об’єднаннях

It is possible to create structures and unions containing bit fields. Bit fields are only possible for integer fields, the bit width is specified as the third item in the `_fields_` tuples:

    >>> class Int(Structure):
    ...     _fields_ = [("first_16", c_int, 16),
    ...                 ("second_16", c_int, 16)]
    ...
    >>> print(Int.first_16)
    <Field type=c_long, ofs=0:0, bits=16>
    >>> print(Int.second_16)
    <Field type=c_long, ofs=0:16, bits=16>
    >>>

### Масиви

Масиви - це послідовності, що містять фіксовану кількість екземплярів одного типу.

Рекомендований спосіб створення типів масивів – це множення типу даних на додатне ціле:

    TenPointsArrayType = POINT * 10

Ось приклад дещо штучного типу даних, структура, яка містить 4 ТОЧКИ серед іншого:

    >>> from ctypes import *
    >>> class POINT(Structure):
    ...     _fields_ = ("x", c_int), ("y", c_int)
    ...
    >>> class MyStruct(Structure):
    ...     _fields_ = [("a", c_int),
    ...                 ("b", c_float),
    ...                 ("point_array", POINT * 4)]
    >>>
    >>> print(len(MyStruct().point_array))
    4
    >>>

Екземпляри створюються звичайним способом за допомогою виклику класу:

    arr = TenPointsArrayType()
    for pt in arr:
        print(pt.x, pt.y)

Наведений вище код друкує серію рядків `0 0`, оскільки вміст масиву ініціалізовано нулями.

Також можна вказати ініціалізатори правильного типу:

    >>> from ctypes import *
    >>> TenIntegers = c_int * 10
    >>> ii = TenIntegers(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    >>> print(ii)
    <c_long_Array_10 object at 0x...>
    >>> for i in ii: print(i, end=" ")
    ...
    1 2 3 4 5 6 7 8 9 10
    >>>

### Покажчики

Екземпляри вказівника створюються шляхом виклику функції `pointer()` для типу `ctypes`:

    >>> from ctypes import *
    >>> i = c_int(42)
    >>> pi = pointer(i)
    >>>

Екземпляри вказівника мають атрибут `contents`, який повертає об’єкт, на який вказує вказівник, об’єкт `i` вище:

    >>> pi.contents
    c_long(42)
    >>>

Зауважте, що `ctypes` не має OOR (повернення вихідного об’єкта), він створює новий, еквівалентний об’єкт кожного разу, коли ви отримуєте атрибут:

    >>> pi.contents is i
    False
    >>> pi.contents is pi.contents
    False
    >>>

Призначення іншого екземпляра `c_int` атрибуту contents вказівника призведе до того, що вказівник вказуватиме на місце пам’яті, де це зберігається:

    >>> i = c_int(99)
    >>> pi.contents = i
    >>> pi.contents
    c_long(99)
    >>>

Екземпляри вказівників також можна індексувати цілими числами:

    >>> pi[0]
    99
    >>>

Присвоєння цілочисельному індексу змінює вказане значення:

    >>> print(i)
    c_long(99)
    >>> pi[0] = 22
    >>> print(i)
    c_long(22)
    >>>

Також можна використовувати індекси, відмінні від 0, але ви повинні знати, що ви робите, так само як у C: ви можете отримати доступ або змінити довільні місця пам’яті. Зазвичай ви використовуєте цю функцію, лише якщо отримуєте вказівник від функції C і знаєте, що вказівник насправді вказує на масив, а не на один елемент.

За лаштунками функція `pointer()` робить більше, ніж просто створює екземпляри вказівників, вона повинна спочатку створити типи вказівників. Це робиться за допомогою функції `POINTER()`, яка приймає будь-який тип `ctypes` і повертає новий тип:

    >>> PI = POINTER(c_int)
    >>> PI
    <class 'ctypes.LP_c_long'>
    >>> PI(42)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: expected c_long instead of int
    >>> PI(c_int(42))
    <ctypes.LP_c_long object at 0x...>
    >>>

Виклик типу покажчика без аргументу створює покажчик `NULL`. Покажчики `NULL` мають логічне значення `False`:

    >>> null_ptr = POINTER(c_int)()
    >>> print(bool(null_ptr))
    False
    >>>

`ctypes` перевіряє `NULL` під час розіменування вказівників (але розіменування недійсних не`NULL` вказівників призведе до збою Python):

    >>> null_ptr[0]
    Traceback (most recent call last):
        ....
    ValueError: NULL pointer access
    >>>

    >>> null_ptr[0] = 1234
    Traceback (most recent call last):
        ....
    ValueError: NULL pointer access
    >>>

### Перетворення типів

Usually, ctypes does strict type checking. This means, if you have `POINTER(c_int)` in the `argtypes` list of a function or as the type of a member field in a structure definition, only instances of exactly the same type are accepted. There are some exceptions to this rule, where ctypes accepts other objects. For example, you can pass compatible array instances instead of pointer types. So, for `POINTER(c_int)`, ctypes accepts an array of c_int:

    >>> class Bar(Structure):
    ...     _fields_ = [("count", c_int), ("values", POINTER(c_int))]
    ...
    >>> bar = Bar()
    >>> bar.values = (c_int * 3)(1, 2, 3)
    >>> bar.count = 3
    >>> for i in range(bar.count):
    ...     print(bar.values[i])
    ...
    1
    2
    3
    >>>

In addition, if a function argument is explicitly declared to be a pointer type (such as `POINTER(c_int)`) in `argtypes`, an object of the pointed type (`c_int` in this case) can be passed to the function. ctypes will apply the required `byref()` conversion in this case automatically.

Щоб встановити для поля типу POINTER значення `NULL`, ви можете призначити `None`:

    >>> bar.values = None
    >>>

Іноді у вас є екземпляри несумісних типів. У C ви можете привести один тип до іншого. `ctypes` надає функцію `cast()`, яку можна використовувати таким же чином. Структура `Bar`, визначена вище, приймає покажчики `POINTER(c_int)` або `c_int` масиви для свого поля `values`, але не примірники інших типів:

    >>> bar.values = (c_byte * 4)()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: incompatible types, c_byte_Array_4 instance instead of LP_c_long instance
    >>>

Для цих випадків зручна функція `cast()`.

Функцію `cast()` можна використати для приведення екземпляра ctypes до покажчика на інший тип даних ctypes. `cast()` приймає два параметри: об’єкт ctypes, який є чи може бути перетворений на певний вказівник, і тип вказівника ctypes. Він повертає екземпляр другого аргументу, який посилається на той самий блок пам’яті, що й перший аргумент:

    >>> a = (c_byte * 4)()
    >>> cast(a, POINTER(c_int))
    <ctypes.LP_c_long object at ...>
    >>>

Отже, `cast()` можна використовувати для призначення полю `values` `Bar` структури:

    >>> bar = Bar()
    >>> bar.values = cast((c_byte * 4)(), POINTER(c_int))
    >>> print(bar.values[0])
    0
    >>>

### Неповні типи

Неповні типи — це структури, об’єднання або масиви, члени яких ще не визначено. У C вони визначені прямими оголошеннями, які визначені пізніше:

    struct cell; /* forward declaration */

    struct cell {
        char *name;
        struct cell *next;
    };

Прямий переклад у код ctypes буде таким, але він не працює:

    >>> class cell(Structure):
    ...     _fields_ = [("name", c_char_p),
    ...                 ("next", POINTER(cell))]
    ...
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "<stdin>", line 2, in cell
    NameError: name 'cell' is not defined
    >>>

because the new `class cell` is not available in the class statement itself. In `ctypes`, we can define the `cell` class and set the `_fields_` attribute later, after the class statement:

    >>> from ctypes import *
    >>> class cell(Structure):
    ...     pass
    ...
    >>> cell._fields_ = [("name", c_char_p),
    ...                  ("next", POINTER(cell))]
    >>>

Давайте спробуємо. Ми створюємо два екземпляри `cell` і дозволяємо їм вказувати один на одного, і, нарешті, слідуємо за ланцюжком вказівників кілька разів:

    >>> c1 = cell()
    >>> c1.name = b"foo"
    >>> c2 = cell()
    >>> c2.name = b"bar"
    >>> c1.next = pointer(c2)
    >>> c2.next = pointer(c1)
    >>> p = c1
    >>> for i in range(8):
    ...     print(p.name, end=" ")
    ...     p = p.next[0]
    ...
    foo bar foo bar foo bar foo bar
    >>>

### Функції зворотного виклику

`ctypes` дозволяє створювати вказівники на функції C із викликів Python. Іноді їх називають функціями зворотного виклику.

По-перше, ви повинні створити клас для функції зворотного виклику. Клас знає угоду про виклики, тип повернення, а також кількість і типи аргументів, які ця функція отримає.

Фабрична функція `CFUNCTYPE()` створює типи для функцій зворотного виклику за допомогою угоди про виклики `cdecl`. У Windows фабрична функція `WINFUNCTYPE()` створює типи для функцій зворотного виклику за допомогою угоди про виклики `stdcall`.

Обидві ці фабричні функції викликаються з типом результату як першим аргументом, а функції зворотного виклику – очікуваними типами аргументів як рештою аргументів.

I will present an example here which uses the standard C library’s `qsort()` function, that is used to sort items with the help of a callback function. `qsort()` will be used to sort an array of integers:

    >>> IntArray5 = c_int * 5
    >>> ia = IntArray5(5, 1, 7, 33, 99)
    >>> qsort = libc.qsort
    >>> qsort.restype = None
    >>>

`qsort()` must be called with a pointer to the data to sort, the number of items in the data array, the size of one item, and a pointer to the comparison function, the callback. The callback will then be called with two pointers to items, and it must return a negative integer if the first item is smaller than the second, a zero if they are equal, and a positive integer otherwise.

Таким чином, наша функція зворотного виклику отримує покажчики на цілі числа та повинна повертати ціле число. Спочатку ми створюємо `type` для функції зворотного виклику:

    >>> CMPFUNC = CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
    >>>

Щоб почати, ось простий зворотний виклик, який показує значення, які він отримує:

    >>> def py_cmp_func(a, b):
    ...     print("py_cmp_func", a[0], b[0])
    ...     return 0
    ...
    >>> cmp_func = CMPFUNC(py_cmp_func)
    >>>

Результат:

    >>> qsort(ia, len(ia), sizeof(c_int), cmp_func)
    py_cmp_func 5 1
    py_cmp_func 33 99
    py_cmp_func 7 33
    py_cmp_func 5 7
    py_cmp_func 1 7
    >>>

Тепер ми фактично можемо порівняти два елементи та повернути корисний результат:

    >>> def py_cmp_func(a, b):
    ...     print("py_cmp_func", a[0], b[0])
    ...     return a[0] - b[0]
    ...
    >>>
    >>> qsort(ia, len(ia), sizeof(c_int), CMPFUNC(py_cmp_func))
    py_cmp_func 5 1
    py_cmp_func 33 99
    py_cmp_func 7 33
    py_cmp_func 1 7
    py_cmp_func 5 7
    >>>

Як ми можемо легко перевірити, наш масив зараз відсортовано:

    >>> for i in ia: print(i, end=" ")
    ...
    1 5 7 33 99
    >>>

Фабрики функцій можна використовувати як фабрики декораторів, тому ми також можемо написати:

    >>> @CFUNCTYPE(c_int, POINTER(c_int), POINTER(c_int))
    ... def py_cmp_func(a, b):
    ...     print("py_cmp_func", a[0], b[0])
    ...     return a[0] - b[0]
    ...
    >>> qsort(ia, len(ia), sizeof(c_int), py_cmp_func)
    py_cmp_func 5 1
    py_cmp_func 33 99
    py_cmp_func 7 33
    py_cmp_func 1 7
    py_cmp_func 5 7
    >>>

Примітка

Переконайтеся, що ви зберігаєте посилання на об’єкти `CFUNCTYPE()`, доки вони використовуються з коду C. `ctypes` не працює, і якщо ви цього не зробите, вони можуть збиратися як сміття, що призведе до збою вашої програми під час зворотного виклику.

Також зауважте, що якщо функція зворотнього виклику викликається в потоці, створеному поза контролем Python (наприклад, зовнішнім кодом, який викликає зворотній виклик), ctypes створює новий фіктивний потік Python під час кожного виклику. Така поведінка є правильною для більшості цілей, але це означає, що значення, збережені в `threading.local` не збережуться в різних зворотних викликах, навіть якщо ці виклики здійснюються з того самого потоку C.

### Доступ до значень, експортованих із dll

Some shared libraries not only export functions, they also export variables. An example in the Python library itself is the `Py_OptimizeFlag`, an integer set to 0, 1, or 2, depending on the `-O` or `-OO` flag given on startup.

`ctypes` can access values like this with the `in_dll()` class methods of the type. pythonapi is a predefined symbol giving access to the Python C api:

    >>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag")
    >>> print(opt_flag)
    c_long(0)
    >>>

If the interpreter would have been started with `-O`, the sample would have printed `c_long(1)`, or `c_long(2)` if `-OO` would have been specified.

Розширений приклад, який також демонструє використання покажчиків, звертається до покажчика `PyImport_FrozenModules`, експортованого Python.

Цитування документів для цього значення:

> This pointer is initialized to point to an array of `_frozen` records, terminated by one whose members are all `NULL` or zero. When a frozen module is imported, it is searched in this table. Third-party code could play tricks with this to provide a dynamically created collection of frozen modules.

Тож маніпулювання цим покажчиком може навіть виявитися корисним. Щоб обмежити розмір прикладу, ми показуємо лише те, як цю таблицю можна прочитати за допомогою `ctypes`:

    >>> from ctypes import *
    >>>
    >>> class struct_frozen(Structure):
    ...     _fields_ = [("name", c_char_p),
    ...                 ("code", POINTER(c_ubyte)),
    ...                 ("size", c_int),
    ...                 ("get_code", POINTER(c_ubyte)),  # Function pointer
    ...                ]
    ...
    >>>

We have defined the `_frozen` data type, so we can get the pointer to the table:

    >>> FrozenTable = POINTER(struct_frozen)
    >>> table = FrozenTable.in_dll(pythonapi, "_PyImport_FrozenBootstrap")
    >>>

Оскільки `table` є `покажчиком` на масив `struct_frozen` записів, ми можемо перебирати його, але нам просто потрібно переконатися, що наш цикл завершується, оскільки покажчики не мають розміру. Рано чи пізно він, ймовірно, вийде з ладу через порушення прав доступу чи щось інше, тому краще вийти з циклу, коли ми натиснемо запис `NULL`:

    >>> for item in table:
    ...     if item.name is None:
    ...         break
    ...     print(item.name.decode("ascii"), item.size)
    ...
    _frozen_importlib 31764
    _frozen_importlib_external 41499
    zipimport 12345
    >>>

Той факт, що стандартний Python має заморожений модуль і заморожений пакет (позначений від’ємним елементом `size`), невідомий, він використовується лише для тестування. Спробуйте, наприклад, `import __hello__`.

### Сюрпризи

У `ctypes` є деякі переваги, де ви можете очікувати щось інше, ніж те, що відбувається насправді.

Розглянемо такий приклад:

    >>> from ctypes import *
    >>> class POINT(Structure):
    ...     _fields_ = ("x", c_int), ("y", c_int)
    ...
    >>> class RECT(Structure):
    ...     _fields_ = ("a", POINT), ("b", POINT)
    ...
    >>> p1 = POINT(1, 2)
    >>> p2 = POINT(3, 4)
    >>> rc = RECT(p1, p2)
    >>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)
    1 2 3 4
    >>> # now swap the two points
    >>> rc.a, rc.b = rc.b, rc.a
    >>> print(rc.a.x, rc.a.y, rc.b.x, rc.b.y)
    3 4 3 4
    >>>

Хм Ми, безумовно, очікували, що останній оператор виведе `3 4 1 2`. Що трапилось? Ось кроки рядка `rc.a, rc.b = rc.b, rc.a`:

    >>> temp0, temp1 = rc.b, rc.a
    >>> rc.a = temp0
    >>> rc.b = temp1
    >>>

Зауважте, що `temp0` і `temp1` є об’єктами, які все ще використовують внутрішній буфер об’єкта `rc` вище. Отже, виконання `rc.a = temp0` копіює вміст буфера `temp0` у буфер `rc`. Це, у свою чергу, змінює вміст `temp1`. Отже, останнє призначення `rc.b = temp1` не має очікуваного ефекту.

Майте на увазі, що отримання підоб’єктів зі структур, об’єднань і масивів не копіює підоб’єкт, натомість отримує обгортку об’єкта, який отримує доступ до основного буфера кореневого об’єкта.

Інший приклад, який може поводитися інакше, ніж очікувалося, це:

    >>> s = c_char_p()
    >>> s.value = b"abc def ghi"
    >>> s.value
    b'abc def ghi'
    >>> s.value is s.value
    False
    >>>

Примітка

Об’єкти, створені з `c_char_p`, можуть мати значення лише байтів або цілих чисел.

Чому він друкує `False`? Екземпляри ctypes — це об’єкти, що містять блок пам’яті плюс деякі descriptor, що мають доступ до вмісту пам’яті. Зберігання об’єкта Python у блоці пам’яті не зберігає сам об’єкт, натомість зберігається `вміст` об’єкта. Повторний доступ до вмісту щоразу створює новий об’єкт Python!

### Типи даних змінного розміру

`ctypes` забезпечує деяку підтримку для масивів і структур змінного розміру.

Функцію `resize()` можна використовувати для зміни розміру буфера пам’яті існуючого об’єкта ctypes. Функція приймає об’єкт як перший аргумент, а запитуваний розмір у байтах як другий аргумент. Блок пам’яті не може бути меншим, ніж природний блок пам’яті, визначений типом об’єкта, `ValueError` виникає, якщо це спробувати:

    >>> short_array = (c_short * 4)()
    >>> print(sizeof(short_array))
    8
    >>> resize(short_array, 4)
    Traceback (most recent call last):
        ...
    ValueError: minimum size is 8
    >>> resize(short_array, 32)
    >>> sizeof(short_array)
    32
    >>> sizeof(type(short_array))
    8
    >>>

Це гарно і добре, але як отримати доступ до додаткових елементів, що містяться в цьому масиві? Оскільки тип все ще знає лише про 4 елементи, ми отримуємо помилки під час доступу до інших елементів:

    >>> short_array[:]
    [0, 0, 0, 0]
    >>> short_array[7]
    Traceback (most recent call last):
        ...
    IndexError: invalid index
    >>>

Інший спосіб використання типів даних змінного розміру з `ctypes` — це використання динамічної природи Python і (повторне) визначення типу даних після того, як потрібний розмір уже відомий, у кожному конкретному випадку.

## посилання на ctypes

### Пошук спільних бібліотек

Під час програмування скомпільованою мовою доступ до спільних бібліотек здійснюється під час компіляції/зв’язування програми та під час виконання програми.

The purpose of the `find_library()` function is to locate a library in a way similar to what the compiler or runtime loader does (on platforms with several versions of a shared library the most recent should be loaded), while the ctypes library loaders act like when a program is run, and call the runtime loader directly.

The `ctypes.util` module provides a function which can help to determine the library to load.

ctypes.util.find_library(name)

  Спробуйте знайти бібліотеку та повернути шлях. name — це назва бібліотеки без будь-якого префікса, як-от lib, суфікса, як-от `.so`, `.dylib` або номера версії (це форма, яка використовується для параметра компонування posix `- l`). Якщо бібліотеки не знайдено, повертає `None`.

Точна функція залежить від системи.

On Linux, `find_library()` tries to run external programs (`/sbin/ldconfig`, `gcc`, `objdump` and `ld`) to find the library file. It returns the filename of the library file.

Змінено в версії 3.6: У Linux значення змінної середовища `LD_LIBRARY_PATH` використовується під час пошуку бібліотек, якщо бібліотеку неможливо знайти будь-яким іншим способом.

Ось кілька прикладів:

    >>> from ctypes.util import find_library
    >>> find_library("m")
    'libm.so.6'
    >>> find_library("c")
    'libc.so.6'
    >>> find_library("bz2")
    'libbz2.so.1.0'
    >>>

On macOS, `find_library()` tries several predefined naming schemes and paths to locate the library, and returns a full pathname if successful:

    >>> from ctypes.util import find_library
    >>> find_library("c")
    '/usr/lib/libc.dylib'
    >>> find_library("m")
    '/usr/lib/libm.dylib'
    >>> find_library("bz2")
    '/usr/lib/libbz2.dylib'
    >>> find_library("AGL")
    '/System/Library/Frameworks/AGL.framework/AGL'
    >>>

On Windows, `find_library()` searches along the system search path, and returns the full pathname, but since there is no predefined naming scheme a call like `find_library("c")` will fail and return `None`.

If wrapping a shared library with `ctypes`, it may be better to determine the shared library name at development time, and hardcode that into the wrapper module instead of using `find_library()` to locate the library at runtime.

### Завантаження спільних бібліотек

Є кілька способів завантажити спільні бібліотеки в процес Python. Одним із способів є створення екземпляра одного з наступних класів:

class ctypes.CDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)

  Instances of this class represent loaded shared libraries. Functions in these libraries use the standard C calling convention, and are assumed to return int.

  У Windows створення екземпляра `CDLL` може завершитися помилкою, навіть якщо ім’я DLL існує. Якщо залежну DLL від завантаженої DLL не знайдено, виникає помилка `OSError` із повідомленням «[WinError 126] Не вдалося знайти вказаний модуль». Це повідомлення про помилку не містить назви відсутня DLL, оскільки Windows API не повертає цю інформацію, що ускладнює діагностику цієї помилки. Щоб усунути цю помилку та визначити, яку DLL не знайдено, потрібно знайти список залежних DLL і визначити, яка з них не знайдена, за допомогою засобів налагодження та трасування Windows.

Дивись також

Інструмент Microsoft DUMPBIN – Інструмент для пошуку залежних DLL.

class ctypes.OleDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)

  Windows only: Instances of this class represent loaded shared libraries, functions in these libraries use the `stdcall` calling convention, and are assumed to return the windows specific `HRESULT` code. `HRESULT` values contain information specifying whether the function call failed or succeeded, together with additional error code. If the return value signals a failure, an `OSError` is automatically raised.

  Змінено в версії 3.3: `WindowsError` used to be raised, which is now an alias of `OSError`.

class ctypes.WinDLL(name, mode=DEFAULT_MODE, handle=None, use_errno=False, use_last_error=False, winmode=None)

  Windows only: Instances of this class represent loaded shared libraries, functions in these libraries use the `stdcall` calling convention, and are assumed to return int by default.

global interpreter lock Python знімається перед викликом будь-якої функції, експортованої цими бібліотеками, і знову отримується після цього.

class ctypes.PyDLL(name, mode=DEFAULT_MODE, handle=None)

  Екземпляри цього класу поводяться як екземпляри `CDLL`, за винятком того, що GIL Python не звільняється під час виклику функції, а після виконання функції перевіряється позначка помилки Python. Якщо встановлено позначку помилки, виникає виняток Python.

  Таким чином, це корисно лише для прямого виклику API-функцій Python C.

All these classes can be instantiated by calling them with at least one argument, the pathname of the shared library. If you have an existing handle to an already loaded shared library, it can be passed as the `handle` named parameter, otherwise the underlying platforms `dlopen` or `LoadLibrary` function is used to load the library into the process, and to get a handle to it.

Параметр mode можна використовувати для визначення способу завантаження бібліотеки. Додаткову інформацію див. на сторінці довідки dlopen(3). У Windows режим ігнорується. У системах posix RTLD_NOW завжди додається та не налаштовується.

The use_errno parameter, when set to true, enables a ctypes mechanism that allows accessing the system `errno` error number in a safe way. `ctypes` maintains a thread-local copy of the systems `errno` variable; if you call foreign functions created with `use_errno=True` then the `errno` value before the function call is swapped with the ctypes private copy, the same happens immediately after the function call.

Функція `ctypes.get_errno()` повертає значення приватної копії ctypes, а функція `ctypes.set_errno()` змінює приватну копію ctypes на нове значення та повертає попереднє значення.

The use_last_error parameter, when set to true, enables the same mechanism for the Windows error code which is managed by the `GetLastError()` and `SetLastError()` Windows API functions; `ctypes.get_last_error()` and `ctypes.set_last_error()` are used to request and change the ctypes private copy of the windows error code.

The winmode parameter is used on Windows to specify how the library is loaded (since mode is ignored). It takes any value that is valid for the Win32 API `LoadLibraryEx` flags parameter. When omitted, the default is to use the flags that result in the most secure DLL load to avoiding issues such as DLL hijacking. Passing the full path to the DLL is the safest way to ensure the correct library and dependencies are loaded.

Змінено в версії 3.8: Додано параметр winmode.

ctypes.RTLD_GLOBAL

  Прапор для використання як параметр mode. На платформах, де цей прапорець недоступний, він визначається як цілий нуль.

ctypes.RTLD_LOCAL

  Прапор для використання як параметр mode. На платформах, де це недоступно, це те саме, що RTLD_GLOBAL.

ctypes.DEFAULT_MODE

  Типовий режим, який використовується для завантаження спільних бібліотек. В OSX 10.3 це RTLD_GLOBAL, інакше це те саме, що RTLD_LOCAL.

Екземпляри цих класів не мають відкритих методів. Доступ до функцій, експортованих спільною бібліотекою, можна отримати як за атрибутами або за індексом. Будь ласка, зверніть увагу, що доступ до функції через атрибут кешує результат, тому повторний доступ повертає той самий об’єкт щоразу. З іншого боку, доступ до нього через індекс кожного разу повертає новий об’єкт:

    >>> from ctypes import CDLL
    >>> libc = CDLL("libc.so.6")  # On Linux
    >>> libc.time == libc.time
    True
    >>> libc['time'] == libc['time']
    False

Доступні такі загальнодоступні атрибути, їх імена починаються з підкреслення, щоб не суперечити ім’ям експортованих функцій:

PyDLL._handle

  Системний дескриптор, який використовується для доступу до бібліотеки.

PyDLL._name

  Ім’я бібліотеки, передане в конструктор.

Shared libraries can also be loaded by using one of the prefabricated objects, which are instances of the `LibraryLoader` class, either by calling the `LoadLibrary()` method, or by retrieving the library as attribute of the loader instance.

class ctypes.LibraryLoader(dlltype)

  Клас, який завантажує спільні бібліотеки. dlltype має бути одним із типів `CDLL`, `PyDLL`, `WinDLL` або `OleDLL`.

  `__getattr__()` has special behavior: It allows loading a shared library by accessing it as attribute of a library loader instance. The result is cached, so repeated attribute accesses return the same library each time.

  LoadLibrary(name)

    Завантажте спільну бібліотеку в процес і поверніть її. Цей метод завжди повертає новий екземпляр бібліотеки.

Ці збірні бібліотечні завантажувачі доступні:

ctypes.cdll

  Створює екземпляри `CDLL`.

ctypes.windll

  Windows only: Creates `WinDLL` instances.

ctypes.oledll

  Windows only: Creates `OleDLL` instances.

ctypes.pydll

  Створює екземпляри `PyDLL`.

Для прямого доступу до API C Python доступний готовий до використання об’єкт спільної бібліотеки Python:

ctypes.pythonapi

  An instance of `PyDLL` that exposes Python C API functions as attributes. Note that all these functions are assumed to return C int, which is of course not always the truth, so you have to assign the correct `restype` attribute to use these functions.

Завантаження бібліотеки через будь-який із цих об’єктів викликає подію аудиту `ctypes.dlopen` з рядковим аргументом `name`, іменем, яке використовується для завантаження бібліотеки.

Доступ до функції у завантаженій бібліотеці викликає подію аудиту `ctypes.dlsym` з аргументами `library` (об’єкт бібліотеки) і `name` (ім’я символу у вигляді рядка або цілого числа).

У випадках, коли доступний лише дескриптор бібліотеки, а не об’єкт, доступ до функції викликає подію аудиту `ctypes.dlsym/handle` з аргументами `handle` (необроблений дескриптор бібліотеки) і `name`.

### Іноземні функції

As explained in the previous section, foreign functions can be accessed as attributes of loaded shared libraries. The function objects created in this way by default accept any number of arguments, accept any ctypes data instances as arguments, and return the default result type specified by the library loader. They are instances of a private class:

class ctypes._FuncPtr

  Базовий клас для зовнішніх функцій C, що викликаються.

  Примірники сторонніх функцій також є C-сумісними типами даних; вони представляють покажчики функцій C.

  Цю поведінку можна налаштувати шляхом призначення спеціальних атрибутів стороннього функціонального об’єкта.

  restype

    Assign a ctypes type to specify the result type of the foreign function. Use `None` for void, a function not returning anything.

    It is possible to assign a callable Python object that is not a ctypes type, in this case the function is assumed to return a C int, and the callable will be called with this integer, allowing further processing or error checking. Using this is deprecated, for more flexible post processing or error checking use a ctypes data type as `restype` and assign a callable to the `errcheck` attribute.

  argtypes

    Призначте кортеж типів ctypes, щоб указати типи аргументів, які приймає функція. Функції, які використовують угоду про виклики `stdcall`, можуть бути викликані лише з тією ж кількістю аргументів, що й довжина цього кортежу; функції, що використовують угоду про виклики C, також приймають додаткові, невизначені аргументи.

    When a foreign function is called, each actual argument is passed to the `from_param()` class method of the items in the `argtypes` tuple, this method allows adapting the actual argument to an object that the foreign function accepts. For example, a `c_char_p` item in the `argtypes` tuple will convert a string passed as argument into a bytes object using ctypes conversion rules.

    New: It is now possible to put items in argtypes which are not ctypes types, but each item must have a `from_param()` method which returns a value usable as argument (integer, string, ctypes instance). This allows defining adapters that can adapt custom objects as function parameters.

  errcheck

    Призначте цьому атрибуту функцію Python або інший виклик. Викликається з трьома або більше аргументами:

    callable(result, func, arguments)

      result is what the foreign function returns, as specified by the `restype` attribute.

      func — це сам зовнішній об’єкт функції, це дозволяє повторно використовувати той самий об’єкт, що викликається, для перевірки або постобробки результатів кількох функцій.

      Аргументи — це кортеж, що містить параметри, спочатку передані до виклику функції, що дозволяє спеціалізувати поведінку на використовуваних аргументах.

    Об’єкт, який повертає ця функція, буде повернено з виклику зовнішньої функції, але він також може перевірити значення результату та викликати виняток, якщо виклик зовнішньої функції не вдався.

exception ctypes.ArgumentError

  Цей виняток виникає, коли зовнішній виклик функції не може перетворити один із переданих аргументів.

On Windows, when a foreign function call raises a system exception (for example, due to an access violation), it will be captured and replaced with a suitable Python exception. Further, an auditing event `ctypes.seh_exception` with argument `code` will be raised, allowing an audit hook to replace the exception with its own.

Деякі способи виклику зовнішніх викликів функцій можуть викликати подію аудиту `ctypes.call_function` з аргументами `вказівник функції` і `аргументи`.

### Прототипи функцій

Сторонні функції також можуть бути створені шляхом інстанціювання прототипів функцій. Прототипи функцій подібні до прототипів функцій у C; вони описують функцію (тип повернення, типи аргументів, угоду про виклики) без визначення реалізації. Фабричні функції мають викликатися з потрібним типом результату та типами аргументів функції, і їх можна використовувати як фабрики декораторів, і як такі застосовувати до функцій за допомогою синтаксису `@wrapper`. Перегляньте Функції зворотного виклику для прикладів.

ctypes.CFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)

  Повернений прототип функції створює функції, які використовують стандартну угоду про виклик C. Функція звільнить GIL під час виклику. Якщо use_errno має значення true, приватна копія ctypes системної змінної `errno` обмінюється справжнім значенням `errno` до і після виклику; use_last_error робить те саме для коду помилки Windows.

ctypes.WINFUNCTYPE(restype, *argtypes, use_errno=False, use_last_error=False)

  Windows only: The returned function prototype creates functions that use the `stdcall` calling convention. The function will release the GIL during the call. use_errno and use_last_error have the same meaning as above.

ctypes.PYFUNCTYPE(restype, *argtypes)

  Повернений прототип функції створює функції, які використовують угоду про виклики Python. Функція не звільняє GIL під час виклику.

Прототипи функцій, створені цими фабричними функціями, можуть бути створені різними способами, залежно від типу та кількості параметрів у виклику:

prototype(address)

  Повертає зовнішню функцію за вказаною адресою, яка має бути цілим числом.

prototype(callable)

  Створіть функцію виклику C (функцію зворотного виклику) з Python callable.

prototype(func_spec[, paramflags])

  Повертає зовнішню функцію, експортовану спільною бібліотекою. func_spec має бути 2-кортежем `(name_or_ordinal, library)`. Перший елемент — це ім’я експортованої функції у вигляді рядка або порядковий номер експортованої функції у вигляді малого цілого числа. Другий елемент — екземпляр спільної бібліотеки.

prototype(vtbl_index, name[, paramflags[, iid]])

  Повертає зовнішню функцію, яка викликає метод COM. vtbl_index — це індекс у таблиці віртуальних функцій, мале невід’ємне ціле число. ім’я — це ім’я методу COM. iid — це додатковий покажчик на ідентифікатор інтерфейсу, який використовується в розширеному звіті про помилки.

  COM methods use a special calling convention: They require a pointer to the COM interface as first argument, in addition to those parameters that are specified in the `argtypes` tuple.

Необов’язковий параметр paramflags створює зовнішні обгортки функцій із набагато більшою функціональністю, ніж функції, описані вище.

paramflags must be a tuple of the same length as `argtypes`.

Кожен елемент у цьому кортежі містить додаткову інформацію про параметр, це має бути кортеж, що містить один, два або три елементи.

Перший елемент є цілим числом, що містить комбінацію прапорів напрямку для параметра:

> 1

>   Визначає вхідний параметр для функції.

> 2

>   Вихідний параметр. Стороння функція заповнює значення.

> 4

>   Вхідний параметр, який за умовчанням дорівнює нулю.

Другим необов’язковим елементом є назва параметра у вигляді рядка. Якщо це вказано, зовнішня функція може бути викликана з іменованими параметрами.

Додатковий третій елемент є значенням за замовчуванням для цього параметра.

The following example demonstrates how to wrap the Windows `MessageBoxW` function so that it supports default parameters and named arguments. The C declaration from the windows header file is this:

    WINUSERAPI int WINAPI
    MessageBoxW(
        HWND hWnd,
        LPCWSTR lpText,
        LPCWSTR lpCaption,
        UINT uType);

Ось обгортка за допомогою `ctypes`:

    >>> from ctypes import c_int, WINFUNCTYPE, windll
    >>> from ctypes.wintypes import HWND, LPCWSTR, UINT
    >>> prototype = WINFUNCTYPE(c_int, HWND, LPCWSTR, LPCWSTR, UINT)
    >>> paramflags = (1, "hwnd", 0), (1, "text", "Hi"), (1, "caption", "Hello from ctypes"), (1, "flags", 0)
    >>> MessageBox = prototype(("MessageBoxW", windll.user32), paramflags)

Сторонню функцію `MessageBox` тепер можна викликати такими способами:

    >>> MessageBox()
    >>> MessageBox(text="Spam, spam, spam")
    >>> MessageBox(flags=2, text="foo bar")

Другий приклад демонструє вихідні параметри. Функція `GetWindowRect` win32 отримує розміри вказаного вікна шляхом копіювання їх у структуру `RECT`, яку має надати абонент. Ось оголошення C:

    WINUSERAPI BOOL WINAPI
    GetWindowRect(
         HWND hWnd,
         LPRECT lpRect);

Ось обгортка за допомогою `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)
    >>>

Функції з вихідними параметрами автоматично повертатимуть значення вихідного параметра, якщо є одне, або кортеж, що містить значення вихідних параметрів, якщо їх декілька, тому функція GetWindowRect тепер повертає екземпляр RECT під час виклику.

Output parameters can be combined with the `errcheck` protocol to do further output processing and error checking. The win32 `GetWindowRect` api function returns a `BOOL` to signal success or failure, so this function could do the error checking, and raises an exception when the api call failed:

    >>> def errcheck(result, func, args):
    ...     if not result:
    ...         raise WinError()
    ...     return args
    ...
    >>> GetWindowRect.errcheck = errcheck
    >>>

If the `errcheck` function returns the argument tuple it receives unchanged, `ctypes` continues the normal processing it does on the output parameters. If you want to return a tuple of window coordinates instead of a `RECT` instance, you can retrieve the fields in the function and return them instead, the normal processing will no longer take place:

    >>> def errcheck(result, func, args):
    ...     if not result:
    ...         raise WinError()
    ...     rc = args[1]
    ...     return rc.left, rc.top, rc.bottom, rc.right
    ...
    >>> GetWindowRect.errcheck = errcheck
    >>>

### Функції корисності

ctypes.addressof(obj)

  Повертає адресу буфера пам’яті як ціле число. obj має бути екземпляром типу ctypes.

  Викликає подію аудиту `ctypes.addressof` з аргументом `obj`.

ctypes.alignment(obj_or_type)

  Повертає вимоги до вирівнювання типу ctypes. obj_or_type має бути типом або екземпляром ctypes.

ctypes.byref(obj[, offset])

  Повертає легкий вказівник на obj, який має бути екземпляром типу ctypes. offset за замовчуванням дорівнює нулю і має бути цілим числом, яке буде додано до значення внутрішнього покажчика.

  `byref(obj, offset)` відповідає цьому коду C:

      (((char *)&obj) + offset)

  Повернений об’єкт можна використовувати лише як параметр виклику зовнішньої функції. Він поводиться подібно до `pointer(obj)`, але будівництво відбувається набагато швидше.

ctypes.cast(obj, type)

  Ця функція схожа на оператор приведення в C. Вона повертає новий екземпляр type, який вказує на той самий блок пам’яті, що й obj. type має бути типом покажчика, а obj має бути об’єктом, який можна інтерпретувати як покажчик.

ctypes.create_string_buffer(init_or_size, size=None)

  Ця функція створює змінний символьний буфер. Повернений об’єкт є масивом ctypes `c_char`.

  init_or_size має бути цілим числом, яке визначає розмір масиву, або об’єктом bytes, який використовуватиметься для ініціалізації елементів масиву.

  Якщо в якості першого аргументу вказано об’єкт bytes, буфер стає на один елемент більшим, ніж його довжина, так що останній елемент у масиві є завершальним символом NUL. Ціле число може бути передане як другий аргумент, що дозволяє вказати розмір масиву, якщо довжина байтів не повинна використовуватися.

  Викликає подію аудиту `ctypes.create_string_buffer` з аргументами `init`, `size`.

ctypes.create_unicode_buffer(init_or_size, size=None)

  Ця функція створює змінний буфер символів Unicode. Повернений об’єкт є масивом ctypes `c_wchar`.

  init_or_size має бути цілим числом, що вказує розмір масиву, або рядком, який використовуватиметься для ініціалізації елементів масиву.

  Якщо рядок вказано як перший аргумент, буфер робиться на один елемент більшим, ніж довжина рядка, так що останній елемент у масиві є завершальним символом NUL. Ціле число може бути передане як другий аргумент, що дозволяє вказати розмір масиву, якщо довжина рядка не повинна використовуватися.

  Викликає подію аудиту `ctypes.create_unicode_buffer` з аргументами `init`, `size`.

ctypes.DllCanUnloadNow()

  Windows only: This function is a hook which allows implementing in-process COM servers with ctypes. It is called from the DllCanUnloadNow function that the _ctypes extension dll exports.

ctypes.DllGetClassObject()

  Windows only: This function is a hook which allows implementing in-process COM servers with ctypes. It is called from the DllGetClassObject function that the `_ctypes` extension dll exports.

ctypes.util.find_library(name)

  Спробуйте знайти бібліотеку та повернути шлях. ім’я — це ім’я бібліотеки без будь-яких префіксів, як-от `lib`, суфіксів, як-от `.so`, `.dylib` або номера версії (це форма, яка використовується для параметра компонувальника posix `-l`). Якщо бібліотеки не знайдено, повертає `None`.

  Точна функція залежить від системи.

ctypes.util.find_msvcrt()

  Windows only: return the filename of the VC runtime library used by Python, and by the extension modules. If the name of the library cannot be determined, `None` is returned.

  Якщо вам потрібно звільнити пам’ять, наприклад, виділену модулем розширення за допомогою виклику `free(void *)`, важливо, щоб ви використовували функцію в тій самій бібліотеці, яка виділила пам’ять.

ctypes.FormatError([code])

  Windows only: Returns a textual description of the error code code. If no error code is specified, the last error code is used by calling the Windows api function GetLastError.

ctypes.GetLastError()

  Windows only: Returns the last error code set by Windows in the calling thread. This function calls the Windows `GetLastError()` function directly, it does not return the ctypes-private copy of the error code.

ctypes.get_errno()

  Повертає поточне значення ctypes-private копії системної змінної `errno` у потоці виклику.

  Викликає подію аудиту `ctypes.get_errno` без аргументів.

ctypes.get_last_error()

  Windows only: returns the current value of the ctypes-private copy of the system `LastError` variable in the calling thread.

  Викликає подію аудиту `ctypes.get_last_error` без аргументів.

ctypes.memmove(dst, src, count)

  Те саме, що стандартна функція бібліотеки C memmove: копіює count байти з src до dst. dst і src мають бути цілими числами або екземплярами ctypes, які можна перетворити на покажчики.

ctypes.memset(dst, c, count)

  Те саме, що стандартна функція бібліотеки memset C: заповнює блок пам’яті за адресою dst count байтами зі значенням c. dst має бути цілим числом, що визначає адресу, або екземпляр ctypes.

ctypes.POINTER(type, /)

  Create and return a new ctypes pointer type. Pointer types are cached and reused internally, so calling this function repeatedly is cheap. type must be a ctypes type.

ctypes.pointer(obj, /)

  Create a new pointer instance, pointing to obj. The returned object is of the type `POINTER(type(obj))`.

  Примітка. Якщо ви просто хочете передати вказівник на об’єкт у зовнішній виклик функції, вам слід використовувати `byref(obj)`, що набагато швидше.

ctypes.resize(obj, size)

  Ця функція змінює розмір буфера внутрішньої пам’яті obj, який має бути екземпляром типу ctypes. Неможливо зробити буфер меншим, ніж власний розмір типу об’єктів, як задано `sizeof(type(obj))`, але можна збільшити буфер.

ctypes.set_errno(value)

  Установіть поточне значення ctypes-private копії системної змінної `errno` у викликаючому потоці на value і поверніть попереднє значення.

  Викликає подію аудиту `ctypes.set_errno` з аргументом `errno`.

ctypes.set_last_error(value)

  Windows only: set the current value of the ctypes-private copy of the system `LastError` variable in the calling thread to value and return the previous value.

  Викликає подію аудиту `ctypes.set_last_error` з аргументом `помилка`.

ctypes.sizeof(obj_or_type)

  Повертає розмір у байтах типу ctypes або буфера пам’яті примірника. Діє так само, як і оператор C `sizeof`.

ctypes.string_at(address, size=-1)

  This function returns the C string starting at memory address address as a bytes object. If size is specified, it is used as size, otherwise the string is assumed to be zero-terminated.

  Raises an auditing event `ctypes.string_at` with arguments `address`, `size`.

ctypes.WinError(code=None, descr=None)

  Windows only: this function is probably the worst-named thing in ctypes. It creates an instance of `OSError`. If code is not specified, `GetLastError` is called to determine the error code. If descr is not specified, `FormatError()` is called to get a textual description of the error.

  Змінено в версії 3.3: An instance of `WindowsError` used to be created, which is now an alias of `OSError`.

ctypes.wstring_at(address, size=-1)

  This function returns the wide character string starting at memory address address as a string. If size is specified, it is used as the number of characters of the string, otherwise the string is assumed to be zero-terminated.

  Raises an auditing event `ctypes.wstring_at` with arguments `address`, `size`.

### Типи даних

class ctypes._CData

  Цей непублічний клас є загальним базовим класом для всіх типів даних ctypes. Серед іншого, усі екземпляри типу ctypes містять блок пам’яті, який містить C-сумісні дані; адреса блоку пам’яті повертається допоміжною функцією `addressof()`. Інша змінна екземпляра представлена як `_objects`; це містить інші об’єкти Python, які потрібно підтримувати в активному стані, якщо блок пам’яті містить покажчики.

  Загальні методи типів даних ctypes, це всі методи класу (точніше, це методи metaclass):

  from_buffer(source[, offset])

    Цей метод повертає екземпляр ctypes, який спільно використовує буфер об’єкта source. Об’єкт джерело має підтримувати інтерфейс буфера з можливістю запису. Необов’язковий параметр offset визначає зсув у вихідному буфері в байтах; за замовчуванням дорівнює нулю. Якщо вихідний буфер недостатньо великий, виникає `ValueError`.

    Викликає подію аудиту `ctypes.cdata/buffer` з аргументами `pointer`, `size`, `offset`.

  from_buffer_copy(source[, offset])

    Цей метод створює екземпляр ctypes, копіюючи буфер із буфера джерельного об’єкта, який має бути читабельним. Необов’язковий параметр offset визначає зсув у вихідному буфері в байтах; за замовчуванням дорівнює нулю. Якщо вихідний буфер недостатньо великий, виникає `ValueError`.

    Викликає подію аудиту `ctypes.cdata/buffer` з аргументами `pointer`, `size`, `offset`.

  from_address(address)

    Цей метод повертає екземпляр типу ctypes, використовуючи пам’ять, визначену адресою, яка має бути цілим числом.

    Цей метод та інші, які опосередковано викликають цей метод, викликають подію аудиту `ctypes.cdata` з аргументом `адреса`.

  from_param(obj)

    This method adapts obj to a ctypes type. It is called with the actual object used in a foreign function call when the type is present in the foreign function’s `argtypes` tuple; it must return an object that can be used as a function call parameter.

    Усі типи даних ctypes мають стандартну реалізацію цього методу класу, який зазвичай повертає obj, якщо це екземпляр типу. Деякі типи також приймають інші об’єкти.

  in_dll(library, name)

    Цей метод повертає екземпляр типу ctypes, експортований спільною бібліотекою. name — це ім’я символу, який експортує дані, library — це завантажена спільна бібліотека.

  Загальні змінні екземплярів типів даних ctypes:

  _b_base_

    Іноді екземпляри даних ctypes не володіють блоком пам’яті, який вони містять, натомість вони спільно використовують частину блоку пам’яті базового об’єкта. Член `_b_base_` лише для читання є кореневим об’єктом ctypes, якому належить блок пам’яті.

  _b_needsfree_

    Ця змінна лише для читання є істиною, коли екземпляр даних ctypes сам виділив блок пам’яті, інакше – false.

  _objects

    Цей член або `None`, або словник, що містить об’єкти Python, які потрібно підтримувати в активному стані, щоб вміст блоку пам’яті залишався дійсним. Цей об’єкт доступний лише для налагодження; ніколи не змінюйте вміст цього словника.

### Основні типи даних

class ctypes._SimpleCData

  Цей закритий клас є базовим класом усіх основних типів даних ctypes. Він згадується тут, оскільки він містить загальні атрибути основних типів даних ctypes. `_SimpleCData` є підкласом `_CData`, тому він успадковує їхні методи та атрибути. Типи даних ctypes, які не є та не містять покажчиків, тепер можна маринувати.

  Екземпляри мають один атрибут:

  value

    Цей атрибут містить фактичне значення екземпляра. Для цілочисельних типів і типів покажчиків це ціле число, для типів символів – об’єкт або рядок із одним символом у байтах, для типів покажчиків на символи – це об’єкт або рядок Python bytes.

    Коли атрибут `value` отримується з екземпляра ctypes, зазвичай щоразу повертається новий об’єкт. `ctypes` не реалізує повернення оригінального об’єкта, завжди створюється новий об’єкт. Те саме стосується всіх інших екземплярів об’єктів ctypes.

Fundamental data types, when returned as foreign function call results, or, for example, by retrieving structure field members or array items, are transparently converted to native Python types. In other words, if a foreign function has a `restype` of `c_char_p`, you will always receive a Python bytes object, not a `c_char_p` instance.

Subclasses of fundamental data types do not inherit this behavior. So, if a foreign functions `restype` is a subclass of `c_void_p`, you will receive an instance of this subclass from the function call. Of course, you can get the value of the pointer by accessing the `value` attribute.

Ось основні типи даних ctypes:

class ctypes.c_byte

  Represents the C signed char datatype, and interprets the value as small integer. The constructor accepts an optional integer initializer; no overflow checking is done.

class ctypes.c_char

  Represents the C char datatype, and interprets the value as a single character. The constructor accepts an optional string initializer, the length of the string must be exactly one character.

class ctypes.c_char_p

  Represents the C char* datatype when it points to a zero-terminated string. For a general character pointer that may also point to binary data, `POINTER(c_char)` must be used. The constructor accepts an integer address, or a bytes object.

class ctypes.c_double

  Represents the C double datatype. The constructor accepts an optional float initializer.

class ctypes.c_longdouble

  Represents the C long double datatype. The constructor accepts an optional float initializer. On platforms where `sizeof(long double) == sizeof(double)` it is an alias to `c_double`.

class ctypes.c_float

  Represents the C float datatype. The constructor accepts an optional float initializer.

class ctypes.c_int

  Represents the C signed int datatype. The constructor accepts an optional integer initializer; no overflow checking is done. On platforms where `sizeof(int) == sizeof(long)` it is an alias to `c_long`.

class ctypes.c_int8

  Represents the C 8-bit signed int datatype. Usually an alias for `c_byte`.

class ctypes.c_int16

  Represents the C 16-bit signed int datatype. Usually an alias for `c_short`.

class ctypes.c_int32

  Represents the C 32-bit signed int datatype. Usually an alias for `c_int`.

class ctypes.c_int64

  Represents the C 64-bit signed int datatype. Usually an alias for `c_longlong`.

class ctypes.c_long

  Represents the C signed long datatype. The constructor accepts an optional integer initializer; no overflow checking is done.

class ctypes.c_longlong

  Represents the C signed long long datatype. The constructor accepts an optional integer initializer; no overflow checking is done.

class ctypes.c_short

  Represents the C signed short datatype. The constructor accepts an optional integer initializer; no overflow checking is done.

class ctypes.c_size_t

  Представляє тип даних C `size_t`.

class ctypes.c_ssize_t

  Представляє тип даних C `ssize_t`.

  Нове в версії 3.2.

class ctypes.c_ubyte

  Represents the C unsigned char datatype, it interprets the value as small integer. The constructor accepts an optional integer initializer; no overflow checking is done.

class ctypes.c_uint

  Represents the C unsigned int datatype. The constructor accepts an optional integer initializer; no overflow checking is done. On platforms where `sizeof(int) == sizeof(long)` it is an alias for `c_ulong`.

class ctypes.c_uint8

  Represents the C 8-bit unsigned int datatype. Usually an alias for `c_ubyte`.

class ctypes.c_uint16

  Represents the C 16-bit unsigned int datatype. Usually an alias for `c_ushort`.

class ctypes.c_uint32

  Represents the C 32-bit unsigned int datatype. Usually an alias for `c_uint`.

class ctypes.c_uint64

  Represents the C 64-bit unsigned int datatype. Usually an alias for `c_ulonglong`.

class ctypes.c_ulong

  Represents the C unsigned long datatype. The constructor accepts an optional integer initializer; no overflow checking is done.

class ctypes.c_ulonglong

  Represents the C unsigned long long datatype. The constructor accepts an optional integer initializer; no overflow checking is done.

class ctypes.c_ushort

  Represents the C unsigned short datatype. The constructor accepts an optional integer initializer; no overflow checking is done.

class ctypes.c_void_p

  Represents the C void* type. The value is represented as integer. The constructor accepts an optional integer initializer.

class ctypes.c_wchar

  Представляє тип даних C `wchar_t` і інтерпретує значення як односимвольний рядок Unicode. Конструктор приймає необов’язковий ініціалізатор рядка, довжина рядка має бути рівно одному символу.

class ctypes.c_wchar_p

  Represents the C wchar_t* datatype, which must be a pointer to a zero-terminated wide character string. The constructor accepts an integer address, or a string.

class ctypes.c_bool

  Represent the C bool datatype (more accurately, _Bool from C99). Its value can be `True` or `False`, and the constructor accepts any object that has a truth value.

class ctypes.HRESULT

  Windows only: Represents a `HRESULT` value, which contains success or error information for a function or method call.

class ctypes.py_object

  Represents the C PyObject* datatype. Calling this without an argument creates a `NULL` PyObject* pointer.

The `ctypes.wintypes` module provides quite some other Windows specific data types, for example `HWND`, `WPARAM`, or `DWORD`. Some useful structures like `MSG` or `RECT` are also defined.

### Структуровані типи даних

class ctypes.Union(*args, **kw)

  Абстрактний базовий клас для об’єднань у рідному порядку байтів.

class ctypes.BigEndianUnion(*args, **kw)

  Abstract base class for unions in big endian byte order.

  Нове в версії 3.11.

class ctypes.LittleEndianUnion(*args, **kw)

  Abstract base class for unions in little endian byte order.

  Нове в версії 3.11.

class ctypes.BigEndianStructure(*args, **kw)

  Абстрактний базовий клас для структур у великому порядку байтів.

class ctypes.LittleEndianStructure(*args, **kw)

  Абстрактний базовий клас для структур у порядку байтів little endian.

Structures and unions with non-native byte order cannot contain pointer type fields, or any other data types containing pointer type fields.

class ctypes.Structure(*args, **kw)

  Абстрактний базовий клас для структур у власному порядку байтів.

  Конкретні типи структури та об’єднання мають бути створені шляхом створення підкласу одного з цих типів і принаймні визначення змінної класу `_fields_`. `ctypes` створить descriptors, які дозволяють читати та записувати поля за допомогою прямого доступу до атрибутів. Це

  _fields_

    Послідовність, що визначає поля структури. Елементи мають бути 2-кортежними або 3-кортежними. Перший пункт – ім’я поля, другий – тип поля; це може бути будь-який тип даних ctypes.

    Для полів цілого типу, таких як `c_int`, можна вказати третій необов’язковий елемент. Це має бути маленьке позитивне ціле число, що визначає розрядність поля.

    Імена полів мають бути унікальними в межах однієї структури чи об’єднання. Це не позначено, лише одне поле доступне, якщо імена повторюються.

    Можна визначити змінну класу `_fields_` після оператора класу, який визначає підклас Structure, це дозволяє створювати типи даних, які прямо чи опосередковано посилаються на себе:

        class List(Structure):
            pass
        List._fields_ = [("pnext", POINTER(List)),
                         ...
                        ]

    Однак змінну класу `_fields_` потрібно визначити перед першим використанням типу (створюється екземпляр, для нього викликається `sizeof()` і так далі). Пізніше призначення змінній класу `_fields_` призведе до помилки AttributeError.

    Можна визначити під-підкласи структурних типів, вони успадковують поля базового класу плюс `_fields_`, визначені в під-підкласі, якщо такі є.

  _pack_

    An optional small integer that allows overriding the alignment of structure fields in the instance. `_pack_` must already be defined when `_fields_` is assigned, otherwise it will have no effect.

  _anonymous_

    Необов’язкова послідовність, яка містить імена безіменних (анонімних) полів. `_anonymous_` має бути вже визначено під час призначення `_fields_`, інакше це не матиме ефекту.

    Поля, перелічені в цій змінній, мають бути структурними або об’єднаними. `ctypes` створить дескриптори у структурному типі, що дозволяє отримати доступ до вкладених полів безпосередньо, без необхідності створювати структуру чи поле об’єднання.

    Ось приклад типу (Windows):

        class _U(Union):
            _fields_ = [("lptdesc", POINTER(TYPEDESC)),
                        ("lpadesc", POINTER(ARRAYDESC)),
                        ("hreftype", HREFTYPE)]

        class TYPEDESC(Structure):
            _anonymous_ = ("u",)
            _fields_ = [("u", _U),
                        ("vt", VARTYPE)]

    Структура `TYPEDESC` описує тип даних COM, поле `vt` визначає, яке з полів об’єднання є дійсним. Оскільки поле `u` визначено як анонімне поле, тепер можна отримати доступ до членів безпосередньо з примірника TYPEDESC. `td.lptdesc` і `td.u.lptdesc` еквівалентні, але перший швидший, оскільки йому не потрібно створювати тимчасовий екземпляр об’єднання:

        td = TYPEDESC()
        td.vt = VT_PTR
        td.lptdesc = POINTER(some_type)
        td.u.lptdesc = POINTER(some_type)

  Є можливість визначення суб-підкласів структур, вони успадковують поля базового класу. Якщо визначення підкласу має окрему змінну `_fields_`, поля, зазначені в ній, додаються до полів базового класу.

  Конструктори структури та об’єднання приймають як позиційні, так і ключові аргументи. Позиційні аргументи використовуються для ініціалізації полів-членів у такому самому порядку, як вони з’являються в `_fields_`. Аргументи ключових слів у конструкторі інтерпретуються як призначення атрибутів, тому вони ініціалізують `_fields_` з тим же іменем або створять нові атрибути для імен, яких немає в `_fields_`.

### Масиви та покажчики

class ctypes.Array(*args)

  Абстрактний базовий клас для масивів.

  Рекомендований спосіб створення конкретних типів масивів — це множення будь-якого типу даних `ctypes` на невід’ємне ціле число. Крім того, ви можете створити підклас цього типу та визначити змінні класу `_length_` і `_type_`. Елементи масиву можна читати та записувати за допомогою стандартного підрядкового і зрізного доступу; для зчитування фрагментів результуючий об’єкт не сам є `Array`.

  _length_

    Додатне ціле число, що визначає кількість елементів у масиві. Індекси поза діапазоном призводять до `IndexError`. Буде повернено `len()`.

  _type_

    Визначає тип кожного елемента в масиві.

  Конструктори підкласу масиву приймають позиційні аргументи, які використовуються для ініціалізації елементів у порядку.

class ctypes._Pointer

  Приватний, абстрактний базовий клас для вказівників.

  Конкретні типи вказівників створюються шляхом виклику `POINTER()` із типом, на який буде вказувати; це робиться автоматично за допомогою `pointer()`.

  Якщо вказівник вказує на масив, його елементи можна читати та записувати за допомогою стандартного підрядкового і зрізного доступу. Об’єкти-вказівники не мають розміру, тому `len()` викличе `TypeError`. Негативні індекси читатимуться з пам’яті перед вказівником (як у C), а індекси поза межами діапазону, ймовірно, впадуть із порушенням доступу (якщо вам пощастить).

  _type_

    Визначає тип, на який вказується.

  contents

    Повертає об’єкт, на який вказує вказівник. Призначення цьому атрибуту змінює вказівник на призначений об’єкт.