本文介绍了为什么 DllImport for C bool as UnmanagedType.I1 会抛出但作为字节它可以工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

typedef struct {
    bool bool_value;
} BoolContainer;

BoolContainer create_bool_container (bool bool_value)
{
    return (BoolContainer) { bool_value };
}

这是我的 P/Invoke 包装器

public partial class NativeMethods
{
    [DllImport(LibraryName, CallingConvention = CallingConvention.Cdecl)]
    public static extern BoolContainer create_bool_container([MarshalAs(UnmanagedType.I1)] bool bool_value);
}

这里是 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;
}

第二个工作:

public struct BoolContainer // Marshal.SizeOf(typeof(BoolContainer)) = 1
{
    public byte bool_value;
}

测试代码:

BoolContainer boolContainer = NativeMethods.create_bool_container(true);

似乎 DllImport 忽略了返回结构中任何布尔成员的 MarshalAs.有没有办法将 bool 保留在托管声明中?

Is seems like DllImport ignores MarshalAs for any boolean members in the returned structure. Is there a way to keep bool in the managed declaration?

推荐答案

作为返回类型的结构在互操作中非常困难,它们不适合 CPU 寄存器.这是由调用者在其堆栈帧上为返回值保留空间并将指针传递给被调用者在本机代码中处理的.然后通过指针复制返回值.一般来说,一个相当麻烦的特性是,不同的 C 编译器有不同的策略来传递该指针.pinvoke marshaller 假定 MSVC 行为.

Structs as return types are pretty difficult in interop, they don't fit a CPU register. This is handled in native code by the caller reserving space on its stack frame for the return value and passing a pointer to the callee. Which then copies the return value through the pointer. In general a pretty troublesome feature, different C compilers have different strategies to pass that pointer. The pinvoke marshaller assumes MSVC behavior.

这是非blittable结构的问题,换句话说,当它的布局不再与本机代码所需的非托管结构完全匹配时.这需要一个额外的步骤来将非托管结构转换为托管结构,相当于 Marshal.PtrToStructure().例如,如果您将字符串字段添加到结构中,您会看到这一点.由于必须将 C 字符串转换为 System.String,这使得它不可 blittable,您将得到完全相同的异常.

This is a problem with structs that are not blittable, in other words when its layout is no longer an exact match with the unmanaged struct that the native code needs. That requires an extra step to convert the unmanaged struct to the managed struct, the equivalent of Marshal.PtrToStructure(). You see this for example if you add a string field to your struct. That makes it non-blittable since the C string has to be converted to a System.String, you'll get the exact same exception.

在您的情况下,类似的问题,bool 也是一种非常难以互操作的类型.由于 C 语言没有类型,并且后来添加了高度不兼容的选择.它在 C++ 和 CLR 中是 1 个字节,在 COM 中是 2 个字节,在 C 和 winapi 中是 4 个字节.pinvoke marshaller 选择 winapi 版本作为默认值,使其匹配 BOOL,这是 pinvoke 的最常见原因.这迫使您添加 [MarshalAs] 属性,这也需要额外的工作,同样需要通过 Marshal.PtrToStructure() 的等价物来完成.

A similar kind of problem in your case, bool is also a very difficult type to interop with. Caused by the C language not having the type and it getting added later with highly incompatible choices. It is 1 byte in C++ and the CLR, 2 bytes in COM, 4 bytes in C and the winapi. The pinvoke marshaller picked the winapi version as the default, making it match BOOL, the most common reason to pinvoke. This forced you to add the [MarshalAs] attribute and that also requires extra work, again to be done by the equivalent of Marshal.PtrToStructure().

所以 pinvoke 编组器缺少的是对这个额外步骤的支持,即调用后返回值的自定义编组.不确定这是设计约束还是资源约束.可能两者兼而有之,非 blittable 结构成员的所有权在非托管语言中是完全未指定的,并且猜测它,尤其是作为返回值,很少会得到很好的结果.因此,他们很可能认为开发该功能不值得成功的可能性很小.这当然是猜测.

So what the pinvoke marshaller is missing is the support for this extra step, custom marshaling of the return value after the call. Not sure if this was a design constraint or a resource constraint. Probably both, ownership of non-blittable struct members is completely unspecified in unmanaged languages and guessing at it, especially as a return value, very rarely turns out well. So they may well have made the call that working on the feature just wasn't worth the low odds of success. This is a guess of course.

使用 byte 是一个很好的解决方法.

Using byte instead is a fine workaround.

这篇关于为什么 DllImport for C bool as UnmanagedType.I1 会抛出但作为字节它可以工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

05-28 11:37
查看更多