Проблема с запуском функций из DLL-файла с использованием ctypes в объектно-ориентированном Python

StackOverflow https://stackoverflow.com/questions/1170372

Вопрос

Я очень надеюсь, что это не будет вопрос с уже полученным ответом или глупый.Недавно я программировал с помощью нескольких инструментов.Пытаюсь установить связь между ними, чтобы создать программу тестирования.Однако я столкнулся с некоторыми проблемами с одним конкретным инструментом, когда я пытаюсь вызвать функции, которые я "замаскировал" из 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)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top