将 struct* 从 c# 传递到 c++ dll

Posted

技术标签:

【中文标题】将 struct* 从 c# 传递到 c++ dll【英文标题】:Pass struct* from c# to c++ dll 【发布时间】:2017-12-21 08:55:53 【问题描述】:

c++ dll中的struct是这样定义的:

struct WAVE_INFO 
    int channel_num;
    int audio_type;
    char *wave_data;
    int wave_length;
;

而调用方法是这样的:

extern "C" STRUCTDLL_API int processStruct(WAVE_INFO *pIn, WAVE_INFO *pOut);

我的 c# 结构中的 wave_data 必须是 字节数组 (byte[])****,而不是 char[] 或字符串。我应该如何在调用 dll 的 c# 中定义结构和方法?而且wave_date的长度是固定的,比如100。

【问题讨论】:

如何知道wave_data的长度。长度必须在实际数据之前,因此 wave_data 和 wave_length 应该颠倒。 数据的长度是固定的,比如100。 @jdweng 为什么结构中的长度字段应该在数据字段之前。这只是决定结构的布局。程序可以按照它喜欢的任何顺序访问这些字段。 结构体的大小必须根据结构体内部的数据来计算。所以你总是把数组的长度放在数组之前。如果您曾经阅读过任何像我这样的 unix 手册,那么所有 unix 库方法的长度都在数组之前。在不知道数组长度的情况下读取结构时,您无法找到数组的末尾,因此您无法获得长度。属性按顺序存储在内存中,只有结构的起始位置和每个属性的大小。令人惊讶的是你不知道多少。 不是混合语言。传递给 c++ 方法时,该结构没有固定大小。仅使用指向起始位置的指针即可完成传递。 【参考方案1】:

首先,我想说的是 C++ 结构被错误地声明了。有效负载是二进制数据,因此数组应该是unsigned char* 而不是char*

除此之外,由于数组,结构体的编组有点繁琐。它是这样的:

[StructLayout(LayoutKind.Sequential)]
struct WAVE_INFO

    public int channel_num;
    public int audio_type;
    public IntPtr wave_data;
    public int wave_length;

我们不能在要编组的结构中使用byte[]。相反,我们必须将数组声明为 IntPtr 并自己处理编组。最简洁的方法是声明 byte[] 数组并使用 GCHandle 固定它们。

导入的函数如下所示:

[DllImport(dllfilename, CallingConvention = CallingConvention.Cdecl)]
static extern int processStruct(ref WAVE_INFO infoIn, ref WAVE_INFO infoOut);

对函数的相当混乱的调用是这样的:

var dataIn = new byte[256];
// populate the input data array
var dataOut = new byte[256];

GCHandle dataInHandle = GCHandle.Alloc(dataIn, GCHandleType.Pinned);
try

    GCHandle dataOutHandle = GCHandle.Alloc(dataOut, GCHandleType.Pinned);
    try
    
        WAVE_INFO infoIn;
        infoIn.audio_type = 1;
        infoIn.channel_num = 2;
        infoIn.wave_data = dataInHandle.AddrOfPinnedObject();
        infoIn.wave_length = dataIn.Length;

        WAVE_INFO infoOut = new WAVE_INFO();
        infoOut.wave_data = dataOutHandle.AddrOfPinnedObject();
        infoOut.wave_length = dataOut.Length;

        int retval = processStruct(ref infoIn, ref infoOut);
        // dataOut should have been populated by processStruct
    
    finally
    
        dataOutHandle.Free();
    

finally

    dataInHandle.Free();

我在这里的假设是第一个参数用于输入,第二个参数用于输出。但是调用者有责任为输出结构分配波形数据数组。

我还假设了一个调用约定,但您必须检查 C++ 宏 STRUCTDLL_API 以确定真正的调用约定是什么。

【讨论】:

谢谢,大卫。我刚刚用你的代码进行了测试,它工作得很好!感谢您的帮助。

以上是关于将 struct* 从 c# 传递到 c++ dll的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 DLLImport 将字符串从 C# 传递到 C++(以及从 C++ 到 C#)?

将结构数组从 C# 传递到 C++

将字节数组从 c++ 传递到 c#(单声道)

将二维数组从 C# 传递到 C++

Dllimport 将字符串从 C# 传递到 C++

如何将二维数组从 C# 传递到 C++?