Scenario
This should be an easy task, but for some reason I cannot achieve its goal. I have to create a basic C ++ struct during the P / Invoke callback (managed code of an unmanaged call).
The problem only occurs when using bool inside the structure, so I just trim the C ++ side to:
struct Foo { bool b; };
Since .NET marshals have 4 byte fields by default, by default I marshaled a boolean boolean value as a 1 byte field:
public struct Foo { [MarshalAs(UnmanagedType.I1)] public bool b; }
When I call the exported managed static method with the following signature and body:
public static void Bar(Foo foo) { Console.WriteLine("{0}", foo.b); }
I get the correct boolean alpha representation. If I expand the structure with a large number of fields, the alignment will be correct and the data will not be damaged after sorting.
Problem
For some reason, if I don't pass this marshalled struct as an argument, but rather as a return type by value:
public static Foo Bar() { var foo = new Foo { b = true }; return foo; }
The application crashes with the following error message:

If I change the managed structure by holding byte instead of bool
public struct Foo { [MarshalAs(UnmanagedType.I1)] public byte b; } public static Foo Bar() { var foo = new Foo { b = 1 }; return foo; }
the return value is sorted correctly without an unmanaged bool error.
I do not understand two things here:
- Why does the parameter mapped to
bool as described above work, but how does the return value give an error? - Why is
UnmanagedType.I1 handled as UnmanagedType.I1 to return, but the bool also associated with UnmanagedType.I1 does not work?
I hope my description makes sense - if not, let me know so that I can change the wording.
EDIT: My current workaround is a managed framework, for example:
public struct Foo { private byte b; public bool B { get { return b != 0; } set { b = value ? (byte)1 : (byte)0; } }
which honestly, I find it pretty funny ...
EDIT2: That's almost MCVE. The managed assembly was recompiled with proper export of characters (using the .export and .vtentry in the IL code), but there should be no difference with C ++ / CLI calls. Thus, this code does not work βas isβ without doing the export manually:
C ++ (native.dll):
#include <Windows.h> struct Foo { bool b; }; typedef void (__stdcall *Pt2PassFoo)(Foo foo); typedef Foo (__stdcall *Pt2GetFoo)(void); int main(int argc, char** argv) { HMODULE mod = LoadLibraryA("managed.dll"); Pt2PassFoo passFoo = (Pt2PassFoo)GetProcAddress(mod, "PassFoo"); Pt2GetFoo getFoo = (Pt2GetFoo)GetProcAddress(mod, "GetFoo"); // Try to pass foo (THIS WORKS) Foo f1; f1.b = true; passFoo(f1); // Try to get foo (THIS FAILS WITH ERROR ABOVE) // Note that the managed method is indeed called; the error // occurs upon return. If 'b' is not a 'bool' but an 'int' // it also works, so there must be something wrong with it // being 'bool'. Foo f2 = getFoo(); return 0; }
C # (managed.dll):
using System; using System.Runtime.InteropServices; public struct Foo { [MarshalAs(UnmanagedType.I1)] public bool b;