Search code examples
c#c++marshallingdllimport

c# Marshal null-terminated string array


I am trying to import the following:

const char * const *object_get_prop_names(propobject_t *ocr);

as:

[DllImport("vender.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern IntPtr object_get_prop_names(int* osr);

based on: https://limbioliong.wordpress.com/2011/08/14/returning-an-array-of-strings-from-c-to-c-part-1/

I've tried the following:

var pNames = object_get_prop_names(hdl);

int StringCount = 200; //how do I know string count?

IntPtr[] pIntPtrArray = new IntPtr[StringCount];
ManagedStringArray = new string[StringCount];

Marshal.Copy(pNames, pIntPtrArray, 0, StringCount);

for (int i = 0; i < StringCount; i++)
{
    ManagedStringArray[i] = Marshal.PtrToStringAnsi(pIntPtrArray[i]);
    //Marshal.FreeCoTaskMem(pIntPtrArray[i]); crashes
}

//Marshal.FreeCoTaskMem(pUnmanagedStringArray); crashes

This works but I am guessing that I have memory leaks and accessing memory I shouldn't.

How should I free the memory?

How do I know the count? This is from a vendor and they will not modify the dll for little ol' me. :)

Also forgive me for delving into something I know very little about.


Solution

  • Following Hans' suggestions:

    var pNames = object_get_prop_names(hdl);
    if (h == IntPtr.Zero)
    {
        return null;
    }
    
    var nameList = new List<string>();
    int elementSize = Marshal.SizeOf(typeof(IntPtr));
    
    for (int i = 0; i < 200; i++) //don't know length, pick large number
    {
        var ptr = Marshal.ReadIntPtr(pNames, i * elementSize);
        var str = Marshal.PtrToStringAnsi(ptr);
        if (!string.IsNullOrWhiteSpace(str))
        {
            nameList.Add(str);
        }
        else //end of pNames
        { 
            break; 
        }
    }
    

    Works great. I have no way of knowing how many property names there are so I just have to pick a larger number than the possible number of property names.