簡體   English   中英

一些 P/Invoke C# 到 C 編組問題與結構中的布爾值一起使用

[英]Some P/Invoke C# to C marshalling questions working with booleans in structs

我在使用 boolean 類型並在 C# 和 C 之間來回編組時遇到了一些問題。 我在 C 中非常生疏,但希望這部分沒有嚴重錯誤。

As far as I've read/seen, .NET Boolean and C# bool type is 4 bytes long whilst the C type bool is only 1 byte . 由於 memory 占用空間的原因,我不使用 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#中的實際測試function:

    [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# 結構,但沒有成功。 所以這是我的問題(1和2最重要):

  1. C function 是否適用於此目的?
  2. 如何正確編寫結構以便讓我將結構中的正確值返回到 C#? (是否甚至需要使用 FieldOffset 值定義具有 StructLayout(LayoutKind.Explicit) 屬性的結構,或者我可以使用 StructLayout(LayoutKind.Sequential) 代替)?
  3. 由於我在 C 返回指向 TestStruct 的指針,我想應該可以在 C# 中取回 TestStructs 數組 但這似乎不可能使用 Marshal.PtrToStructure function。 是否可以通過其他方式實現?
  4. 顯然,通過使用相同的 FieldOffset 屬性值讓多個結構字段指向相同的 memory 分配,可以在 C 中使用稱為聯合的東西。 我理解這一點,但我仍然不知道這種情況何時有用 請賜教。
  5. 有人可以推薦一本關於 C# P/Invoke to C/C++ 的好書嗎? 我有點厭倦了在 web 上到處獲取信息。

非常有義務幫助解決這些問題。 我希望他們不要太多。

停止使用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# 中聲明 function :

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

The default marshalling will match your C++ declaration (your code is C++ rather than C in fact) but you must make sure that your allocate the TestStruct[] parameter in the C# code before calling the function. 通常,您還將數組的長度作為參數傳遞,以便 C++ 代碼知道有多少結構。

請不要嘗試從 function 返回結構數組。 使用structs參數作為輸入/輸出參數。

我知道沒有一本書強調 P/Invoke。 這似乎是一種黑色藝術!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM