I was able to return a string by creating it in memory and just passing an pointer and size of the string to python. I created a example project where I tested I few functions to return values before I implemented them: The example below is where I returned a string array, I made some changed to code below to fit the Q so I may have made a mistake somewhere.
C#:
[DllExport]
static void StringArrayExample(out IntPtr unmanagedArray, out int length)//for ref value you have to use out
{
var valueList = new[]
{
"aaa", "bbb", "ccc"
};
length = valueList.Length;//return the length of the array
IntPtr[] ArrayPtr = new IntPtr[valueList.Length];
for (int i = 0; i < valueList.Length; i++)//create list of string arrays and
{
byte[] chars = System.Text.Encoding.ASCII.GetBytes(valueList[i] + '\0');//convert string to byte array
ArrayPtr[i] = Marshal.AllocHGlobal(chars.Length * Marshal.SizeOf(typeof(char)));//allocate memory to char array, return ptr to location
Marshal.Copy(chars, 0, ArrayPtr[i], chars.Length);//copy char array to memory location
}
//Create memory location to store pointers
unmanagedArray = Marshal.AllocHGlobal(valueList.Length * Marshal.SizeOf(typeof(IntPtr)));
//copy over all pointer to memory location
Marshal.Copy(ArrayPtr, 0, unmanagedArray, ArrayPtr.Length);
}
and the python function to call this function:
class Arrays is the data structure that I used for a string array.
Cdll = ctypes.WinDLL("CtypesExamples.dll")
class Arrays(ctypes.Structure):# 2 string arrays
_fields_ = [ ('arr1', ctypes.POINTER(ctypes.c_char_p)),
('size1', ctypes.c_int),
('arr2', ctypes.POINTER(ctypes.c_char_p)),
('size2', ctypes.c_int)]
def StringArray(self, dllfunc, stringlist):
unmanagedArray = ctypes.POINTER(ctypes.c_char_p)()#create ctypes pointer
length = ctypes.POINTER(ctypes.c_int)()#create ctypes int
#call function with the ctypes pointer and int as ref
dllfunc(ctypes.byref(unmanagedArray), ctypes.byref(length))
INTP = ctypes.POINTER(ctypes.c_int)#pointer to int
addr = ctypes.addressof(length)#memory address of int
arraylength = ctypes.cast(addr, INTP)[0]#cast the pointer to int to a python variable
for i in range(0,arraylength):
stringlist.append(ctypes.string_at(unmanagedArray[i]).decode(encoding='UTF-8'))#decode convert from bits to string
return arraylength
#send list to c# dll
stringlist =list()
arraylength = self.StringArray(Cdll.StringArrayExample, stringlist)
print(str(arraylength)+" "+str(stringlist[0])+" "+str(stringlist[1])+" "+str(stringlist[2]))