Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/270.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么C bool的DllImport作为UnmanagedType.I1抛出,但作为字节有效 这里是一个简单的C代码(VS 2013 C++项目,“编译为C”): 这是我的P/Invoke包装器 以下是BoolContainer的托管版本:_C#_C_Boolean_Pinvoke_Visual Studio 2013 - Fatal编程技术网

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);