Python, using ctypes to create C++ class wrapper

c, ctypes, dll, python

Solution

Everything works fine... but you forgot to pass along the return value of the C function in the method MyMath.FunAdd!

def FunAdd(self, a, b):
    return self.FunMath.MyAdd(self.obj, a, b)
    ^^^^^^

Problem

I'm well aware that there is no standard ABI for c++, so this is what I did: ``` //trialDLL.h #ifndef TRIALDLL_H_ #define TRIALDLL_H_ class MyMathFuncs { private: double offset; public: MyMathFuncs(double offset); ~MyMathFuncs(); double Add(double a, double b); double Multiply(double a, double b); double getOffset(); }; #ifdef __cplusplus extern "C"{ #endif #ifdef TRIALDLL_EXPORT #define TRIALDLL_API __declspec(dllexport) #else #define TRIALDLL_API __declspec(dllimport) #endif TRIALDLL_API MyMathFuncs* __stdcall new_MyMathFuncs(double offset); TRIALDLL_API void __stdcall del_MyMathFuncs(MyMathFuncs *myMath); TRIALDLL_API double __stdcall MyAdd(MyMathFuncs* myMath, double a, double b); #ifdef __cplusplus } #endif #endif ``` And the definition .cpp: (Other class functions' definitions are omitted) ``` //trialDLL.cpp #include "trialDLL.h" MyMathFuncs* __stdcall new_MyMathFuncs(double offset) { return new MyMathFuncs(offset); } void __stdcall del_MyMathFuncs(MyMathFuncs *myMath) { myMath->~MyMathFuncs(); } double __stdcall MyAdd(MyMathFuncs *myMath, double a, double b) { return myMath->Add(a, b); } // class functions double MyMathFuncs::Add(double a, double b) { return a+b+ this->offset; } ``` And I build this into a dll and named it trialDLL3.dll. Then in python, I wrote a module as: ``` #trialDLL3.py import ctypes from ctypes import WinDLL class MyMath(object): def __init__(self, offset): self.FunMath = WinDLL('trialDLL3.dll') self.FunMath.new_MyMathFuncs.argtypes = [ctypes.c_double] self.FunMath.new_MyMathFuncs.restype = ctypes.c_void_p self.FunMath.MyAdd.argtypes = [ctypes.c_void_p, \ ctypes.c_double, ctypes.c_double] self.FunMath.MyAdd.restype = ctypes.c_double self.obj = self.FunMath.new_MyMathFuncs(offset) def FunAdd(self, a, b): self.FunMath.MyAdd(self.obj, a, b) def delete(): self.FunMath.del_MyMathFuncs() ``` After all these, strange things happened. In the IDLE python shell, I did: ``` theMath = MyMath(3.3) #create the instance theMath.FunAdd(3.3, 3.3) #call the function ``` The second line returned None instead of 9.9. Then I tried another way round, putting this line in the shell: ``` theMath.FunMath.MyAdd(theMath.obj, 3.3 ,3.3) ``` And this line returns me an unsurprising 9.9, but surprising when compared to the last result None. Shouldn't these two lines identical? And I decided to run all those lines explicitly in python shell and see what can go wrong, writing: (excluding the imports) ``` loadedDLL = WinDLL('trialDLL3.dll') loadedDLL.new_MyMathFuncs.argtypes = [ctypes.c_double] loadedDLL.new_MyMathFuncs.restype = ctypes.c_void_p loadedDLL.MyAdd.argtypes = [ctypes.c_void_p, \ ctypes.c_double, ctypes.c_double] loadedDLL.MyAdd.restype = ctypes.c_double obj = loadedDLL.new_MyMathFuncs(3.3) FunMath.MyAdd(obj, 3.3, 3.3) ``` All these lines finally returned 9.9. Aren't these lines identical to the two lines if the trialDLL3.py module is imported? ``` theMath = MyMath(3.3) #create the instance theMath.FunAdd(3.3, 3.3) #call the function ``` If they are the same deal, why the two line class version returns None and the explicit way return expected 9.9? Thanks in advance!

Original source