一些P/Invoke C#到C编组问题在结构中使用布尔值

Tob*_*999 2 c c# pinvoke struct boolean

我在使用布尔类型时遇到了一些问题,并在C#和C之间在结构中来回编组.我在C中非常生疏,但希望在那部分没有任何重大错误.

据我所知,.NET Boolean和C#bool类型4个字节,而C类型bool只有1个字节.出于内存占用的原因,我没有在C代码中使用定义的BOOL 4字节版本.

这是一些简单的测试代码,希望能够清楚地表达我的问题:


C代码:

typedef struct
{
        double SomeDouble1;
        double SomeDouble2;
        int SomeInteger;
        bool SomeBool1;
        bool SomeBool2;
} TestStruct;

extern "C" __declspec(dllexport) TestStruct* __stdcall TestGetBackStruct(TestStruct* structs);

__declspec(dllexport) TestStruct* __stdcall TestGetBackStruct(TestStruct* structs)
{
    return structs;
}
Run Code Online (Sandbox Code Playgroud)

我使用以下定义在C#中调用此代码:

    [StructLayout(LayoutKind.Explicit)]
    public struct TestStruct
    {
        [FieldOffset(0)]
        public double SomeDouble1;
        [FieldOffset(8)]
        public double SomeDouble2;

        [FieldOffset(16)]
        public int SomeInteger;

        [FieldOffset(17), MarshalAs(UnmanagedType.I1)]
        public bool SomeBool1;
        [FieldOffset(18), MarshalAs(UnmanagedType.I1)]
        public bool SomeBool2;
    };

    [DllImport("Front.dll", CharSet = CharSet.Auto, SetLastError = true, CallingConvention = CallingConvention.StdCall)]
    public static extern IntPtr TestGetBackStruct([MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] TestStruct[] structs);
Run Code Online (Sandbox Code Playgroud)

这是C#中的实际测试函数:

    [Test]
    public void Test_CheckStructParsing()
    {
        var theStruct = new TestStruct();
        theStruct.SomeDouble1 = 1.1;
        theStruct.SomeDouble2 = 1.2;
        theStruct.SomeInteger = 1;
        theStruct.SomeBool1 = true;
        theStruct.SomeBool2 = false;

        var structs = new TestStruct[] { theStruct };

        IntPtr ptr = TestGetBackStruct(structs);

        var resultStruct = (TestStruct)Marshal.PtrToStructure(ptr, typeof(TestStruct));
    }
Run Code Online (Sandbox Code Playgroud)

这是因为我确实得到了一个结构(使用调试器来检查它),但是使用了完全错误的值.即编组不起作用.我尝试过不同版本的C#struct而没有成功.所以这是我的问题(1和2最重要):

  1. C功能是否正确用于此目的?
  2. 如何正确编写结构以便将结构中的正确值返回给C#?(甚至有必要使用FieldOffset值使用StructLayout(LayoutKind.Explicit)属性定义结构,还是可以使用StructLayout(LayoutKind.Sequential))?
  3. 由于我在C中返回指向TestStruct的指针,我想应该可以在C#中返回一个TestStructs数组.但是使用Marshal.PtrToStructure函数似乎不可能.是否有可能以其他方式?
  4. 显然,通过使用相同的FieldOffset属性值使多个结构字段指向相同的内存分配,可以在C中使用称为联合的东西.我理解这一点,但是当这种情况有用时我还没有得到.请赐教.
  5. 有人可以推荐一本关于C#P/Invoke to C/C++的好书吗? 我有点厌倦了在网络上随处获取信息.

很有必要帮助解决这些问题.我希望他们不是太多.

Dav*_*nan 6

停止使用LayoutKind.Explicit并删除FieldOffset属性,您的代码将起作用.您的偏移量没有正确对齐字段.

public struct TestStruct
{
    public double SomeDouble1;
    public double SomeDouble2;
    public int SomeInteger;
    [MarshalAs(UnmanagedType.I1)]
    public bool SomeBool1;
    [MarshalAs(UnmanagedType.I1)]
    public bool SomeBool2;
};
Run Code Online (Sandbox Code Playgroud)

在C#中声明函数如下:

public static extern void TestGetBackStruct(TestStruct[] structs);
Run Code Online (Sandbox Code Playgroud)

默认编组将匹配您的C++声明(您的代码实际上是C++而不是C)但您必须确保TestStruct[]在调用函数之前在C#代码中分配参数.通常,您还会将数组的长度作为参数传递,以便C++代码知道有多少个结构.

请不要尝试从函数返回结构数组.将structs参数用作输入/输出参数.

我知道没有一本强调P/Invoke的书.它似乎是一种黑色艺术!