【问题标题】:Issues with communicating with USB device through Ctypes and precompiled binaries通过 Ctypes 和预编译的二进制文件与 USB 设备通信的问题
【发布时间】:2022-06-17 03:18:31
【问题描述】:

我在使用 ctypes 连接高斯计 (F.W. Bell 5180) 时遇到问题。制造商提供接口的 DLL 和一个名为 FWB5180.h 的头文件:

FWB5180.h:

    // The following ifdef block is the standard way of creating macros which make exporting
    // from a DLL simpler. All files within this DLL are compiled with the USB5100_EXPORTS
    // symbol defined on the command line. this symbol should not be defined on any project
    // that uses this DLL. This way any other project whose source files include this file see
    // USB5100_API functions as being imported from a DLL, whereas this DLL sees symbols
    // defined with this macro as being exported.
    #ifdef USB5100_EXPORTS
    #define USB5100_API __declspec(dllexport)
    #else
    #define USB5100_API __declspec(dllimport)
    #endif
    extern "C" USB5100_API unsigned int openUSB5100(void);
    extern "C" USB5100_API void closeUSB5100(unsigned int fwb5000ID);
    extern "C" USB5100_API int scpiCommand(unsigned int usbID, char* cmd, char* result, int len);

我的 ctypes Python 代码如下,我要做的就是初始化设备然后关闭它:

import ctypes,time

# open DLL
path = "C:\\Users\\Roger\\fw_bell_magnetic_field_probe\\usb5100-x64\\x64-dist\\usb5100.dll"
fwbell = ctypes.WinDLL(path)

# define open and close functions with argument and return types 
openUSB5100 = fwbell.openUSB5100 
openUSB5100.argtypes = None
openUSB5100.restype = ctypes.c_int

closeUSB5100 = fwbell.closeUSB5100
closeUSB5100.argtypes = [ctypes.c_int]
closeUSB5100.restype = None

# open device
idn = openUSB5100()
print(idn, type(idn))

# close device
time.sleep(0.1)
closeUSB5100(idn)

预期的行为:它在文档的其他地方说idn 是一个四位无符号整数,所以它应该返回一个像 10203045 这样的数字。所以我希望idn 像这样,并且在关闭连接时不会出错.

实际行为:在我的代码中,openUSB5100 始终返回 0,无论设备是否插入。 print 语句始终输出 0 <class 'int'>。然后,closeUSB5100 函数会出现类似OSError: exception: access violation reading 0x0000000000000028 的错误。我也尝试过为idn 使用不同的类型,比如c_ulong,但这似乎没有帮助。

我在使用 python 3.9 的 Windows 10 上。两者都是 64 位的,DLL 也是。

我会注意到,我可以使用他们提供的虚拟程序来使用高斯计,因此严格来说这不是连接问题。不过,我认为他们正在使用带有 32 位驱动程序的 32 位应用程序,因为当我尝试使用他们似乎使用的 DLL 时,我收到以下错误:OSError: [WinError 193] %1 is not a valid Win32 application。当我使用标记为 64 位的 DLL 时,我没有收到此错误。

对我的代码有什么建议或尝试吗?这是我第一次涉足 ctypes,所以我接受可能存在严重错误。

编辑: 这是我收到的确切错误消息。

PS C:\Users\Roger\fw_bell_magnetic_field_probe\usb5100-x64\x64-dist> python .\fw_bell_py.py
Traceback (most recent call last):
  File "C:\Users\Roger\fw_bell_magnetic_field_probe\usb5100-x64\x64-dist\fw_bell_py.py", line 30, in <module>
    idn = openUSB5100()
OSError: exception: access violation reading 0x00000000B56B1D68

如果我多次运行代码,最后一个值 0x ... 通常会发生一些变化。

此外,我发现高斯计在被 PC 检测到后,显然在准备使用时可能真的很慢。因此,如果我在插入设备(或使用 usb.core.list_devices 监视直到出现某些东西)和运行此代码之间等待很长时间,代码 always 在打开命令上出错,它不会进入关闭命令。

【问题讨论】:

  • 从技术上讲,使用openUSB5100.argtypes = () 表示无参数,使用ctypes.c_uint 表示unsigned int 参数,但在这种情况下应该没有区别。此外,WinDLL 用于__stdcall 函数,因此请使用CDLL,但这只会影响到 32 位的可移植性。 WinDLL 和 CDLL 在 64 位上是相同的调用约定。否则,我看不出代码有问题。关闭idn的错误是打开失败所以idn无效。
  • 我做了您建议的更改,但不幸的是,他们没有解决问题。我确实发现在没有插入设备的情况下,我总是得到idn=0,并且代码在关闭时失败。插入设备后,我第一次运行代码时会发生同样的事情,但在随后的代码运行中,我会在 open 语句中得到OSErrors。也许它与有两个 dll 相关,我在代码中明确引用的那个,usb5800.dll,取决于另一个 dll(本质上是 libusb-win32)。除了将其保存在工作目录中之外,我需要做些什么吗?
  • 我认为他们不会。对于这种简单的情况,您应该能够在不设置 argtypes 或 restype 的情况下调用 open,因此如果它在 C 中正常工作,这是某种路径问题。使用像 Process Monitor 这样的工具来监视 DLL 加载失败。见this answer。
  • OSError 的回溯可能会提供线索,如果您想编辑您的问题并发布它。
  • 哈哈,我的代码适用于 32 位库和 32 位 python,但是在 64 位 python 中运行的相同代码似乎不适用于 64 位库。 ProcMon 看起来也差不多。感谢您的帮助!

标签: python c++ python-3.x ctypes python-bindings


【解决方案1】:

代码存在一些问题(参见讨论),但更大的问题是 DLL 文件本身存在一些问题。

【讨论】:

    猜你喜欢
    • 2018-02-17
    • 1970-01-01
    • 2012-12-19
    • 2015-08-30
    • 1970-01-01
    • 2013-04-07
    • 2014-05-26
    • 1970-01-01
    相关资源
    最近更新 更多