将结构数组从C#传递给C ++

时间:2012-04-30 15:52:03

标签: c# c++ marshalling

我需要将一个结构数组从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]);

任何建议都表示赞赏!

1 个答案:

答案 0 :(得分:2)

您创建的API存在问题。您在托管端分配数组的内存(10个元素),但不将数组中的元素数传递给非托管端。编组器无法确定您是否要编组10个元素,而非托管代码不知道它正在写入的缓冲区的大小。

您可以使用MarshalAsAttribute.SizeParamIndex向编组人员提供有关阵列大小的信息。另请查看文章Default Marshaling for Arrays。 (特别是关于C风格数组的信息。)

鉴于您的API的性质,您可以更改它,以便在非托管端分配内存。您必须使用安全数组或hglobal来允许在管理端释放内存。