在Python中传递指向DLL函数的指针 [英] Passing pointers to DLL function in Python

查看:121
本文介绍了在Python中传递指向DLL函数的指针的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am working on a project where I have to build a GUI for a development board with python with which I am new to as well. I am given the DLL which has required functions to communicate with the development board. I have LabVIEW equivalent function prototype which looks something like this:

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

对于Visual Basic,相同的原型也看起来像这样:

And the same prototype also looks like this for 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访问此函数.

I am trying to access this function with python instead of LabVIEW because of a lot of issues.

要传递给函数的最后三个参数必须是255个元素的数组的地址.

Last three parameters to be passed to the function needs to be an address to an array of 255 elements.

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

我编写了以下短代码以在python中访问此功能:

I wrote the following shortcode to access this function in 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)

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

After executing this code I get following error message:

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

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

Any help will be appreciated!! Thanks a lot!

推荐答案

作为 SO 充满了类似的问题(我回答了其中的几个问题).

As [Python]: ctypes - A foreign function library for Python states, there are a few things to do, out of which the most important is setting argtypes and restype for the function object. SO is full of similar questions (I answered to several of them).

无论如何,我准备了一个虚拟示例(不要介意错误倾向),这只是为了说明这种机制.

Anyway, I prepared a dummy example (don't mind the error proneness), it's just for illustrating the mechanism.

code.c :

#include <stdio.h>
#include <inttypes.h>

#define DIM 10  // Must be the SAME (well, or lower) than the constant defined in the Python code


__declspec(dllexport) int32_t __stdcall WriteFPGARegsC(int16_t *USBdev, int32_t *DUTSelect, int32_t *Array_RegsIn, int32_t *Array_RegsOut, int32_t *Array_RegEnable) {
    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, Array_RegsIn[0], Array_RegsOut[0], Array_RegEnable[0], ret);
    for (int i = 0; i < DIM; i++) {
        Array_RegsOut[i] *= *DUTSelect;
    }
    return ret;
}

code.py :

import sys
import ctypes


DIM = 10  # Should be 255, but for demo purposes keep it smaller
uint_arr = ctypes.c_uint * DIM
ushort_arr = ctypes.c_ushort * DIM
uint_p = ctypes.POINTER(ctypes.c_uint)
ushort_p = ctypes.POINTER(ctypes.c_ushort)


def main():
    dll = ctypes.WinDLL("USB_IO_for_VB6.dll")
    func = dll.WriteFPGARegsC
    func.argtypes = [ushort_p, uint_p, uint_p, uint_p, uint_p]
    func.restype = ctypes.c_uint

    usb_dev = ctypes.c_ushort(25)
    dut_select = ctypes.c_uint(2)
    regs_in = uint_arr(*range(20, 20 + DIM))
    regs_out = uint_arr(*range(30, 30 + DIM))
    reg_enable = uint_arr(*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 = func(ctypes.byref(usb_dev), ctypes.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} on {:s}\n".format(sys.version, sys.platform))
    main()

输出:

(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
code.c
code.py

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

(py35x64_test) e:\Work\Dev\StackOverflow\q051289410>dir /b
code.c
code.obj
code.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" code.py
Python 3.5.4 (v3.5.4:3f56838, Aug  8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] 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

@ EDIT0 :

@EDIT0:

  • 修改后的答案应尽可能接近实际情况,并解决评论中的问题
    • 为清楚起见,可以将 ctypes 数组与其他任何 Python 序列一样访问
    • Modified answer to be as close as possible to the real scenario, and also to address questions in the comments
      • To make it clear, a ctypes array can be accessed as any other Python sequence

      这篇关于在Python中传递指向DLL函数的指针的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆