将 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的主要内容,如果未能解决你的问题,请参考以下文章