Проблема с запуском функций из DLL-файла с использованием ctypes в объектно-ориентированном Python
-
19-09-2019 - |
Вопрос
Я очень надеюсь, что это не будет вопрос с уже полученным ответом или глупый.Недавно я программировал с помощью нескольких инструментов.Пытаюсь установить связь между ними, чтобы создать программу тестирования.Однако я столкнулся с некоторыми проблемами с одним конкретным инструментом, когда я пытаюсь вызвать функции, которые я "замаскировал" из DLL-файла instruments.Когда я использую интерактивную оболочку python, она работает отлично (хотя в ней много словосочетаний).Но когда я реализую функции объектно-ориентированным образом, программа завершается сбоем, ну, на самом деле это не сбой, это просто ничего не делает.Это первый метод, который вызывается:(импортированы ctypes и ctypes.util)
def init_hardware(self):
""" Inits the instrument """
self.write_log("Initialising the automatic tuner")
version_string = create_string_buffer(80)
self.error_string = create_string_buffer(80)
self.name = "Maury MT982EU"
self.write_log("Tuner DLL path: %s", find_library('MLibTuners'))
self.maury = WinDLL('MlibTuners')
self.maury.get_tuner_driver_version(version_string)
if (version_string.value == ""):
self.write_log("IMPORTANT: Error obtaining the driver version")
else:
self.write_log("Version number of the DLL: %s" % version_string.value)
self.ThreeTypeLong = c_long * 3
Теперь это работает отлично, все идеально, и я получаю идеальные записи в журнале.Но когда я пытаюсь запустить метод дальше в программу, вызываемую:
def add_tuner_and_controller(self, name, serial_number, tuner_number=0):
""" Adds the tuner to the driver object, controller is inside the tuner """
self.write_log("Adding tuner %d and the built-in controller" % tuner_number)
TempType = self.ThreeTypeLong()
self.maury.add_controller(c_short(tuner_number), c_char_p(self.file_path), c_char_p(name), c_int(0), c_int(0),
c_long(0), c_short(serial_number), self.error_string)
self.maury.add_tuner(c_short(tuner_number), c_char_p(name), c_short(serial_number), c_short(0),
c_short(1), pointer(c_double()), TempType, pointer(c_double()), pointer(c_double()),
pointer(c_double()), self.error_string)
Программа внезапно перестает работать / продолжает выполняться, ничего не происходит при вызове строки "self.maury".Когда я помещаю все в метод init_hardware, он работает отлично, поэтому я предполагаю, что есть небольшая "ошибка" памяти или что-то с объектно-ориентированной структурой.Я действительно хочу, чтобы это оставалось таким образом, есть ли способ изолировать функции таким образом?или я должен ограничить себя большим куском кода?
Редактировать:
Информация о документации:
[Легенда:Звездочки обозначают указатели, а скобки - массивы]
Функция add_tuner добавляет или обновляет один тюнер в объекте драйвера тюнера.
short add_tuner(short tuner_number, char model[ ], short serial_number, short ctlr_num, short ctlr_port, short *no_of_motors, long max_range[ ], double *fmin, double *fmax, double *fcrossover, char error_string[ ])
Выходной сигнал: no_motors, max_range (array of three numbers), fmin, fmax, fcrossover,error_string (80+ characters long), function-return->Error flag
Функция add_controller добавляет или обновляет один контроллер в объекте драйвера тюнера
short add_controller(short controller_number, char driver[ ], char model[ ], int timeout, int address, long delay_ms, char error_string[ ])
Выходной сигнал: error_string, function-return->Error flag
Решение 3
Я обнаружил, что единственный способ вызвать функции в экспортированной библиотеке DLL - это использовать библиотеку DLL через параметр в каждом методе.(программа экспортирует dll и при каждом вызываемом методе будет отправлять ее в качестве параметра).Это выглядит довольно уродливо, но это единственный способ, который, как я обнаружил, работает для меня.Я даже попытался экспортировать DLL в качестве атрибута класса.Система, с которой я работаю, довольно мощная, поэтому я предполагаю, что где-то есть какой-то boboo-код, который приводит к сбою.Спасибо за все отзывы и советы!
/Маздак
Другие советы
Я не уверен в вашей конкретной проблеме, но вот пара общих советов:
Для тех функций, которые вы вызываете вне конструктора, я бы настоятельно рекомендовал установить их argtypes
в конструкторе также.Как только вы объявите о argtypes
, вам не нужно приводить все аргументы как c_short
, c_double
, и т.д.Более того, если вы случайно передадите неверный аргумент функции C, Python выдаст ошибку времени выполнения вместо сбоя в DLL.
Еще одна незначительная деталь, но вы должны использовать x = 0;
byref(x)
или, может быть POINTER
(c_double)()
вместо указателя(c_double()) в тюнере и контроллере.
Недавно я также писал несколько классов ctypes на Python 2.6, и я не видел никаких проблем, подобных тому, что вы описываете.Поскольку, по-видимому, по этому поводу также нет сообщений об ошибках Python, я твердо убежден, что в вашем методе есть всего лишь незначительная деталь, которую мы оба упускаем из виду, и которая вызывает проблему.
Действительно ли какие-либо параметры в add-controller или add-tuner возвращают значения?
Настоятельно рекомендую вам определить прототипы ваших функций, а не вызывать их напрямую с приведением всех параметров.
Я уверен, что вы уже читали эту страницу, но раздел, на который вы хотите обратить внимание, - это Прототипы функций.Делает код намного чище и проще для отслеживания / отладки.
Также - как упоминает Марк Рушаковфф - использование pointer(c_double()) и like в вашем вызове довольно неприятно.Мне гораздо больше повезло с POINTER(), и я еще раз рекомендую вам предварительно указать значение как переменную и передать переменную при вызове вашей функции.Тогда, по крайней мере, вы сможете позже проверить его значение на предмет странного поведения.
Редактировать:Таким образом, ваш прототип и вызов будут выглядеть примерно так:
prototype = WINFUNCTYPE(
c_int, # Return value (correct? Guess)
c_short, # tuner_number
c_char_p, # file_path
c_char_p, # name
c_int, # 0?
c_int, # 0?
c_long, # 0?
c_short, # serial_number
c_char_p, # error_string
)
# 1 input, 2 output, 4 input default to zero (I think; check doc page)
paramflags = (1, 'TunerNumber' ), (1, 'FilePath' ), (1, 'Name' ), ...
AddController = prototype(('add_controller', WinDLL.MlibTuners), paramflags)
Тогда ваш звонок будет намного чище:
arg1 = 0
arg2 = 0
arg3 = 0
AddController(tuner_number, self.file_path, name, arg1, arg2, arg3,
serial_number, self.error_string)