不同操作系统上的 python ctypes 问题

new*_*man 5 c python windows ctypes python-3.x

我正在尝试转换 C 函数以供 python 3.6 使用。

代码如下:

lib = ctypes.WinDLL('ftrScanAPI.dll') # provided by fingerprint scanner
class FTRSCAN_IMAGE_SIZE(ctypes.Structure):
    _fields_ = [
    ("nWidth", ctypes.c_int),
    ("nHeight", ctypes.c_int),
    ("nImageSize", ctypes.c_int)
]

print('Open device and get device handle...')
hDevice = lib.ftrScanOpenDevice()
print('handle is', hDevice)
print('Get image size...')
Image_size = FTRSCAN_IMAGE_SIZE(0, 0, 0)
if lib.ftrScanGetImageSize(hDevice, ctypes.byref(Image_size)):
    print('Get image size succeed...')
    print('  W', Image_size.nWidth)
    print('  H', Image_size.nHeight)
    print('  Size', Image_size.nImageSize)
else:
    print('Get image size failed...')
Run Code Online (Sandbox Code Playgroud)

函数定义:

typedef struct FTR_PACKED __FTRSCAN_IMAGE_SIZE {
    int nWidth;
    int nHeight;
    int nImageSize;
} FTRSCAN_IMAGE_SIZE, *PFTRSCAN_IMAGE_SIZE;
FTRHANDLE ftrScanOpenDevice();  # typedef void *  FTRHANDLE;
BOOL ftrScanGetImageSize(FTRHANDLE ftrHandle, 
    PFTR_SCAN_IMAGE_SIZE pImageSize);
Run Code Online (Sandbox Code Playgroud)

不同的操作系统具有相同的代码似乎有不同的结果:

  • 在 Windows 7 64 位上
    输出1

  • 在 Windows 10 64 位上,
    我不打印“handle is here” 输出2

    我尝试过的:
    根据堆栈溢出的一些答案,这可能是由于未显式分配函数argtypes和restype引起的,所以我尝试但失败了。

  • Cri*_*ati 5

    99%的情况下,参数(和/或返回)类型不一致之间的不一致是原因(检查[SO]:通过 ctypes 从 Python 调用的 C 函数返回不正确的值(@CristiFati 的答案)以了解更多详细信息)。

    始终拥有[Python.Docs]:ctypes -使用CTypes时打开的Python 外部函数库

    我找到了[GitHub]:erikssm/futronics-fingerprint-reader - (master) futronics-fingerprint-reader/ftrScanAPI.h(我不知道它与您当前拥有的有什么不同,但到目前为止您发布的内容似乎匹配) ),我对您的代码做了一些更改:

    • 定义函数的argtypesrestype

    • 定义缺失的类型(仅为了清楚起见)

    • 其他一些无关紧要的更改(重命名)

    • 我在上面的文件中注意到的另一件事是一个#pragma pack(push, 1)宏(检查[MS.Docs]: pack以了解更多详细信息)。对于这个结构来说,没有什么区别(感谢 @AnttiHaapala 的提示),因为 3 int4字节)成员对齐不会改变,但对于其他结构(具有“较小”成员类型(例如charShort))你可能想添加:_pack_ = 1

    您修改后的代码(不用说,我没有运行它,因为我没有 .dll

    #!/usr/bin/env python
    
    import ctypes as cts
    from ctypes import wintypes as wts
    
    
    # ...
    
    
    class FTRSCAN_IMAGE_SIZE(cts.Structure):
        # _pack_ = 1
        _fields_ = (
            ("nWidth", cts.c_int),
            ("nHeight", cts.c_int),
            ("nImageSize", cts.c_int),
        )
    
    PFTRSCAN_IMAGE_SIZE = cts.POINTER(FTRSCAN_IMAGE_SIZE)
    FTRHANDLE = cts.c_void_p
    
    lib = cts.WinDLL("ftrScanAPI.dll")  # provided by fingerprint scanner
    
    ftrScanOpenDevice = lib.ftrScanOpenDevice
    ftrScanOpenDevice.argtypes = ()
    ftrScanOpenDevice.restype = FTRHANDLE
    
    ftrScanGetImageSize = lib.ftrScanGetImageSize
    ftrScanGetImageSize.argtypes = (FTRHANDLE, PFTRSCAN_IMAGE_SIZE)
    ftrScanGetImageSize.restype = wts.BOOL
    
    print("Open device and get device handle...")
    h_device = ftrScanOpenDevice()
    print("Handle is:", h_device)
    print("Get image size...")
    image_size = FTRSCAN_IMAGE_SIZE(0, 0, 0)
    
    if ftrScanGetImageSize(h_device, cts.byref(image_size)):
        print("Get image size succeed...")
        print("  W:", image_size.nWidth)
        print("  H:", image_size.nHeight)
        print("  Size:", image_size.nImageSize)
    else:
        print("Get image size failed...")
    
    Run Code Online (Sandbox Code Playgroud)