0

I have researched this topic and the closest answer I have found uses NuGet Package Manager. That example is found at this link. Calling a C# library from python

In that example, the C# code returns an integer. I want to return a string. It seems simple enough, but when I return a string, the result in Python is always integer. I have found other sites which talk about marshalling the result datatype, but I cannot see how to make this work.

Can someone post an example of the 'add' method from the above website where the return datatype is a string? I don't want examples which use IronPython or Python .Net. My question is about Python 2.7.x and C# only

Community
  • 1
  • 1
James
  • 1
  • 2

1 Answers1

0

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]))
D__
  • 1