2

I would like to instantiate memory for a boolean array in C# and pass this to a C library function using interop. Then the C function should fill up the array with data (result) so that the data can passed back to C# and used there. Since arrays are reference types and since I explicitly set the [In, Out] marshalling attribute for the array I thought this would be a piece of cake. But apparantly not. :-( Below is some test code (as simple as I could get it) that illuminates the problem.

In C, here is what I will call:

extern "C" __declspec(dllexport) int __stdcall TestFillArray(bool *resultMaterials, int materialLength);


__declspec(dllexport) int __stdcall TestFillArray(bool *resultMaterials, int materialLength)
{
    resultMaterials[0] = true; 
    resultMaterials[1] = true; 
    return materialLength;
}

I call this function from C# using the following declaration:

[DllImport("FrontAuction2.dll", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern int TestFillArray([MarshalAs(UnmanagedType.LPArray, SizeConst = 2), In, Out] bool[] resultMaterial, int materialLength);

then within my C# test method I have:

var resultMaterials = new bool[2];
var res = TestFillArray(resultMaterials, 2);

When I check the result, I get res=2 and resultMaterials[0] = true, and resultMaterials[1] = false. I.e. the res value is correct as well as the first array element´, but not the second one. So it seems that the boolean data is not marshalled correctly (unless I am missing something obvious).

I am guessing it also would be possible to declare a IntPtr instead of an array and succesfully marshal the two elements to the correct result. However, since I want the array to be allocated in memory in C#, I am not sure how to do this.

Much obliged for help on this. I'm kind of stuck here. :(


UPDATE: I am guessing that it is due to that boolean is only 1 byte long and that the C# code does not get this information. So how do you specify this?

Toby999
  • 584
  • 1
  • 5
  • 14

1 Answers1

1

Using

[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1, SizeConst = 2), In, Out]

should tell the framework to mashal the array as an array of 1-byte bools. Another option would be to use the 4-byte BOOL instead. For more information see UnmanagedType enum.

svick
  • 236,525
  • 50
  • 385
  • 514
  • Thanks a lot! That worked. I tested with ArraySubType = UnmanagedType.Bool which did not work. But I missed that .NET bool type is 4 bytes and not 1. – Toby999 Jul 06 '11 at 16:07
  • @Tobias, I think it's not because .Net `bool` is 4 bytes, but because Win32 `BOOL` is 4 bytes. See the documentation I linked to. – svick Jul 06 '11 at 16:11
  • Well, boolean types seems to be a hell hole of different definitions and I still have (another) problem dealing with booleans. I will post it soon as a different question. From my reading though it seems like the .NET Boolean struct type is 4 bytes, but recollect having seen statement that C# bool is only 1 byte. I think this is wrong though and that it is 4 bytes to map correctly to the Boolean struct type. Would you agree? In my example I am using a C bool which apparantly is 1 byte which I guess is why your response works so good. – Toby999 Jul 07 '11 at 13:15
  • Well, neither the C# specification for `bool` nor the MSDN documentation for `System.Boolean` specify the size, so, theoretically, it would be possible that you created a struct with 8 `bool` fields and that struct would only take one byte. In the actual implementation of .Net, the boolean type itself takes just one byte, but can often be padded for more efficient copying to full 4 bytes (or 8, on 64-bit framework). See [this question](http://stackoverflow.com/questions/294905/why-in-net-system-boolean-takes-4-byte). – svick Jul 07 '11 at 19:45