2

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.

inside
  • 3,047
  • 10
  • 49
  • 75
  • It is not the proper way to declare that field, it should be done with [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] public int[] ColorTable. Which gives you more rope, but not enough to make it depend on the *Size* field. You'll need to write a custom marshaller. – Hans Passant Aug 28 '13 at 14:49
  • Hey Hans, you are right, this is exactly how I am doing it right now: [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)], I just made it similar to Jon's code to avoid confusion. But now the request is to have it as [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0)] and then change size, when size is known, custom marshaller is exactly what I am interesting in, I just never touched this before, so need to know where to start – inside Aug 28 '13 at 14:52
  • This question would be better with a bespoke example. All those extra fields are superfluous for the discussion. Hans is correct that there's no need for `unsafe` here. Jon presumably just picked on this as a way to illustrate `fixed`. But `ByValArray` is the right approach. You could use a custom marshaller. Or you could do it with `IntPtr`, `Marshal.AllocHGlobal`, `Marshal.PtrToStructure` and `Marshal.Copy`. – David Heffernan Aug 28 '13 at 15:14
  • 1
    Your ultimate mistake is basing your question on a really bad example. Ask the proper one, show what you *really* need to interop with. – Hans Passant Aug 28 '13 at 15:19
  • I've answered a series of this kind of questions, maybe start from [this](http://stackoverflow.com/questions/15197195/how-to-pass-structure-as-pointer-in-c-dll-from-c-sharp/15197411#15197411) would get you helped .. – Ken Kin Aug 28 '13 at 15:24
  • 1
    edited, my question for it to be more related to my real situation. – inside Aug 28 '13 at 15:27

1 Answers1

3

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);
    }
}
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • @Stanislav You might be interested in this question: http://stackoverflow.com/questions/18498452/how-do-i-write-a-custom-marshaler-which-allows-data-to-flow-from-native-to-manag?lq=1 – David Heffernan Aug 28 '13 at 21:25