views:

138

answers:

3

Ok, I'm now very confused. After my last question had several people comment about changing bool to uint I verified they are the same size by:

    Console.WriteLine("sizeof bool = {0}", Marshal.SizeOf(typeof(bool)));
    Console.WriteLine("sizeof uint = {0}", Marshal.SizeOf(typeof(uint)));

Which of course prints:

sizeof bool = 4
sizeof uint = 4

That said, I then broke down and gave their suggestions a try anyway... Changing a single bool inside a structure to a uint. What I can't figure out for the life of me is why this made it work...

So this works:

[StructLayout(LayoutKind.Sequential)]
public struct KEY_EVENT_RECORD
{
    public bool bKeyDown;
    public short wRepeatCount;
    public short wVirtualKeyCode;
    public short wVirtualScanCode;
    public char UnicodeChar;
    public int dwControlKeyState;
}

When used in this structure:

[StructLayout(LayoutKind.Explicit)]
public struct INPUT_RECORD
{
    [FieldOffset(0)] public short EventType;
    [FieldOffset(4)] public KEY_EVENT_RECORD KeyEvent;
}

But in this structure it breaks:

[StructLayout(LayoutKind.Explicit)]
public struct INPUT_RECORD
{
    [FieldOffset(0)] public short EventType;
    [FieldOffset(4)] public KEY_EVENT_RECORD KeyEvent;
    [FieldOffset(4)] public MOUSE_EVENT_RECORD MouseEvent;
    [FieldOffset(4)] public WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
    [FieldOffset(4)] public MENU_EVENT_RECORD MenuEvent;
    [FieldOffset(4)] public FOCUS_EVENT_RECORD FocusEvent;
}

Yet when I change bool bKeyDown to uint in the KEY_EVENT_RECORD structure it starts working again...

Can someone please explain this behavior?

I really would like to know the why of it so that I can avoid this undocumented feature (aka bug) in the future.

+1  A: 

Try setting the field type to bool and add the attribute [MarshalAs(UnmanagedType.Bool)].

[StructLayout(LayoutKind.Sequential)]
public struct KEY_EVENT_RECORD
{
    [MarshalAs(UnmanagedType.Bool)]
    public bool bKeyDown;
    public short wRepeatCount;
    public short wVirtualKeyCode;
    public short wVirtualScanCode;
    public char UnicodeChar;
    public int dwControlKeyState;
}

Docs for MarshalAsAttribute Docs for UnmanagedType

Jason
I would hope that UnmanagedType.Bool would be the default marshal type for bool... but I've been wrong before. I tried it anyway and it still fails. I also tried UnmanagedType.I4 and UnmanagedType.U4 and both of them refuse to allow this decoration on a bool type.
csharptest.net
A: 

bools are 1byte --> sizeof (C# Reference)

Also, see Default Marshaling for Boolean Types

hjb417
The MarshalAs attribute does not apply to what you're trying to do. For P/Invoke you use the MarshalAs attribute inline.E.x.:[DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]public static extern IntPtr GetStdHandle([MarshalAs(UnmanagedType.U4)] int nStdHandle);
hjb417
Yes I know a bool is represented in C# as a single byte; however, it is always marshalled by default as a 4-byte int. Thus the question, why does changing bool to uint make a difference?
csharptest.net
I think this is platform dependent. E.x.: It will Marshal.SizeOf will return 4 on a desktop and 1 on a pocket pc.Look at Rudedog2's post @ http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/f69da088-5be9-4665-878b-3f6efe3b855b
hjb417