簡體   English   中英

將非托管C ++指針轉換為對象到托管C#對象

[英]Convert unmanaged C++ pointer to an object to a managed C# object

我有一個用C ++編寫的非托管靜態庫(.dll):

// This is a personal academic project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include "program.h"

struct MyData
{
    int32_t index;
    char* name;
    //uint8_t* data;
};

extern "C" {
    __declspec(dllexport) MyData* GetMyData()
    {
        MyData* ms = new MyData();
        ms->index = 5;
        ms->name = "Happy string";
        //ms->data = new uint8_t[5] { 4, 8, 16, 32, 64 };
        return ms;
    }
}

'GetMyData'方法返回指向'MyData'對象的指針。

我使用'PInvoke'將此庫導入C#projeсt並調用'GetMyData'方法。

// This is a personal academic project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Explicit)]
public class MyData
{
    [FieldOffset(0)]
    public Int32 index;

    [FieldOffset(4)]
    public String name;

    //[FieldOffset(8)]
    //public Byte[] data;
};

class Program
{
    [DllImport("TestCpp.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern IntPtr GetMyData();

    public static void Main(string[] args)
    {
        // Call 'GetMyData' method and get structure from pointer using marshaling.
        var ptr = GetMyData();
        var ms = Marshal.PtrToStructure<MyData>(ptr);

        // Print my data into console
        var str = ms.index.ToString();
        str += ", " + ms.name;
        //str += ", [" + string.Join(", ", ms.data) + "]";
        Console.WriteLine(str);
        Console.ReadKey();
    }
}

這段代碼工作正常,但是如果我取消注釋使用'MyData'類型的'data'成員(在C ++和C#代碼中),我將在此行的C#代碼中獲得異常:

var ms = Marshal.PtrToStructure(ptr);

錯誤:System.Runtime.InteropServices.SafeArrayTypeMismatchException:
'數組的運行時類型與元數據中記錄的子類型之間發生了不匹配。

據我所知,'FieldOffset'屬性中的偏移量參數 - 在非托管C ++對象轉換為托管C#對象期間,它是非托管內存中的字節變化。

字段'索引'有4個字節大小,因為它是32位類型。

字段'name'是char數組的指針。 對於32位架構,它也是32位數(4字節)。

我需要在“數據”字段中使用“FieldOffset”屬性中的哪個偏移量?

你不能輕易做到......正如Ðannn手動或做的那樣

[FieldOffset(8)]
public IntPtr _data;

public byte[] GetData()
{
    // YOU MUST FREE _data C-side! You can't use
    // C++ delete C#-side
    var bytes = new byte[5];
    Marshal.Copy(_data, bytes, 0, bytes.Length);
    return bytes;
}

這里還有另一個(小)問題:我反對使用LayoutKind.Explicit除非你確實需要它。 LayoutKind.Sequential開始,看看它是否足夠。 使用LayoutKind.Sequential您將更准備從32位切換到64位,因為結構將根據指針的大小進行拉伸。

暫無
暫無

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

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