将结构数组从 C# 传递到 C++
Posted
技术标签:
【中文标题】将结构数组从 C# 传递到 C++【英文标题】:Passing an array of structure from C# to C++ 【发布时间】:2012-04-30 15:52:03 【问题描述】:我需要将一个结构数组从 C++ 传递到 C#。我有下面的代码,它首先创建一个临时结构,然后将memcpy
它到C#端结构的地址。我用相同的元素顺序定义了两边的结构。
当我调试时,我看到临时结构被正确填充,temp_buf(目标变量的地址)在每次迭代时结构的大小都会增加,memcpy
不会返回任何错误。
但是C#端只设置了数组的第一项。
以下是 C# 方面的定义:
[DllImport(@"MyAwesomeDLL.dll", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?GetDevices@@YAHPAXIPAIPAUDEVICE_S@@@Z", CharSet = CharSet.Auto)]
public static extern Int32 GetCoolDevices(out UInt32 p_deviceCount, out Device_s p_devicesBuf);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct Device_s
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 51)]
public String DeviceName;
public UInt32 DeviceID;
以下是 C++ 方面的定义:
#pragma pack (1)
typedef struct
TCHAR device_name [51];
UINT32 device_rid;
DEVICE_S;
int GetDevices (UINT32 *device_count, DEVICE_S *devices_buf)
....
while(....)
DEVICE_S tmp_device;
memset(&tmp_device, 0, sizeof(DEVICE_S));
tmp_device.device_id = 5;
sprintf( tmp_device.device_name, "a string");
DEVICE_S *temp_buf = &(devices_buf[i]);
size_t mysize = sizeof(DEVICE_S);
memcpy(temp_buf, &tmp_device, mysize);
i++;
getNextDevice();
.....
而且,我是这样称呼它的:
UInt32 MyDecDeviceCnt = 0;
Device_s[] MyDecDevices = new Device_s[10];
int ret = GetCoolDevices(out MyDecDeviceCnt, out MyDecDevices[0]);
欢迎提出任何建议!
【问题讨论】:
@SamFisher83 - 你的建议毫无意义。使用字符串是正确的过程。当然这两个结构的大小甚至不一样,C#结构至少要大12位。 @Ramhound 我纠正了我的拼写错误。现在,device_name 的长度为 51 个字符。还是不匹配? 【参考方案1】:您创建的 API 存在问题。您为托管端的数组分配内存(10 个元素),但您没有将数组中的元素数量传递给非托管端。编组器无法确定您要编组 10 个元素,并且非托管代码不知道它正在写入的缓冲区的大小。
您可以使用MarshalAsAttribute.SizeParamIndex 向编组器提供有关数组大小的信息。另请查看文章Default Marshaling for Arrays。 (特别是有关 C 样式数组的信息。)
鉴于您的 API 的性质,您可以对其进行更改,以便在非托管端分配内存。您必须使用安全数组或 hglobal 来允许在托管端释放内存。
【讨论】:
你还应该提到TCHAR device_name [20];
vs SizeConst = 51
——这将导致DeviceID
驻留在错误的偏移量。
我认为这是一个简单的错字,但需要修正。
@MartinLiversage - 该错误不太可能是拼写错误。
@MartinLiversage 谢谢,但我不确定这是否是问题所在。如果我从结构中删除字符串并且只有整数,它工作正常。在非托管方面,我在每次迭代时都有正确的内存位置地址。似乎在非托管端正确设置了内存,但是当我切换回托管端时它以某种方式(?)丢失了。
@mustafa:字符串是不同的,因为它们是指针。从调用返回时,编组器必须遵循这些指针并从指向的数据创建托管字符串。编组器仅对第一个元素执行此操作,除非您向其提供有关数组大小的一些信息。以上是关于将结构数组从 C# 传递到 C++的主要内容,如果未能解决你的问题,请参考以下文章
将结构数组从 C#(.NET Core) 传递到 C++(未管理)