简体   繁体   English

在面向对象的Python中使用ctypes从DLL文件运行函数时出现问题

[英]Problem running functions from a DLL file using ctypes in Object-oriented Python

I sure hope this won't be an already answered question or a stupid one. 我肯定希望这不会是已经回答的问题或愚蠢的问题。 Recently I've been programming with several instruments. 最近,我一直在使用几种仪器进行编程。 Trying to communicate between them in order to create a testing program. 尝试在它们之间进行通信以创建测试程序。 However I've encoutered some problems with one specific instrument when I'm trying to call functions that I've "masked" out from the instruments DLL file. 但是,当我尝试调用从工具DLL文件中“屏蔽”的函数时,我遇到了一种特定工具的一些问题。 When I use the interactive python shell it works perfectly (although its alot of word clobbering). 当我使用交互式python shell时,它可以完美地工作(尽管它有很多词破坏功能)。 But when I implement the functions in a object-oriented manner the program fails, well actually it doesn't fail it just doesn't do anything. 但是,当我以面向对象的方式实现功能时,程序会失败,实际上它不会失败,只是什么也没做。 This is the first method that's called: (ctypes and ctypes.util is imported) 这是第一个调用的方法:(导入了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

Now that works swell, everything is perfect and I get perfect log-entries. 现在一切正常,一切都很完美,我得到了完美的登录记录。 But when I try to run a method further into the program called: 但是当我尝试在程序中进一步运行一种方法时:

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)

The program suddenly stops working/keeps running , nothing happenes when the "self.maury"-line is called. 该程序突然停止工作/继续运行,当调用“ self.maury”行时没有任何反应。 When I place everything in the init_hardware method it works perfectly so I'm guessing there's a slight memory "error" or something with the objective oriented structure. 当我将所有内容放置在init_hardware方法中时,它可以完美地工作,因此我猜测存在轻微的内存“错误”或具有面向对象的结构。 I really want it to remain this way, is there anyway to isolate the functions in this manner? 我真的希望它保持这种方式,是否仍以这种方式隔离功能? or do I have to restrict myself to a big chunk of code? 还是我必须限制自己使用大量代码?


EDIT: 编辑:
Documentation info : 文件资料
[Legend: The stars indicate pointers and the brackets indicate arrays] [图例:星号表示指针,方括号表示数组]

The add_tuner function adds or updates one tuner in the tuner driver object. 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[ ])

Output : no_motors, max_range (array of three numbers), fmin, fmax, fcrossover,error_string (80+ characters long), function-return->Error flag 输出no_motors, max_range (array of three numbers), fmin, fmax, fcrossover,error_string (80+ characters long), function-return->Error flag



The add_controller function adds or updates one controller in the tuner driver object add_controller函数在调谐器驱动程序对象中添加或更新一个控制器

short add_controller(short controller_number, char driver[ ], char model[ ], int timeout, int address, long delay_ms, char error_string[ ])

Output : error_string, function-return->Error flag 输出error_string, function-return->Error flag

I'm not sure about your exact problem, but here's a couple general tips: 我不确定您的确切问题,但是这里有一些一般性提示:

For those functions that you are calling outside of the constructor, I would strongly recommend setting their argtypes in the constructor as well. 对于在构造函数之外调用的那些函数,我强烈建议您也在构造函数中设置其argtypes Once you've declared the argtypes , you shouldn't need to cast all the arguments as c_short , c_double , etc. Moreover, if you do accidentally pass an incorrect argument to a C function, Python will raise a runtime error instead of crashing within the DLL. 声明argtypes ,您无需将所有参数都c_short c_doublec_shortc_double等。此外,如果确实不小心将错误的参数传递给C函数,Python会引发运行时错误,而不会崩溃DLL。

Another minor detail, but you should be using x = 0; 另一个小细节,但是您应该使用x = 0; byref(x) or maybe POINTER (c_double)() instead of pointer(c_double()) in the tuner and controller. byref(x)或可能是调谐器和控制器中的POINTER (c_double)()而不是pointer(c_double())。

I've been writing some ctypes classes in Python 2.6 recently as well, and I haven't seen any issues like what you're describing. 最近,我也一直在Python 2.6中编写一些ctypes类,而且还没有看到任何类似您所描述的问题。 Since there apparently aren't any Python bug reports on that either, I strongly believe that there's just a minute detail that we are both overlooking in your method that is having a problem. 由于显然也没有关于此的任何Python错误报告,因此我坚信,在您遇到问题的方法中,我们都忽略了只有一分钟的细节。

Are any of the parameters in add-controller or add-tuner actually return values? add-controller或add-tuner中的任何参数是否实际返回值?

Strongly recommend that you define prototypes of your functions, rather than calling them direct with casts of all the parameters. 强烈建议您定义函数的原型,而不要直接对所有参数进行强制转换。

I'm sure you've read this page already , but the section you want to look at is Function Prototypes. 我确定您已经阅读了此页面 ,但是要查看的部分是“函数原型”。 Makes the code much cleaner and easier to trace/debug. 使代码更简洁,更易于跟踪/调试。

Also -- as Mark Rushakoff mentions too -- using pointer(c_double()) and like in your call is pretty icky. 而且-正如Mark Rushakoff所提到的-使用指针(c_double())就像在您的通话中那样非常糟糕。 I have much better luck w/ POINTER(), and recommend again that you predeclare the value as a variable, and pass the variable in your function call. 我很高兴w / POINTER(),再次建议您将值预先声明为变量,并在函数调用中传递该变量。 Then at least you can examine its value afterward for strange behavior. 然后,至少您可以随后检查其值是否为异常行为。

EDIT: So your prototype and call will look something like this: 编辑:因此您的原型和调用将看起来像这样:

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)

Then your call is much cleaner: 这样您的通话会更加干净:

arg1 = 0
arg2 = 0
arg3 = 0
AddController(tuner_number, self.file_path, name, arg1, arg2, arg3, 
    serial_number, self.error_string)

I found out that the only way to call the functions in the exported DLL was to use the DLL through a parameter in each method. 我发现,调用导出的DLL中的函数的唯一方法是通过每个方法中的参数使用DLL。 (the program exports the dll and in each method called it will send it as a parameter). (程序导出dll,并在每个调用的方法中将其作为参数发送)。 It looks pretty ugly but that's the only way I found to be working for me. 它看起来很丑陋,但这是我发现为我工作的唯一方法。 I even tried exporting the DLL as an class attribute. 我什至尝试将DLL导出为类属性。 The system I'm working with is pretty hefty so I guess there is some boboo-code somewhere that makes it fail. 我正在使用的系统非常庞大,所以我猜想某个地方有一些boboo代码会使它失败。 Thanks for all the feedback and tips! 感谢您的所有反馈和提示!

/Mazdak /马萨达克

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM