I am currently writing a wrapper for a C++ library. The library is a 32-bits dll file and I’m using 64-bits so I’m using msl-loadlib
. I have a problem wrapping a function that has pointer parameters.
Here is the header of the function in C++
int CUSB::GetMeasurement(int Group, int StartPoint, int* NumberOfPoints, double* XData, double** YData, eFilter Filter)
and here the wrapper I wrote
from msl.loadlib import Server32
import ctypes
from client import Client
class Server(Server32):
def __init__(self, host: str, port: int):
super().__init__("USBLib.dll", "cdll", host, port)
def getMeasurement(self, group: int, startPoint: int, nbrOfPoints: int, filter: Client.Filter):
self.lib.GetMeasurement.restype = int
xData = (ctypes.c_double * 65536)()
yData = ((ctypes.c_double * 3) * 65536)()
self.lib.GetMeasurement(
ctypes.c_int(int(group)),
ctypes.c_int(int(startPoint)),
ctypes.pointer(ctypes.c_int(int(nbrOfPoints))),
ctypes.byref(xData),
ctypes.byref(yData),
ctypes.c_int(int(filter.value[0]))
)
return xData, yData
from enum import Enum, unique
from msl.loadlib import Client64
class Client(Client64):
@unique
class Filter(Enum):
NONE = 0,
LOWPASS = 1
def getMeasurement(self, group: int, startPoint: int, nbrOfPoints: int, filter: Filter):
return self.request32(
'getMeasurement',
group,
startPoint,
nbrOfPoints,
filter
)
When I call Client.getMeasurement(parameters)
, I get the following error
File 'C:\Users\DELL\Documents\python\USBlib\server.py', line 77, in getMeasurement
ctypes.c_int(int(filter.value[0]))
OSError: exception: access violation writing 0x00000000
Edit :
I tried to use ctypes argtypes.
xData = (ctypes.c_double * 65536)()
yData = ((ctypes.c_double * 3) * 65536)()
nbrOfPoints = ctypes.c_int()
self.lib.GetMeasurement.argtypes = [
ctypes.c_int,
ctypes.c_int,
ctypes.POINTER(ctypes.c_int),
ctypes.POINTER(ctypes.c_double),
ctypes.POINTER(ctypes.POINTER(ctypes.c_double)),
ctypes.c_int
]
dataSize = ctypes.c_int(int(inputDataSize - previousPoint))
self.lib.GetMeasurement(1, previousPoint, ctypes.byref(dataSize), xData, yData, Client.Filter.NONE)
I have a C++ sample code that is using the GetMeasurement function :
int PreviousPoint = 0;
double* ppYData1[3];
double* pXData1;
int UpdateSize = 65536;
for (int channel=0; channel<3; channel++)
{
ppYData1[channel] = new double[UpdateSize];
}
pXData1 = new double[UpdateSize];
int DataSize = Input1DataSize-PreviousPoint;
GetMeasurement(INPUT1, PreviousPoint, &DataSize, pXData1, ppYData1, (eFilter)(TC->SC->m_ScanConfiguration.m_nFilter));
Advertisement
Answer
I’m ignoring msl-loadlib
as extraneous to the problem of calling ctypes correctly.
Here’s an example of calling the function shown. The YData
needs to be an array of 3 double* and then each of those pointers needs to be initialized with the next dimension of the array. Note this parallels the C++ example of calling the function.
test.cpp – sample implementation to fill out the arrays.
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
typedef int eFilter;
extern "C" {
API int GetMeasurement(int Group, int StartPoint, int* NumberOfPoints, double* XData, double** YData, eFilter Filter) {
for(int i = 0; i < 65536; ++i) {
XData[i] = i;
YData[0][i] = i + .25;
YData[1][i] = i + .5;
YData[2][i] = i + .75;
}
return 0;
}
}
test.py – ctypes example to call the function
import ctypes as ct
pdouble = ct.POINTER(ct.c_double)
ppdouble = ct.POINTER(pdouble)
dll = ct.CDLL('./test')
dll.GetMeasurement.argtypes = ct.c_int, ct.c_int, ct.POINTER(ct.c_int), pdouble, ppdouble, ct.c_int
dll.GetMeasurement.restype = ct.c_int
xData = (ct.c_double * 65536)()
yData = (pdouble * 3)()
for channel in range(3):
yData[channel] = (ct.c_double * 65536)()
nbrOfPoints = ct.c_int()
dll.GetMeasurement(1, 0, ct.byref(nbrOfPoints), xData, yData, 0)
print(xData[0],xData[65535])
print(yData[0][0],yData[1][0],yData[2][0])
print(yData[0][65535],yData[1][65535],yData[2][65535])
Output:
0.0 65535.0
0.25 0.5 0.75
65535.25 65535.5 65535.75