将C#中的struct*传递给C++ DLL

5
在 C++ DLL 中定义结构体如下:
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[]或string。我该如何定义结构体以及在调用dll文件时定义方法?并且wave_data的长度是固定的,比如说100。


1
你如何知道 wave_data 的长度。长度必须在实际数据之前,因此 wave_data 和 wave_length 应该颠倒。 - jdweng
@jdweng 为什么结构体中的长度字段应该放在数据字段之前?这只是决定了结构体的布局。程序可以按任意顺序访问字段。 - David Heffernan
在传递给C++方法时,结构体的大小没有固定的尺寸。传递只需使用指向起始位置的指针完成。 - jdweng
@jdweng 结构体有固定的大小。您可以按任意顺序读取和写入其字段。这不是一个变长数组,其中确实必须先指定长度。此处的字段是指向数组的指针,不是结构体的一部分。 - David Heffernan
你的意思是音频波形数据是固定大小吗?????它总是相同的时间量吗????? - jdweng
显示剩余5条评论
1个回答

10

首先,我想说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;
}

我们不能在要被marshalled的结构体中使用byte[]。相反,我们必须将数组声明为IntPtr并自己处理marshalling。最清晰的方法是声明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以确定真正的调用约定。


谢谢,David。我刚刚用你的代码进行了测试,它完美地运行了!感谢你的帮助。 - Yao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接