Note that there are some explanatory texts on larger screens.

plurals
  1. POBoolean Marshalling with LayoutKind.Explicit, Is this broken or failing as designed?
    primarykey
    data
    text
    <p>First of all the Boolean type is said to have a default marshal type of a four-byte value. So the following code works:</p> <pre><code> struct A { public bool bValue1; public int iValue2; } struct B { public int iValue1; public bool bValue2; } public static void Main() { int[] rawvalues = new int[] { 2, 4 }; A a = (A)Marshal.PtrToStructure(GCHandle.Alloc(rawvalues, GCHandleType.Pinned).AddrOfPinnedObject(), typeof(A)); Assert.IsTrue(a.bValue1 == true); Assert.IsTrue(a.iValue2 == 4); B b = (B)Marshal.PtrToStructure(GCHandle.Alloc(rawvalues, GCHandleType.Pinned).AddrOfPinnedObject(), typeof(B)); Assert.IsTrue(b.iValue1 == 2); Assert.IsTrue(b.bValue2 == true); } </code></pre> <p>Clearly these structures marshal independently just fine. The values are translated as expected. However, when we combine these structures into a "union" by declaring LayoutKind.Explicit like this:</p> <pre><code> [StructLayout(LayoutKind.Explicit)] struct Broken { [FieldOffset(0)] public A a; [FieldOffset(0)] public B b; } </code></pre> <p>We suddenly find ourselves unable to correctly marshal these types. Here is the test code for the above structure and how it fails:</p> <pre><code> int[] rawvalues = new int[] { 2, 4 }; Broken broken = (Broken)Marshal.PtrToStructure(GCHandle.Alloc(rawvalues, GCHandleType.Pinned).AddrOfPinnedObject(), typeof(Broken)); Assert.IsTrue(broken.a.bValue1 != false);// pass, not false Assert.IsTrue(broken.a.bValue1 == true);// pass, must be true? Assert.IsTrue(true.Equals(broken.a.bValue1));// FAILS, WOW, WTF? Assert.IsTrue(broken.a.iValue2 == 4);// FAILS, a.iValue1 == 1, What happened to 4? Assert.IsTrue(broken.b.iValue1 == 2);// pass Assert.IsTrue(broken.b.bValue2 == true);// pass </code></pre> <p>It's very humorous to see this express as true: (a.bValue1 != false &amp;&amp; a.bValue1 == true &amp;&amp; !true.Equals(a.bValue1))</p> <p>Of course the bigger problem here is that a.iValue2 != 4, rather the 4 has been changed to 1 (presumably by the overlapped bool). </p> <p><strong>So the question: Is this a bug, or just failed as designed?</strong></p> <p>Background: this came from <a href="https://stackoverflow.com/questions/1602899"> <a href="https://stackoverflow.com/questions/1602899">What is the difference between structures containing bool vs uint when using PInvoke?</a></a></p> <p>Update: This is even stranger when you use large integer values (> 255) as only the byte that is used for the boolean is being modified to a 1, thus changing 0x0f00 to 0x0f01 for the b.bValue2. For a.bValue1 above it's not translated at all and 0x0f00 provides a false value for a.bValue1.</p> <p>Update #2:</p> <p>The most obvious and reasonable solution to the above issue(s) is to use a uint for the marshalling and expose boolean properties instead. Really solving the issue with a 'workaround' is not at question. I'm mostly wondering is this a bug or is this the behavior you would expect?</p> <pre><code> struct A { private uint _bValue1; public bool bValue1 { get { return _bValue1 != 0; } } public int iValue2; } struct B { public int iValue1; private uint _bValue2; public bool bValue2 { get { return _bValue2 != 0; } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload