I have a function in c++ which returns class object to python and I have a wrapper in python(ctypes import)in below snippet, when i call the function(Get_Student) from python, the School has new instance created in c++ and I cannot retrieve data of Student class,
//The c++ code is:
#include"stdafx.h"
#include<string>
using namespace std;
class Student
{
int ID;
public:
void SetId(int id)
{
ID = id;
}
int GetId()
{
return ID;
}
};
class School{
Student* stud;
public:
void* CreateStudent()
{
stud = new Student();
return stud;
}
Student* GetStudent()
{
return stud;
}
};
extern "C"
{
__declspec(dllexport) void Student_SetId(Student* stud ,int id)
{
stud->SetId(id);
}
__declspec(dllexport) int Student_GetId(Student* stud)
{
return (stud->GetId());
}
__declspec(dllexport) School* School_new(){
return new School();
}
__declspec(dllexport) void* School_CreateStudent(School* school){
return (school->CreateStudent());
}
__declspec(dllexport)Student* School_GetStudent(School* school){
return (school->GetStudent());
}
}
#The Python code is:
from ctypes import*
mydll=cdll.LoadLibrary("D:\\shameel\\Cpp\\Sample_class\\Debug\\Sample_class.dll")
class Student():
def __init__(self):
self.nativeStudent = mydll.School_CreateStudent()
def Set_Id(self,arg):
mydll.Student_SetId(self.nativeStudent,arg)
def Get_Id(self):
return (mydll.Student_GetId(self.nativeStudent))
class School():
def __init__(self):
self.nativeSchool = mydll.School_new()
def CreateStudent(self):
return Student()
def Get_Student(self):
mydll.School_GetStudent.restype = c_void_p
self.nativestd = mydll.School_GetStudent(self.nativeSchool)
return (self.nativestd)
#The Python call is as follows:
fobj = School()
std_new = fobj.CreateStudent()
std_new.Set_Id(3)
Id = std_new.Get_Id()
getobj =fobj.Get_Student()
print(getobj)
when i print getobj its output is "none".
How do i get the same object from the CPP?
ctypes
assumes arguments and return values are 32-bit integers (ctypes.c_int
) unless told otherwise. Particularly if you are using 64-bit Python, pointers will be truncated to 32 bits. The first thing to do is declare the function arguments and return values correctly:
mydll.Student_SetId.argtypes = c_void_p,c_int
mydll.Student_SetId.restype = None
mydll.Student_GetId.argtypes = c_void_p,
mydll.Student_GetId.restype = c_int
mydll.School_new.argtypes = ()
mydll.School_new.restype = c_void_p
mydll.School_CreateStudent.argtypes = c_void_p,
mydll.School_CreateStudent.restype = c_void_p
mydll.School_GetStudent.argtypes = c_void_p,
mydll.School_GetStudent.restype = c_void_p
This will also help you catch errors, such as School_CreateStudent()
needs to be passed a School*
to work properly.
To catch even more errors, declare specific pointer types. Here is a little class that will display its type and an example:
class Ptr(c_void_p):
def __repr__(self):
cls_name = self.__class__.__name__
if self.value is not None:
return f'{cls_name}({self.value:#x})'
return f'{cls_name}(None)'
class pStudent(Ptr): pass
class pSchool(Ptr): pass
Demo:
>>> p = pSchool()
>>> p
pSchool(None)
Then declare the function arguments and results like so:
mydll.Student_SetId.argtypes = pStudent,c_int
mydll.Student_SetId.restype = None
mydll.Student_GetId.argtypes = pStudent,
mydll.Student_GetId.restype = c_int
mydll.School_new.argtypes = ()
mydll.School_new.restype = pSchool
mydll.School_CreateStudent.argtypes = pSchool,
mydll.School_CreateStudent.restype = pStudent
mydll.School_GetStudent.argtypes = pSchool,
mydll.School_GetStudent.restype = pStudent
Now anywhere the code is used incorrectly in Python should give you a good error message.
Once you fix your C++ and Python code your output for print(getobj)
will look something like:
pStudent(0x1b54b89b350)