在 Python 中将指针传递给 DLL 函数

问题描述 投票:0回答:1

我正在开发一个项目,我必须使用 python 为开发板构建一个 GUI,我也是新手。我得到了 DLL,它具有与开发板通信所需的功能。 我有 LabVIEW 等效函数原型,如下所示:

int32_t WriteFPGARegsC(int16_t *USBdev, int32_t *DUTSelect, int32_t *Array_RegsIn, int32_t *Array_RegsOut, int32_t *Array_RegEnable);

对于 Visual Basic,相同的原型也如下所示:

Public Declare Function WriteFPGARegsC Lib "USB_IO_for_VB6.dll" (ByRef USBdev As Short, ByVal DUTSelect As Integer, ByRef Array_RegsIn As Integer, ByRef Array_RegsOut As Integer, ByRef Array_RegEnable As Integer) As Integer

由于存在很多问题,我尝试使用 python 而不是 LabVIEW 来访问此函数。

传递给函数的最后三个参数需要是包含 255 个元素的数组的地址。

我不知道如何在Python中的函数中传递指针!

我编写了以下短代码来在 python 中访问此函数:

USBdev = [0]
DUTSelect = [0]
RegsIn = [0] * 255
RegsOut = [0] * 255
RegEnable = [0] * 255

from ctypes import*

mydll = cdll.LoadLibrary("USB_IO_for_VB6.dll")
retmydll = mydll.WriteFPGARegsC(USBdev, DUTSelect, RegsIn, RegsOut, RegEnable)

执行此代码后,我收到以下错误消息:

Traceback (most recent call last):
  File "D:\Kushal\ATLASS\Source_code\Atlass.py", line 12, in <module>
    retmydll = mydll.WriteFPGARegsC(id(USBdev), id(DUTSelect), id(RegsIn),    id(RegsOut), id(RegEnable))
ValueError: Procedure called with not enough arguments (20 bytes missing) or wrong calling convention

任何帮助将不胜感激! 非常感谢!

python dll
1个回答
3
投票

清单 [Python.Docs]:ctypes - Python 的外部函数库
在一切之前,请检查[SO]:通过 ctypes 从 Python 调用的 C 函数返回不正确的值(@CristiFati 的答案),了解使用 CTypes(调用函数)时的常见陷阱。

无论如何,我准备了一个虚拟示例(不要介意容易出错),它只是为了说明机制。

  • dll00.c:

    #if defined(_WIN32)
    #  define DLL00_EXPORT_API __declspec(dllexport)
    #else
    #  define DLL00_EXPORT_API
    #endif
    
    #include <stdint.h>
    #include <stdio.h>
    
    #define DIM 10  // Must be the SAME (well, or lower) than the constant defined in the Python code
    
    
    DLL00_EXPORT_API int32_t __stdcall WriteFPGARegsC(int16_t *USBdev, int32_t *DUTSelect, int32_t *ArrayRegsIn, int32_t *ArrayRegsOut, int32_t *ArrayRegEnable)
    {
        int32_t ret = 99;
        printf("From C:\n\t*USBdev: %d\n\t*DUTSelect: %d\n\tArray_RegsIn[0]: %d\n\tArray_RegsOut[0]: %d\n\tArray_RegEnable[0]: %d\n\n\tReturning: %d\n",
        *USBdev, *DUTSelect, ArrayRegsIn[0], ArrayRegsOut[0], ArrayRegEnable[0], ret);
        for (int i = 0; i < DIM; i++) {
            ArrayRegsOut[i] *= *DUTSelect;
        }
        return ret;
    }
    
  • code00.py:

    #!/usr/bin/env python
    
    import ctypes as cts
    import sys
    
    
    DIM = 10  # Should be 255, but for demo purposes keep it smaller
    UIntArr = cts.c_uint * DIM
    UShortArr = cts.c_ushort * DIM
    UIntPtr = cts.POINTER(cts.c_uint)
    UShortPtr = cts.POINTER(cts.c_ushort)
    
    
    def main(*argv):
        dll = cts.WinDLL("./USB_IO_for_VB6.dll")
        dll_func = dll.WriteFPGARegsC
        dll_func.argtypes = (UShortPtr, UIntPtr, UIntPtr, UIntPtr, UIntPtr)
        dll_func.restype = cts.c_uint
    
        usb_dev = cts.c_ushort(25)
        dut_select = cts.c_uint(2)
        regs_in = UIntArr(*range(20, 20 + DIM))
        regs_out = UIntArr(*range(30, 30 + DIM))
        reg_enable = UIntArr(*range(40, 40 + DIM))
    
        nth = 5
        print("Output register array: {:s}".format(" ".join(["{:d}".format(item) for item in regs_out])))
        print("\tIts {:d}th element: {:d}\n".format(nth, regs_out[nth]))
    
        ret = dll_func(cts.byref(usb_dev), cts.byref(dut_select), regs_in, regs_out, reg_enable)
        print("\nFunction returned: {:d}".format(ret))
        print("Output register array: {:s}".format(" ".join(["{:d}".format(item) for item in regs_out])))
        print("\tIts {:d}th element: {:d}\n".format(nth, regs_out[nth]))
    
    
    if __name__ == "__main__":
        print(
            "Python {:s} {:03d}bit on {:s}\n".format(
                " ".join(elem.strip() for elem in sys.version.split("\n")),
                64 if sys.maxsize > 0x100000000 else 32,
                sys.platform,
            )
        )
        rc = main(*sys.argv[1:])
        print("\nDone.\n")
        sys.exit(rc)
    
    

输出

(py35x64_test) e:\Work\Dev\StackOverflow\q051289410> "c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\vcvarsall.bat" amd64

(py35x64_test) e:\Work\Dev\StackOverflow\q051289410> dir /b
dll00.c
code00.py

(py35x64_test) e:\Work\Dev\StackOverflow\q051289410> cl /nologo dll00.c /link /DLL /OUT:USB_IO_for_VB6.dll
dll00.c
  Creating library USB_IO_for_VB6.lib and object USB_IO_for_VB6.exp

(py35x64_test) e:\Work\Dev\StackOverflow\q051289410> dir /b
dll00.c
dll00.obj
code00.py
USB_IO_for_VB6.dll
USB_IO_for_VB6.exp
USB_IO_for_VB6.lib

(py35x64_test) e:\Work\Dev\StackOverflow\q051289410> "e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" ./code00.py
Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] 064BIT on win32

Output register array: 30 31 32 33 34 35 36 37 38 39
        Its 5th element: 35

From C:
        *USBdev: 25
        *DUTSelect: 2
        Array_RegsIn[0]: 20
        Array_RegsOut[0]: 30
        Array_RegEnable[0]: 40

        Returning: 99

Function returned: 99
Output register array: 60 62 64 66 68 70 72 74 76 78
        Its 5th element: 70


更新#0

  • 修改答案尽可能贴近真实场景,也解决评论中的问题

    • 为了明确起见,可以像任何其他 Python 序列一样访问 CTypes 数组
© www.soinside.com 2019 - 2024. All rights reserved.