【问题标题】:Problem running functions from a DLL file using ctypes in Object-oriented Python在面向对象的 Python 中使用 ctypes 从 DLL 文件运行函数时出现问题
【发布时间】:2010-11-13 07:28:25
【问题描述】:

我当然希望这不是一个已经回答的问题或一个愚蠢的问题。最近我一直在用几种仪器编程。尝试在它们之间进行通信以创建测试程序。 但是,当我尝试调用从仪器 DLL 文件中“屏蔽”出来的函数时,我遇到了一些特定仪器的问题。 当我使用交互式 python shell 时,它可以完美运行(尽管它有很多单词破坏)。但是当我以面向对象的方式实现这些功能时,程序失败了,实际上它并没有失败,它只是什么都不做。这是第一个调用的方法:(导入了 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

【问题讨论】:

  • 你传递什么作为 add_tuner_and_controller 方法的参数?
  • 调谐器的“名称” = "MT982EU" and serial_number=2316

标签: python dll oop automation ctypes


【解决方案1】:

我不确定您的确切问题,但这里有一些一般性提示:

对于那些在构造函数之外调用的函数,我强烈建议在构造函数中也设置它们的argtypes。一旦你声明了argtypes,你就不需要把所有的参数都转换成c_shortc_double等等。此外,如果你不小心将一个不正确的参数传递给了一个C函数,Python会引发一个运行时错误而不是在 DLL 中崩溃。

另一个小细节,但您应该在调谐器和控制器中使用 x = 0; byref(x)POINTER(c_double)() 而不是 pointer(c_double())。

我最近也在 Python 2.6 中编写了一些 ctypes 类,我还没有看到像您所描述的那样的任何问题。由于显然也没有任何 Python 错误报告,因此我坚信只有一分钟的细节我们都忽略了您的方法中有问题。

【讨论】:

  • 我目前使用的是 Python 2.5,那里可能有问题吗?可以安全地前往新版本吗?
  • 来自python.org/download:“当前的生产版本是 Python 2.6.2 和 Python 3.1...请注意,Python 2.6 和 3.1 都被认为是稳定的生产版本...”
  • 我在 Python 2.5 的生产环境中使用了很多带有 ctypes 相关代码的模块,但我没有看到类似的问题。无论如何,+1 用于设置 argtypes。
【解决方案2】:

add-controller 或 add-tuner 中的参数是否真正返回值?

强烈建议您定义函数的原型,而不是使用所有参数的强制转换直接调用它们。

I'm sure you've read this page already,但您要查看的部分是函数原型。使代码更简洁,更易于跟踪/调试。

另外——正如 Mark Rushakoff 所提到的——在你的电话中使用 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)

【讨论】:

  • 嗯,这实际上并不能解决我的问题,但无论如何感谢您的提示!所以你想让我声明原型并在构造函数中设置参数标志?我知道如果是语法错误,将更容易找到该错误。但这不是,我认为。我已经更改并将所有内容移至构造函数,然后它就可以工作了。但是,一旦从我正在运行的类中调用了一个方法,它总是会卡在“self.maury”行。也许我应该将 DLL 作为每个方法的参数?
【解决方案3】:

我发现调用导出的 DLL 中的函数的唯一方法是通过每个方法中的参数来使用 DLL。 (程序导出 dll 并在每个调用的方法中将其作为参数发送)。 它看起来很丑,但这是我发现为我工作的唯一方式。我什至尝试将 DLL 作为类属性导出。我正在使用的系统非常庞大,所以我猜某处有一些 boboo 代码导致它失败。感谢所有反馈和提示!

/马自达

【讨论】:

    猜你喜欢
    • 2021-02-27
    • 1970-01-01
    • 1970-01-01
    • 2011-02-22
    • 2012-11-01
    • 2021-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多