When my code calls a function from a C DLL it gets a access violation error. The function:
int* get_shader_points(int uv_x0, int uv_x1, int uv_y0, int uv_y1, float** triangles, int no_tri){
int max_no_point = ((uv_x1 - uv_x0) * (uv_y0 - uv_y1)) * 2;
int* points = (int*) calloc(NULL, sizeof(int) * max_no_point); // error here
if(points == NULL){
return NULL;
}
int p_Id = 0;
for(int y = uv_y1; y < uv_y0; y )
for(int x = uv_x0; x < uv_x1; x ){
for(int tid = 0; tid < no_tri/3; tid = 3){
if(isInside((int) triangles[tid][0], (int) triangles[tid][1], (int) triangles[tid 1][0], (int) triangles[tid 1][1], (int) triangles[tid 2][0], (int) triangles[tid 2][1], x, y)){
//points[p_Id 0] = x;
//points[p_Id 1] = y;
//p_Id = 2;
}
}
}
return points;
}
I commented out the part where it sets the values in the array, because that also gives me an OSError in python
The error: OSError: exception: access violation writing 0x0000000000002C44
Python code:
lib = WinDLL("./util.dll")
uvx0, uvx1 = -30, 30
uvy0, uvy1 = 30, -30
triangles = [(-20, 10), (-10, 20), (0, 20), (40, 40), (100, 40), (40, 100)]
ptris = ((ctypes.c_float * 2) * len(triangles))(*triangles)
print(lib.get_shader_points(uvx0, uvx1, uvy0, uvy1, ptris, len(ptris)))
Also it should be noted that I am forced to compile the c code using the distutils module from python(using msvc), if that might make the DLL not work properly
CodePudding user response:
I had to do some guessing to make a reproducible example, and changed the signature of the function called slightly. Since a variable number of points can be returned there needs to be a way to know how many points are returned. I also added a way to release the allocated memory:
test.c
// To export functions of Windows DLLs
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
#include <stdlib.h>
// Added missing implementation...just returns true for everything...
int isInside(int x1, int y1, int x2, int y2, int x3, int y3, int x, int y) {
return 1;
}
// float** is the wrong type for a 2D array (at least an easy one to make from Python)
// Also added output parameter for number of points returned.
API int* get_shader_points(int uv_x0, int uv_x1, int uv_y0, int uv_y1, float triangles[][2], int no_tri, int *no_point) {
int max_no_point = ((uv_x1 - uv_x0) * (uv_y0 - uv_y1)) * 2;
// calloc was called incorrectly, it takes a count and size.
int* points = calloc(max_no_point, sizeof(int));
if(points == NULL) {
return NULL;
}
int p_Id = 0;
for(int y = uv_y1; y < uv_y0; y )
for(int x = uv_x0; x < uv_x1; x ) {
for(int tid = 0; tid < no_tri/3; tid = 3) {
if(isInside((int) triangles[tid][0], (int) triangles[tid][1], (int) triangles[tid 1][0], (int) triangles[tid 1][1], (int) triangles[tid 2][0], (int) triangles[tid 2][1], x, y)) {
points[p_Id 0] = x;
points[p_Id 1] = y;
p_Id = 2;
}
}
}
*no_point = p_Id; // return number of points
return points; // and the allocated array
}
API void free_points(int* points) {
free(points);
}
test.py
import ctypes as ct
lib = ct.CDLL('./test') # WinDLL is for 32-bit __stdcall functions
# although either works on 64-bit.
lib.get_shader_points.argtypes = ct.c_int, ct.c_int, ct.c_int, ct.c_int, ct.POINTER(ct.c_float * 2), ct.c_int, ct.POINTER(ct.c_int)
lib.get_shader_points.restype = ct.POINTER(ct.c_int) # Need, or default return value is c_int.
lib.free_points.argtypes = ct.POINTER(ct.c_int),
lib.free_points.restype = None
def get_shader_points(uvx0, uvx1, uvy0, uvy1, triangles):
ptris = ((ct.c_float * 2) * len(triangles))(*triangles)
no_point = ct.c_int() # storage for output parameter
result = lib.get_shader_points(uvx0, uvx1, uvy0, uvy1, ptris, len(ptris), ct.byref(no_point))
retval = result[:no_point.value] # slicing retrieves a list of points of the correct size
lib.free_points(result) # free the allocation.
return retval
uvx0, uvx1 = -3, 3 # reduced range for smaller output since isInside() returns everything right now
uvy0, uvy1 = 3, -3
triangles = [(-20, 10), (-10, 20), (0, 20), (40, 40), (100, 40), (40, 100)]
points = get_shader_points(uvx0, uvx1, uvy0, uvy1, triangles)
print(len(points))
print(points)
Output:
72
[-3, -3, -2, -3, -1, -3, 0, -3, 1, -3, 2, -3, -3, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -2, -3, -1, -2, -1, -1, -1, 0, -1, 1, -1, 2, -1, -3, 0, -2, 0, -1, 0, 0, 0, 1, 0, 2, 0, -3, 1, -2, 1, -1, 1, 0, 1, 1, 1, 2, 1, -3, 2, -2, 2, -1, 2, 0, 2, 1, 2, 2, 2]