In comparison with Ctypes, everything being the same except for the syntax, my CFFI implementation quits throwing access violation.
Process finished with exit code -1073741819 (0xC0000005)
Environment: windows 10 (64-bit) Python versions tried:
- 3.9 (64-bit)
- 3.10 (64-bit)
I have written two separate implementations of calling a DLL function which returns a point cloud. The DLL accepts a pointer to buffer allocated for a structure and the size of the buffer.
Note: while writing the data to the pointcloud buffer, the DLL takes into consideration only the size passed in iBufSize argument, not for the nPoints variable in the structure.
from cffi import FFI
ffi = FFI()
lib = ffi.dlopen("PointCloud.dll")
ffi.cdef(
"""
typedef struct {
double x;
double y;
double z;
} PointXYZ;
typedef struct {
uint32_t nPoints;
PointXYZ * pointcloud;
} PointCloud;
int GetPointCloud(void * ptrPointCloudBuf, int iBufSize);
"""
)
nPts = 5000000
buf_size = nPts * ffi.sizeof('PointXYZ')
pc_struct = ffi.new(
"PointCloud *", {
"nPoints": ffi.cast("uint32_t", 0),
"pointcloud": ffi.new("PointXYZ []", nPts )
}
)
retcode = lib.GetPointCloud(pc_struct, buf_size)
If the everything is fine, the GetPointCloud() function returns retcode
to be SUCCESS
with the data written to the pointcloud buffer, else appropriate errorcode to the `retcode'.
The same implementation with Ctypes gets executed without any problem.
from ctypes import *
lib = cdll.LoadLibrary("PointCloud.dll")
class PointXYZ(Structure):
_fields_ = [
('x', c_double),
('y', c_double),
('z', c_double)
]
class PointCloud(Structure):
_fields_ = [
('nPoints', c_uint32),
('pointcloud', POINTER(PointXYZ)),
]
GetPointCloud = lib['GetPointCloud']
GetPointCloud.restype = c_int
GetPointCloud.argtypes = [POINTER(PointCloud), c_int]
nPts = 5000000
buf_size = nPts * sizeof(PointXYZ)
pc_struct = pointer(
PointCloud(
nPoints=c_uint32(0),
pointcloud=cast((PointXYZ * nPts)(), POINTER(PointXYZ))
)
)
retcode = lib.GetPointCloud(pc_struct, buf_size)
Note:
- DLL (pure C
implementation) Source code is not availabele to me.
- Both, CFFI and Ctypes, implementations were working smoothly for previous versions of DLL, until they changed something in the DLL, while keeping the external interface same.
The contents of the header file supplied with the DLL. Of course it has a few of other functions. But I have pasted only the part of our interest.
#ifndef POINTCLOUD_H
#define POINTCLOUD_H
#if defined(_MSC_VER)
#define POINTCLOUD_DLL_EXPORT __declspec(dllexport)
#else
#define POINTCLOUD_DLL_EXPORT __attribute__ ((visibility ("default")))
#define _stdcall
#endif
// Point structs
typedef struct {
double x;
double y;
double z;
} PointXYZ;
struct PointCloud {
uint32_t number_of_points;
PointXYZ * pointcloud;
PointCloud() {
pointcloud= nullptr;
number_of_points = 0;
}
};
extern "C" POINTCLOUD_DLL_EXPORT int GetPointCloud(void* buffer, int buffer_size);
#endif // POINTCLOUD_H
I have access to the source code of their C/C++ demo application which uses the DLL, which runs absolutely fine. A code snippet for the respective C
code is:
struct PointXYZ
{
double x;
double y;
double z;
};
struct PointCloud {
uint32_t nPoints;
PointXYZ * pointcloud;
PointCloud() {
pointcloud = nullptr;
nPoints = 0;
}
};
PointCloud pcloud;
int nPts = 5000000;
pcloud.pointcloud = new PointXYZ[nPts];
buf_size = sizeof(PointXYZ) * nPts;
int n = GetPointCloud(&pcloud, buf_size);
if(n == 0)
{
printf("Success, result = %d\n", n);
}
else
{
printf("Failure, result = %d\n", n);
}
/*
Do the rest with the point cloud.
*/