首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将非托管C++指针转换为托管C#对象

将非托管C++指针转换为托管C#对象
EN

Stack Overflow用户
提问于 2017-03-23 13:21:42
回答 1查看 1.9K关注 0票数 6

我有一个非托管静态库(.dll)写在C++上:

代码语言:javascript
复制
// 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‘将这个库导入到PInvoke projeс中,并调用'GetMyData’方法。

代码语言:javascript
复制
// 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#代码中就会出现异常:

变量ms = Marshal.PtrToStructure(ptr); 错误: System.Runtime.InteropServices.SafeArrayTypeMismatchException: “数组的运行时类型与元数据中记录的子类型之间发生了错误匹配。”

正如我所理解的'FieldOffset‘属性中的偏移参数--在将非托管C++对象转换为托管C#对象期间,非托管内存中的字节发生了变化。

字段'index‘有4个字节大小,因为它是32位类型。

字段'name‘是指向字符数组的指针。对于32位架构,它也是32位数(4字节)。

在“FieldOffset”属性中,我需要为“数据”字段使用哪些偏移量?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-03-23 13:33:08

你做起来不容易..。按照аn的建议手动执行或

代码语言:javascript
复制
[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位,因为结构将根据指针的大小展开。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42977306

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档