P/Invoke from C to C# without knowing size of arra

2019-05-22 18:17发布

问题:

Right know in my code I have structure declared as like this, with fixed this 16, know at compile time.

struct CONSOLE_SCREEN_BUFFER_INFOEX
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public int ColorTable[];
}

but what I need is to be able to have this structure:

struct CONSOLE_SCREEN_BUFFER_INFOEX
{
   int arraySize;
   [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0)]
   public int ColorTable[];
}

get the arraySize from C function response, initialize ColorTable array with proper size, put result of response into ColorTable.

Not sure if it's possible, just doing investigation right now, and any comments are very welcome.

回答1:

You can do this easily enough with some manual marshalling using the Marshal class. For example:

[DllImport(@"MyLib.dll")]
private static extern void Foo(IntPtr structPtr);

private static IntPtr StructPtrFromColorTable(int[] colorTable)
{
    int size = sizeof(int) + colorTable.Length*sizeof(int);
    IntPtr structPtr = Marshal.AllocHGlobal(size);
    Marshal.WriteInt32(structPtr, colorTable.Length);
    Marshal.Copy(colorTable, 0, structPtr + sizeof(int), colorTable.Length);
    return structPtr;
}

private static int[] ColorTableFromStructPtr(IntPtr structPtr)
{
    int len = Marshal.ReadInt32(structPtr);
    int[] result = new int[len];
    Marshal.Copy(structPtr + sizeof(int), result, 0, len);
    return result;
}

static void Main(string[] args)
{
    int[] colorTable = new int[] { 1, 2, 3 };
    IntPtr structPtr = StructPtrFromColorTable(colorTable);
    try
    {
        Foo(structPtr);
        colorTable = ColorTableFromStructPtr(structPtr);
    }
    finally
    {
        Marshal.FreeHGlobal(structPtr);
    }
}