rgr*_*per 4 c c# pinvoke boolean visual-studio-2013
typedef struct {
bool bool_value;
} BoolContainer;
BoolContainer create_bool_container (bool bool_value)
{
return (BoolContainer) { bool_value };
}
Run Code Online (Sandbox Code Playgroud)
public partial class NativeMethods
{
[DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
public static extern BoolContainer create_bool_container([MarshalAs(UnmanagedType.I1)] bool bool_value);
}
Run Code Online (Sandbox Code Playgroud)
BoolContainer:首先是投掷MarshalDirectiveException: Method's type signature is not PInvoke compatible.:
public struct BoolContainer // Marshal.SizeOf(typeof(BoolContainer)) = 1
{
[MarshalAs(UnmanagedType.I1)] // same with UnmanagedType.U1
public bool bool_value;
}
Run Code Online (Sandbox Code Playgroud)
第二是工作:
public struct BoolContainer // Marshal.SizeOf(typeof(BoolContainer)) = 1
{
public byte bool_value;
}
Run Code Online (Sandbox Code Playgroud)
测试代码:
BoolContainer boolContainer = NativeMethods.create_bool_container(true);
Run Code Online (Sandbox Code Playgroud)
似乎DllImport忽略MarshalAs了返回结构中的任何布尔成员.有没有办法保留bool托管声明?
作为返回类型的结构在互操作中非常困难,它们不适合CPU寄存器.这是由本地代码处理的,调用者在其堆栈帧上为返回值保留空间并将指针传递给被调用者.然后通过指针复制返回值.通常一个非常麻烦的功能,不同的C编译器有不同的策略来传递该指针.pinvoke marshaller假设MSVC行为.
这是一个问题,结构不是blittable,换句话说,当它的布局不再与本机代码所需的非托管结构完全匹配时.这需要额外的步骤将非托管结构转换为托管结构,相当于Marshal.PtrToStructure().例如,如果向结构中添加字符串字段,则会看到此情况.这使得它不闪烁,因为必须将C字符串转换为System.String,您将得到完全相同的异常.
在你的情况下类似的问题,布尔也是一个非常难以互操作的类型.由C语言引起的没有类型,后来添加了高度不兼容的选择.它是C++和CLR中的1个字节,COM中的2个字节,C中的4个字节和winapi.pinvoke marshaller选择了winapi版本作为默认版本,使其与BOOL相匹配,BOOL是pinvoke最常见的原因.这迫使你添加[MarshalAs]属性,这也需要额外的工作,再次由Marshal.PtrToStructure()完成.
所以pinvoke marshaller缺少的是对这个额外步骤的支持,即调用后返回值的自定义编组.不确定这是设计约束还是资源约束.可能两者都是,非blittable结构成员的所有权在非托管语言中完全没有指定并且猜测它,特别是作为返回值,很少结果很好.所以他们很可能已经打电话说这个功能的工作并不值得成功的可能性很小.这当然是猜测.
使用byte代替是一个很好的解决方法.