Сообщить об ошибке.

Поведение внешних C-функций модуля ctypes в Python

Аргументы и возвращаемые значения функций, загруженных C библиотек

К сторонним функциям, можно обращаться как к атрибутам загруженных C библиотек. Объекты C-функций, созданные таким образом, по умолчанию принимают любое количество аргументов, принимают любые экземпляры данных модуля ctypes в качестве аргументов и возвращают тип результата по умолчанию, указанный загрузчиком библиотеки.

Все они являются экземплярами частного класса ctypes._FuncPtr.

ctypes._FuncPtr:

Класс ctypes._FuncPtr это базовый класс для всех вызываемых C-функций, загруженных из внешних библиотек языка C.

Экземпляры сторонних C-функций также являются типами данных, совместимыми с языком C. Они представляют собой указатели на C-функции.

Их поведение можно настроить, назначив специальные атрибуты объекта внешней C-функции.

_FuncPtr.restype:

Атрибут _FuncPtr.restype назначает тип ctypes, для указания возвращаемого типа внешней C-функции. Используйте None для void-функции, которые ничего не возвращают.

Атрибуту можно назначить вызываемый объект Python, который не является типом ctypes, в этом случае предполагается, что функция возвращает тип C int, а вызываемый объект будет вызываться с целым числом, позволяя дальнейшую обработку или проверку ошибок.

Использование такого поведения не рекомендуется, Для более гибкой постобработки или проверки ошибок используйте тип данных ctypes в качестве _FuncPtr.restype и определите вызываемый атрибут _FuncPtr.errcheck.

>>> from ctypes import *
>>> strchr = libc.strchr
>>> strchr(b"abcdef", ord("d"))  
# 8059983

# c_char_p - это указатель на строку
>>> strchr.restype = c_char_p 
>>> strchr(b"abcdef", ord("d"))
# b'def'
>>> print(strchr(b"abcdef", ord("x")))
# None

_FuncPtr.argtypes:

Атрибут _FuncPtr.argtypes назначает кортеж типов ctypes, для указания типов аргументов, которые принимает C-функция.

  • C-функции, использующие соглашение о вызовах stdcall, могут вызываться только с тем же количеством аргументов, что и длина этого кортежа.
  • C-функции, использующие соглашение о вызовах C, также принимают дополнительные неуказанные аргументы.

Когда вызывается внешняя C-функция, каждый фактический аргумент передается методу класса .from_param() элементов в кортеже _FuncPtr.argtypes. Этот метод позволяет адаптировать фактический аргумент к объекту, который принимает внешняя C-функция. Например, элемент ctypes.c_char_p в кортеже _FuncPtr.argtypes преобразует строку, переданную в качестве аргумента, в объект байтов, используя правила преобразования ctypes.

>>> from ctypes import *
>>> printf = libc.printf
>>> 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

Новое: теперь можно размещать элементы в _FuncPtr.argtypes, не являются типами ctypes. При этом каждый элемент должен иметь метод .from_param(), который возвращает значение, используемое в качестве аргумента (целое число, строка, экземпляр ctypes). Это позволяет определять адаптеры, которые адаптируют пользовательские объекты как параметры внешней C-функции.

_FuncPtr.errcheck:

Атрибут _FuncPtr.errcheck предназначен для назначения ему функции Python или другого вызываемого объекта. Эта функция будет вызываться с тремя или более аргументами:

  • callable(result, func, arguments):

    • Аргумент result - это то, что возвращает внешняя C-функция, как указано в атрибуте _FuncPtr.restype.
    • Аргумент func - это сам объект внешней C-функции, он позволяет повторно использовать один и тот же вызываемый объект для проверки или последующей обработки результатов нескольких функций.
    • Аргумент arguments - это кортеж, содержащий параметры, первоначально переданные вызову C-функции, что позволяет специализировать поведение на используемых аргументах.
>>> def errcheck(result, func, args):
...     if not result:
...         raise WinError()
...     return args
...
>>> GetWindowRect.errcheck = errcheck

Объект, который возвращает назначенная функции Python, будет возвращен из вызова C-функции. Также, эта функция Python может проверить значение результата и вызвать исключение, если вызов внешней C-функции завершился неудачно.


Исключение при преобразовании переданных аргументов.

ctypes.ArgumentError:

Исключение ctypes.ArgumentError возникает, когда вызов внешней функции не может преобразовать один из переданных аргументов.

В Windows, когда вызов внешней функции вызывает системное исключение (например, из-за нарушения прав доступа), то оно будет захвачено и заменено подходящим исключением Python. Далее будет вызвано событие аудита ctypes.seh_exception с аргумента code, позволяющее перехватчику заменить исключение своим собственным.

Некоторые способы вызова внешних функций могут вызвать событие аудита ctypes.call_function с аргументами function pointer и arguments.