将C++结构体数组封送到C#中

Marshal C++ struct array into C#

本文关键字:C++ 结构体 数组      更新时间:2023-10-16

我在C++中有以下结构:

#define MAXCHARS 15
typedef struct 
{
    char data[MAXCHARS];
    int prob[MAXCHARS];
} LPRData;

还有一个函数,我正在调用它来获得一个由3个结构组成的数组:

void GetData(LPRData *data);

在C++中,我会做这样的事情:

LPRData *Results;
Results = (LPRData *)malloc(MAXRESULTS*sizeof(LPRData));
GetData( Results );

它会很好地工作,但在C#中,我似乎无法让它工作。我创建了一个C#结构,如下所示:

public struct LPRData
{
    /// char[15]
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
    public string data;
    /// int[15]
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
    public int[] prob;
}

如果我初始化一个由3个数组(以及它们的所有子数组)组成的数组,并将其传递给这个:

GetData(LPRData[] data);

它成功返回,但LPRData数组中的数据没有更改。

我甚至尝试创建一个3个LPRData大小的原始字节数组,并将其传递到如下的函数原型中:

GetData(byte[]数据);

但在这种情况下,我将从第一个LPRData结构中获得"data"字符串,但在它之后什么都没有,包括来自同一LPRData的"prob"数组。

有什么想法可以妥善处理吗?

我会尝试向结构精简添加一些属性

[StructLayout(LayoutKind.Sequential, Size=TotalBytesInStruct),Serializable]
public struct LPRData
{
/// char[15]
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
public string data;
/// int[15]
[MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
public int[] prob;
}

*注:TotalBytesInStruct不代表可变

JaredPar也正确地认为,使用IntPtr类可能会有所帮助,但我已经有很长一段时间没有使用PInvoke了,所以我很生疏。

处理指针时的一个技巧是只使用IntPtr。然后,您可以在指针上使用Marshal.PtrToStructure,并根据结构的大小递增以获得结果。

static extern void GetData([Out] out IntPtr ptr);
LPRData[] GetData()
{
    IntPtr value;
    LPRData[] array = new LPRData[3];
    GetData(out value);
    for (int i = 0; i < array.Length; i++)
    {
        array[i] = Marshal.PtrToStructure(value, typeof(LPRData));
        value += Marshal.SizeOf(typeof(LPRData));
    }
    return array;
}

关于这个问题也讨论了类似的主题,其中一个结论是CharSet命名参数必须设置为CharSet.Ansi。否则,我们将制作wchar_t阵列,而不是char阵列。因此,正确的代码如下:

[Serializable]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct LPRData
{
    [MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 15)]
    public string data;
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 15)]
    public int[] prob;
}

PInvoke互操作助手可能会有所帮助。http://clrinterop.codeplex.com/releases/view/14120

是否使用OutAttribute标记GetData参数?

将InAttribute和OutAttribute特别有用当应用于阵列并格式化时,非blitable类型。来电者看到被调用者对这些类型所做的更改仅当同时应用这两个属性时。