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