Я пытаюсь использовать библиотеку Python ctypes для доступа к некоторым методам в библиотеке сканирования SANE . Это мой первый опыт работы с ctypes, и я впервые столкнулся с типами данных C более чем за год, поэтому здесь есть неплохая кривая обучения, но я думаю, что даже без этого это конкретное объявление будет проблематичным:
extern SANE_Status sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only);
Прежде всего, я успешно справился с SANE_Status
(перечисление) и SANE_Bool
(определение типа до c_int
). Это было просто. Этот первый параметр, с другой стороны, вызывает у меня всякое горе. Я не знаком с нотацией "***
" с самого начала, и мои трассирующие пули до сих пор не дали ничего, кроме данных о мусоре. Как мне отформатировать входные данные для этой функции, чтобы я мог прочитать список своих структурных объектов Python? Для справки: структура C, на которую ссылаются:
typedef struct
{
SANE_String_Const name; /* unique device name */
SANE_String_Const vendor; /* device vendor string */
SANE_String_Const model; /* device model name */
SANE_String_Const type; /* device type (e.g., "flatbed scanner") */
}
SANE_Device;
Где SANE_String_Const
определяется как c_char_p
.
Моя версия этого объекта на Python / ctypes:
class SANE_Device(Structure):
_fields_ = [
("name", c_char_p),
("vendor", c_char_p),
("model", c_char_p),
("type", c_char_p)]
Предложения о том, что я должен передать, чтобы я мог получить ожидаемое поведение (список структур-объектов) из этого? Все ответы приветствуются.
Обновление 1:
Используя следующее, я смог получить правильную структуру Python SANE_Device:
devices = pointer(pointer(pointer(SANE_Device())))
status = libsane.sane_get_devices(devices, c_int(0))
print status, devices, devices.contents.contents.contents.name
Тем не менее, 1) гадость и 2) кажется, что это будет работать только при наличии единственного результата. Я не могу len () на devices.contents.contents
или devices.contents.contents.contents
. Как мне определить количество результатов? Документы SANE указывают, что «Если функция выполняется успешно, она сохраняет указатель на массив указателей с окончанием NULL на структуры SANE_Device в * device_list». Предложения?
Обновление 2:
Мне удалось передать массив из десяти элементов, а затем получить доступ к первому элементу, используя:
devices = pointer(pointer(pointer((SANE_Device * 10)())))
status = libsane.sane_get_devices(devices, c_int(0))
print status, devices, devices.contents.contents.contents[0].name
Однако десять, очевидно, произвольное число, и у меня нет способа определить фактическое количество результатов. Попытка доступа к devices.contents.contents.contents[1].name
, когда подключено только одно устройство, вызывает ошибку сегментации. Должен быть правильный способ работы с конструкциями переменной длины, подобными этим, в ctypes.