pythonc++ctypesdynamic-dll-import

Wrong ctypes assignation


I made a CPP DLL and I'm trying to call function inside it from python. I've achieved this multiple times for other functions, but this one, I just can't find my mistake.

dll_name = "..\\src\\x64\\Debug\\2019-3A-IBD-MLDLL.dll"
dllabspath = os.path.dirname(os.path.abspath(__file__)) + os.path.sep + dll_name
myDll = CDLL(dllabspath)

#fit_reg_RBF_naive
myDll.fit_reg_RBF_naive.argtypes = [ct.c_void_p, ct.c_double,  ct.c_void_p, ct.c_int, ct.c_int]
myDll.fit_reg_RBF_naive.restypes = ct.c_void_p

#predict_reg_RBF_naive
myDll.predict_reg_RBF_naive.argtypes = [ct.c_void_p, ct.c_void_p, ct.c_void_p, ct.c_int, ct.c_double, ct.c_int]
myDll.predict_reg_RBF_naive.restypes = ct.c_double

def fit_reg_RBF_naive(pyXTrain, pyGamma, pyYTrain, pySampleCount, pyInputCountPerSample):
    XTrain = (ct.c_double * len(pyXTrain))(*pyXTrain)
    YTrain = (ct.c_double * len(pyYTrain))(*pyYTrain)
    inputCountPerSample = ct.c_int(pyInputCountPerSample)
    sampleCount = ct.c_int(pySampleCount)
    gamma = ct.c_double(pyGamma)
    return myDll.fit_reg_RBF_naive(XTrain, gamma, YTrain, sampleCount, inputCountPerSample)

def predict_reg_RBF_naive(pyW, pyXTrain, pyXpredict ,pyInputCountPerSample, pyGamma, pySampleCount):
    XTrain = (ct.c_double * len(pyXTrain))(*pyXTrain)
    inputCountPerSample = ct.c_int(pyInputCountPerSample)
    sampleCount = ct.c_int(pySampleCount)
    gamma = ct.c_double(pyGamma)
    Xpredict = (ct.c_double * len(pyXpredict))(*pyXpredict)
    return myDll.predict_reg_RBF_naive(W, XTrain, Xpredict, inputCountPerSample, gamma, sampleCount)

Basically I load my DLL, set Ctypes for arguments and result for both of my fonctions. Then I make a python wrapper so that the user does not have to retype every cast from python to cpp.

My types on the cpp side seems good too:

extern "C" {

    SUPEREXPORT double predict_reg_RBF_naive(double* W, double* X, double* Xpredict, int inputCountPerSample, double gamma, int N);
    SUPEREXPORT double* fit_reg_RBF_naive(double* XTrain, double gamma, double* YTrain, int sampleCount, int inputCountPerSample);
}

I have no warning from the compiler for the cpp part, I've printed the memory adresse before the return inside fit_reg_RBF_naive from cpp and the W in python and they are the same.

000002B358384980 // cpp address of W before return
0x58384980       # Python address of W after function call

For me it seems the same address. Maybe I'm wrong.

So when I try to call my second cpp function it said

myDll.predict_reg_RBF_naive(W, XTrain, Xpredict,inputCountPerSample, gamma, sampleCount) OSError: exception: access violation reading 0x000000007C7380A0

It crashed in the cpp when it tries to read W. They are no free or 'delete' in the cpp and the variable is properly allocated : double* W = new double[2];

Also, when I print W type in python I get <class 'int'>.

How comes my W seems to have the same address regarding the language, but has not the good type? Changing the result type of fit_reg_RBF_naive to POINTER(ct.c_double * 2) makes no change.

EDIT:

Here is how I call my functions:

from dll_load import predict_reg_RBF_naive, fit_reg_RBF_naive

gamma = 50
sampleCount = 2
inputCountPerSample = 3
XTrain = [1.0, 1.0, 1.0, 3.0, 3.0, 3.0]
YTrain = [-1.0, 1.0]
Xpredict = [1.0, 1.0, 1.0]

W = fit_reg_RBF_naive(XTrain, gamma, YTrain, sampleCount, inputCountPerSample)

print(predict_reg_RBF_naive(W, XTrain, Xpredict, inputCountPerSample, gamma, sampleCount))

Solution

  • [Python 3.Docs]: ctypes - A foreign function library for Python.

    You misspelled restypes (it should be restype). By doing so, restype is not initialized, and defaults to int (this wouldn't be a problem on 32bit), and you ran into:

    Besides that, there are several problems in the code: