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

时间:2011-07-07 14:15:10

标签: c# c struct pinvoke 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;
}

我使用以下定义在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);

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

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

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

1 个答案:

答案 0 :(得分: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;
};

在C#中声明函数,如下所示:

public static extern void TestGetBackStruct(TestStruct[] structs);

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

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

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