C# 为什么C bool的DllImport作为UnmanagedType.I1抛出,但作为字节有效 这里是一个简单的C代码(VS 2013 C++项目,“编译为C”): 这是我的P/Invoke包装器 以下是BoolContainer的托管版本:
首先是抛出C# 为什么C bool的DllImport作为UnmanagedType.I1抛出,但作为字节有效 这里是一个简单的C代码(VS 2013 C++项目,“编译为C”): 这是我的P/Invoke包装器 以下是BoolContainer的托管版本:,c#,c,boolean,pinvoke,visual-studio-2013,C#,C,Boolean,Pinvoke,Visual Studio 2013,首先是抛出MarshalDirectiveException:方法的类型签名与PInvoke不兼容。: public struct BoolContainer // Marshal.SizeOf(typeof(BoolContainer)) = 1 { [MarshalAs(UnmanagedType.I1)] // same with UnmanagedType.U1 public bool bool_value; } 第二是工作: public struct BoolCon
MarshalDirectiveException:方法的类型签名与PInvoke不兼容。
:
public struct BoolContainer // Marshal.SizeOf(typeof(BoolContainer)) = 1
{
[MarshalAs(UnmanagedType.I1)] // same with UnmanagedType.U1
public bool bool_value;
}
第二是工作:
public struct BoolContainer // Marshal.SizeOf(typeof(BoolContainer)) = 1
{
public byte bool_value;
}
测试代码:
BoolContainer boolContainer = NativeMethods.create_bool_container(true);
对于返回的结构中的任何布尔成员,Is看起来像是
DllImport
忽略marshallas
。有没有办法在托管声明中保留bool
?结构因为返回类型在互操作中非常困难,它们不适合CPU寄存器。调用方在其堆栈帧上为返回值保留空间,并向被调用方传递指针,从而在本机代码中处理此问题。然后通过指针复制返回值。一般来说,这是一个相当麻烦的特性,不同的C编译器有不同的策略来传递该指针。pinvoke marshaller采用MSVC行为
这是不可blittable的结构的问题,换句话说,当其布局不再与本机代码所需的非托管结构完全匹配时。这需要额外的步骤将非托管结构转换为托管结构,相当于Marshal.PtrToStructure()。例如,如果将字符串字段添加到结构中,就会看到这一点。由于C字符串必须转换为System.string,因此它不可blittable,您将得到完全相同的异常
在您的案例中,bool也是一个类似的问题,它也是一种很难进行互操作的类型。这是由于C语言没有该类型,并且后来添加了高度不兼容的选项。它是1字节的C++和CLR,2字节的COM,4字节的C和WiLAPI。pinvoke封送员选择winapi版本作为默认版本,使其与pinvoke最常见的原因BOOL匹配。这迫使您添加[MarshalAs]属性,这也需要额外的工作,同样需要等效的Marshal.PtrToStructure()来完成
因此,pinvoke封送器缺少的是对这个额外步骤的支持,即调用后返回值的自定义封送。不确定这是设计约束还是资源约束。可能两者都有,在非托管语言中,不可blittable结构成员的所有权是完全未指定的,猜测它,特别是作为返回值,结果很少是好的。因此,他们很可能已经发出了这样的呼吁:开发该功能不值得这么低的成功几率。这当然是一个猜测
使用byte是一个很好的解决方法。将结构作为函数返回值返回充其量是有风险的。不同的编译器有不同的方法来实现这一点。似乎您根本无法将结构中的
bool
封送为函数返回值。如果p/invoke确实有文档记录,那么我们就能够找出原因。我怀疑函数的out
参数是前进的方向。感谢您为我指出这个答案!因此,只有在通过值将内容传递到非托管函数的情况下才能使用marshallas
(在不安全的上下文中通过指针传递也有同样的问题)?创建托管指针还需要可blittable结构。当您将结构作为参数传递时,很少会出现实际问题,您会在参数上生成一个带有ref关键字的非托管指针。
public struct BoolContainer // Marshal.SizeOf(typeof(BoolContainer)) = 1
{
public byte bool_value;
}
BoolContainer boolContainer = NativeMethods.create_bool_container(true);