将 C++ struct 数组元组化为 C#

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/188299/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 17:16:21  来源:igfitidea点击:

Marshal C++ struct array into C#

c#c++interopstructmarshalling

提问by Adam Haile

I have the following struct in C++:

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

#define MAXCHARS 15

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

And a function that I'm p/invoking into to get an array of 3 of these structures:

还有一个我正在调用的函数来获取这些结构中的 3 个数组:

void GetData(LPRData *data);

In C++ I would just do something like this:

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

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

And it would work just fine, but in C# I can't seem to get it to work. I've created a C# struct like this:

它会工作得很好,但在 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;
}

And if I initialize an array of 3 of those (and all their sub-arrays) and pass it into this:

如果我初始化一个包含 3 个(及其所有子数组)的数组并将其传递给这个:

GetData(LPRData[] data);

It returns with success, but the data in the LPRData array has not changed.

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

I've even tried to create a raw byte array the size of 3 LPRData's and pass that into a function prototype like this:

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

GetData(byte[] data);

GetData(byte[] 数据);

But in that case I will get the "data" string from the very first LPRData structure, but nothing after it, including the "prob" array from the same LPRData.

但在那种情况下,我将从第一个 LPRData 结构中获取“数据”字符串,但在它之后没有任何内容,包括来自同一个 LPRData 的“prob”数组。

Any ideas of how to properly handle this?

有关如何正确处理此问题的任何想法?

采纳答案by denny

I would try adding some attributes to your struct decloration

我会尝试在你的结构声明中添加一些属性

[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;
}

*Note TotalBytesInStruct is not intended to represent a variable

*注意 TotalBytesInStruct 不代表变量

JaredPar is also correct that using the IntPtr class could be helpful, but it has been quite awhile since I have used PInvoke so I'm rusty.

JaredPar 也是正确的,使用 IntPtr 类可能会有所帮助,但自从我使用 PInvoke 以来已经有一段时间了,所以我生疏了。

回答by JaredPar

One trick when dealing with pointers is to just use an IntPtr. You can then use Marshal.PtrToStructure on the pointer and increment based on the size of the structure to get your results.

处理指针时的一个技巧是只使用 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;
}

回答by GregUzelac

The PInvoke Interop Assistant may help. http://clrinterop.codeplex.com/releases/view/14120

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

回答by Constantin

Did you mark GetData parameter with OutAttribute?

您是否使用OutAttribute标记了 GetData 参数?

Combining the InAttribute and OutAttribute is particularly useful when applied to arrays and formatted, non-blittable types. Callers see the changes a callee makes to these types only when you apply both attributes.

当应用于数组和格式化的非 blittable 类型时,组合 InAttribute 和 OutAttribute 特别有用。只有当您应用这两个属性时,调用方才能看到被调用方对这些类型所做的更改。

回答by Zenexer

A similar topic was discussed on this question, and the one of the conclusions was that the CharSetnamed parameter must be set to CharSet.Ansi. Otherwise, we would be making a wchar_tarray instead of a chararray. Thus, the correct code would be as follows:

这个问题上讨论了一个类似的主题,结论之一是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;
}