将结构数组从 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# 传递到 C++

将结构数组从 C#(.NET Core) 传递到 C++(未管理)

当结构仅在运行时已知时,将结构从 c++ 传递到 c#

使用名称管道将结构从 C# 应用程序传递到 C++ 服务器?

如何将结构中的char *从c#传递到c++

如何将带有 unsigned char* 的结构从 C# 传递到 C++?