将 C# 结构数组传递给 C++
Pass c# structure array to c++
我在 C++ dll 上工作,遇到任何问题!
我的头文件是这样的
struct ST_DevInfo
{
EN_DevType de_type;
int screen_width;
int screen_height;
char dev_name[256];
char id[14];
char sboox_version[16];
char fpga_version[16];
};
extern "C" __declspec(dllexport) int CB_GetDeviceList(ST_DevInfo* buff,int length);
和 C++ 代码
int CB_GetDeviceList(ST_DevInfo* buff,int length)
{
buff = (ST_DevInfo *)malloc(sizeof(ST_DevInfo) * length);
return GetDeviceList(buff, length);
}
现在我像这样在 C# 中使用这个函数
[StructLayout(LayoutKind.Sequential)]
struct ST_DevInfo
{
[MarshalAs(UnmanagedType.I4)]
public EN_DevType de_type;
[MarshalAs(UnmanagedType.I4)]
public int screen_width;
[MarshalAs(UnmanagedType.I4)]
public int screen_height;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 256)]
public char[] dev_name;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 14)]
public char[] id;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 16)]
public char[] sboox_version;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 16)]
public char[] fpga_version;
};
[DllImport(dllName, EntryPoint = "CB_GetDeviceList", SetLastError = true, ExactSpelling = true,
CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public static extern
int CB_GetDeviceList([MarshalAs(UnmanagedType.LPArray)] ref ST_DevInfo[] buff,
int length);
最后我在我的程序中像这样使用这个函数
ST_DevInfo[] buff = new ST_DevInfo[dev_length];
int ret = BBIA.CB_GetDeviceList( ref buff, dev_length);
但在从 CB_GetDeviceList 检索后,我的 buff 变量已分配但没有任何值(包含 0x00)。我用 C++ 测试它,它工作正常!
我认为这条线上有问题
buff = (ST_DevInfo *)malloc(sizeof(ST_DevInfo) * length);
在您的 C# 代码中,您这样做:
ST_DevInfo[] buff = new ST_DevInfo[dev_length];
int ret = BBIA.CB_GetDeviceList( ref buff, dev_length);
分配一个数组,并将其传递给 C++ 代码(通过双指针,因为您有 ref
)。
在您的 C++ 代码中您正在做的事情:
int CB_GetDeviceList(ST_DevInfo* buff,int length)
{
buff = (ST_DevInfo *)malloc(sizeof(ST_DevInfo) * length);
return GetDeviceList(buff, length);
}
它采用数组(而不是双指针)并将该(本地)指针更改为指向一些新内存。因此 C# 中的原始数组将永远不会被 C++ 代码触及。
首先,完全删除 malloc
调用。然后将您的 pinvoke 更改为:
[DllImport( ... )]
public static extern int CB_GetDeviceList( [In, Out] ST_DevInfo[] buff, int length );
并像以前一样调用,但没有 ref
。需要 In, Out
来告诉编组器您希望 pinvoke 调用修改数据。并非在所有情况下都需要它们,但对于您的情况,我不是 100% 确定,所以我会保留它们以防万一。
我在 C++ dll 上工作,遇到任何问题! 我的头文件是这样的
struct ST_DevInfo
{
EN_DevType de_type;
int screen_width;
int screen_height;
char dev_name[256];
char id[14];
char sboox_version[16];
char fpga_version[16];
};
extern "C" __declspec(dllexport) int CB_GetDeviceList(ST_DevInfo* buff,int length);
和 C++ 代码
int CB_GetDeviceList(ST_DevInfo* buff,int length)
{
buff = (ST_DevInfo *)malloc(sizeof(ST_DevInfo) * length);
return GetDeviceList(buff, length);
}
现在我像这样在 C# 中使用这个函数
[StructLayout(LayoutKind.Sequential)]
struct ST_DevInfo
{
[MarshalAs(UnmanagedType.I4)]
public EN_DevType de_type;
[MarshalAs(UnmanagedType.I4)]
public int screen_width;
[MarshalAs(UnmanagedType.I4)]
public int screen_height;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 256)]
public char[] dev_name;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 14)]
public char[] id;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 16)]
public char[] sboox_version;
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.I1, SizeConst = 16)]
public char[] fpga_version;
};
[DllImport(dllName, EntryPoint = "CB_GetDeviceList", SetLastError = true, ExactSpelling = true,
CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public static extern
int CB_GetDeviceList([MarshalAs(UnmanagedType.LPArray)] ref ST_DevInfo[] buff,
int length);
最后我在我的程序中像这样使用这个函数
ST_DevInfo[] buff = new ST_DevInfo[dev_length];
int ret = BBIA.CB_GetDeviceList( ref buff, dev_length);
但在从 CB_GetDeviceList 检索后,我的 buff 变量已分配但没有任何值(包含 0x00)。我用 C++ 测试它,它工作正常! 我认为这条线上有问题
buff = (ST_DevInfo *)malloc(sizeof(ST_DevInfo) * length);
在您的 C# 代码中,您这样做:
ST_DevInfo[] buff = new ST_DevInfo[dev_length];
int ret = BBIA.CB_GetDeviceList( ref buff, dev_length);
分配一个数组,并将其传递给 C++ 代码(通过双指针,因为您有 ref
)。
在您的 C++ 代码中您正在做的事情:
int CB_GetDeviceList(ST_DevInfo* buff,int length)
{
buff = (ST_DevInfo *)malloc(sizeof(ST_DevInfo) * length);
return GetDeviceList(buff, length);
}
它采用数组(而不是双指针)并将该(本地)指针更改为指向一些新内存。因此 C# 中的原始数组将永远不会被 C++ 代码触及。
首先,完全删除 malloc
调用。然后将您的 pinvoke 更改为:
[DllImport( ... )]
public static extern int CB_GetDeviceList( [In, Out] ST_DevInfo[] buff, int length );
并像以前一样调用,但没有 ref
。需要 In, Out
来告诉编组器您希望 pinvoke 调用修改数据。并非在所有情况下都需要它们,但对于您的情况,我不是 100% 确定,所以我会保留它们以防万一。