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

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

Содержание:

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

Фабричные функции должны вызываться с желаемым типом результата и типами аргументов функции и могут использоваться как фабричные декораторы и как таковые, применяться к функциям с помощью синтаксиса @wrapper. Смотрите примеры функций обратного вызова.

Функции создания прототипов модуля ctypes.

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

Фабричная функция ctypes.CFUNCTYPE() возвращает прототип prototype созданной C-функции, который использует стандартное соглашение о вызове языка Си. Функция отключает GIL во время вызова.

Если аргумент use_errno=True, то частная копия ctypes системной переменной errno обменивается реальным значением errno до и после вызова.

Аргумент use_last_error делает то же самое для кода ошибки Windows.

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

Фабричная функция ctypes.WINFUNCTYPE() используется только в Windows: возвращает прототип prototype созданной C-функции, который использует соглашение о вызовах stdcall, за исключением Windows CE, где WINFUNCTYPE() совпадает с ctypes.CFUNCTYPE().

Функция ctypes.WINFUNCTYPE() освободит GIL во время вызова. Аргументы use_errno и use_last_error имеют то же значение, что класс ctypes.CFUNCTYPE().

ctypes.PYFUNCTYPE(restype, *argtypes):

Фабричная функция ctypes.PYFUNCTYPE() возвращает прототип prototype созданной C-функции, который использует стандартное соглашение о вызовах Python. Функция ctypes.PYFUNCTYPE() не освобождает GIL во время вызова.

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


Способы создания прототипов внешний C-функций.

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

prototype(address):

Возвращает внешнюю функцию по указанному адресу address, который должен быть целым числом.

prototype(callable):

Создает вызываемую C-функцию (функцию обратного вызова) из вызываемого объекта Python.

prototype(func_spec[, paramflags]):

Возвращает внешнюю C-функцию, экспортированную из общей библиотеки. Аргумент func_spec должен быть кортежем из 2-х элементов (name_or_ordinal, library).

  • элемент name_or_ordinal - это имя экспортируемой функции в виде строки или порядковый номер экспортируемой функции в виде небольшого целого числа.
  • элемент library - это экземпляр загружаемой библиотеки C.

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

Возвращает внешнюю C-функцию, которая вызовет метод COM.

  • Аргумент vtbl_index - это индекс в таблице виртуальных функций, небольшое неотрицательное целое число.
  • Аргумент name - это имя COM-метода.
  • Аргумент iid - это необязательный указатель на идентификатор интерфейса, который используется в расширенных сообщениях об ошибках.

В COM методах используется специальное соглашение о вызовах: им требуется указатель на интерфейс COM в качестве первого аргумента в дополнение к тем параметрам, которые указаны в кортеже argtypes.

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

Аргумент paramflags должен быть кортежем той же длины, что и argtypes.

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

  1. Первый элемент - это целое число, содержащее комбинацию флагов направления для параметра:
    • Значение 1 - задает входной параметр функции.
    • Значение 2 - выходной параметр. Внешняя функция заполняет значение.
    • Значение 4 - входной параметр, значение которого по умолчанию равно нулю.
  2. Необязательный второй элемент - это имя параметра в виде строки. Если он указан, то внешняя функция может быть вызвана с именованными параметрами.
  3. Необязательный третий элемент является значением по умолчанию для этого параметра.

Примеры создания прототипов загружаемых C-функций.

В этом примере показано, как обернуть функцию Windows MessageBoxW(), чтобы она поддерживала параметры по умолчанию и именованные аргументы. Объявление C из файла заголовка Windows выглядит следующим образом:

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

Оборачиваем функцию Windows MessageBoxW():

>>> 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")

Второй пример демонстрирует выходные параметры. Функция Win32 GetWindowRect() извлекает размеры указанного окна, копируя их в структуру RECT, которую должен предоставить вызывающий. Вот объявление C:

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

Оборачиваем функцию Win32 GetWindowRect():

>>> 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.

Параметры вывода могут быть объединены с протоколом errcheck для дальнейшей обработки и проверки ошибок. Функция Win32 api GetWindowRect возвращает BOOL, чтобы сигнализировать об успехе или неудаче, поэтому эта функция может выполнять проверку ошибок и вызывает исключение, когда вызов api не удался:

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

Если функция errcheck возвращает кортеж аргументов, который она получает без изменений, то ctypes продолжает обычную обработку выходных параметров. Если необходимо вернуть кортеж координат окна вместо экземпляра RECT, то можно получить поля в функции и вернуть их результат, в этом случае нормальная обработка больше выполняться не будет:

>>> 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