问题
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);
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
I am trying to access this function with python instead of LabVIEW because of a lot of issues.
Last three parameters to be passed to the function needs to be an address to an array of 255 elements.
I have no clue how to pass pointers in function in 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!
回答1:
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()
Output:
(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:
- 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
来源:https://stackoverflow.com/questions/51289410/passing-pointers-to-dll-function-in-python