Export char*[] to C#

Viewed 90

I have a structure in C++ that contains char*[]

struct Adapters {
    int iAdapterIndex[6];
    int iBusNumber[6];
    int iDeviceNumber[6];
    char *iAdapterName[6];
    char *iDisplayName[6];
};

extern "C"
{
    __declspec(dllexport) int GET_ADAPTERS_INFO(Adapters* send)
        {    
                .........       

                for (int i = 0; i < 6; i++)
                {
                    if (lpAdapterInfo[i].iBusNumber > -1)
                    {
                        send->iAdapterIndex[i] = lpAdapterInfo[i].iAdapterIndex;
                        send->iBusNumber[i] = lpAdapterInfo[i].iBusNumber;
                        send->iDeviceNumber[i] = lpAdapterInfo[i].iDeviceNumber;
                        send->iAdapterName[i] = lpAdapterInfo[i].strAdapterName;
                        send->iDisplayName[i] = lpAdapterInfo[i].strDisplayName;
                    }
                }        
            return 0;
        }
}

I call a function that passes this structure to C#

[StructLayout(LayoutKind.Sequential)]
public struct Adapters
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public int[] iAdapterIndex;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public int[] iBusNumber;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public int[] iDeviceNumber;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public char[] iAdapterName;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public char[] iDisplayName;
};

[DllImport("Example.dll", EntryPoint = "GET_ADAPTERS_INFO", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
        public static extern int GET_ADAPTERS_INFO(out Adapters adapters);

But in the end I get garbage in arrays with char*. I have tried different UnmanagedType but no success. What to do?

UPD 1 :

[StructLayout(LayoutKind.Sequential)]
public struct Adapters
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public int[] iAdapterIndex;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public int[] iBusNumber;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public int[] iDeviceNumber;
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPTStr, SizeConst = 6)]
    public string[] iAdapterName;
    [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.LPTStr, SizeConst = 6)]
    public string[] iDisplayName;
};

it will cause the application to crash

1 Answers

Your C struct contains arrays of char pointers. An array of char pointers is not an array of chars.

However, your C# struct declares char arrays.

So, the "garbage" you are seeing in your C# struct char arrays are actually the bytes that make up the pointer values in the C struct char pointer arrays being interpreted as char values by the marshaller.

I am not entirely certain about what you are supposed to do. However, note the following: In C, which is lacking a native string type, char pointers are typically used to handle strings. You can think of an array of char pointers as an array of strings. (iAdapterName and iDisplayName can be thought of as an array of six strings.)

Therefore, i tend to suggest your C# struct should define string arrays and not char arrays. (Not sure if you would need to explicitly specify UnmanagedType.LPTStr or alike for the ArraySubType field of the MarshalAs attribute, though.)

Related