我如何编组一个包含可变大小的数组到C#中的结构?数组、大小、结构

2023-09-02 21:37:07 作者:顾笙

我如何编组本C ++类型?

的ABS_DATA结构用来与所述长度信息的任意长的数据块相关联。在数据数组的声明长度为1,但实际长度是由长度成员给出。

  typedef结构abs_data {
  ABS_DWORD长度;
  ABS_BYTE数据[ABS_VARLEN]
} ABS_DATA;
 

我尝试以下code,但它不工作。数据变量始终是空的,我敢肯定,它有数据在那里。

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential,字符集= System.Runtime.InteropServices.CharSet.Ansi)     公共结构abs_data     {         /// ABS_DWORD->无符号整型         公共UINT长度;         /// ABS_BYTE [1]        [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 1)]         公共字符串数据;     }

解决方案 数据结构 数组

如果被保存的数据不是一个字符串,您不必将其存储在一个字符串。我通常不元帅为一个字符串,除非原始数据类型是的char * 。否则,字节[] 应该做的。

尝试:

  [的MarshalAs(UnmanagedType.ByValArray,SizeConst = [无论你的大小]
byte []的数据;
 

如果您稍后需要将此转换为字符串,可以使用:

  System.Text.Encoding.UTF8.GetString(这里的字节数组)。
 

显然,你需要改变编码你需要什么,尽管 UTF-8 通常是足够的。

我看到现在的问题,你要封送可变长度数组。所述的MarshalAs不允许这种和阵列将必须被引用发送

如果数组的长度是可变的,你的字节[] 必须是一个IntPtr,所以你会使用,

  IntPtr的数据;
 

相反

  [的MarshalAs(UnmanagedType.ByValArray,SizeConst = [无论你的大小]
byte []的数据;
 

您可以再使用Marshal类访问底层数据。

是这样的:

  UINT长度= yourABSObject.Length;
byte []的缓冲区=新的字节[长度];

Marshal.Copy(缓冲液,0,yourABSObject.Data,长度);
 

您可能需要清理你的记忆,当你完成,以避免泄漏,但我怀疑,当yourABSObject超出范围的GC将它清理干净。总之,这里是清理code:

  Marshal.FreeHGlobal(yourABSObject.Data);
 

How do I marshal this C++ type?

The ABS_DATA structure is used to associate an arbitrarily long data block with the length information. The declared length of the Data array is 1, but the actual length is given by the Length member.

typedef struct abs_data {
  ABS_DWORD Length;
  ABS_BYTE Data[ABS_VARLEN];
} ABS_DATA;

I tried the following code, but it's not working. The data variable is always empty and I'm sure it has data in there.

[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
    public struct abs_data
    {
        /// ABS_DWORD->unsigned int
        public uint Length;

        /// ABS_BYTE[1]
       [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst = 1)]
        public string Data;
    }

解决方案

If the data being saved isn't a string, you don't have to store it in a string. I usually do not marshal to a string unless the original data type was a char*. Otherwise a byte[] should do.

Try:

[MarshalAs(UnmanagedType.ByValArray, SizeConst=[whatever your size is]]
byte[] Data;

If you need to convert this to a string later, use:

System.Text.Encoding.UTF8.GetString(your byte array here). 

Obviously, you need to vary the encoding to what you need, though UTF-8 usually is sufficient.

I see the problem now, you have to marshal a VARIABLE length array. The MarshalAs does not allow this and the array will have to be sent by reference.

If the array length is variable, your byte[] needs to be an IntPtr, so you would use,

IntPtr Data;

Instead of

[MarshalAs(UnmanagedType.ByValArray, SizeConst=[whatever your size is]]
byte[] Data;

You can then use the Marshal class to access the underlying data.

Something like:

uint length = yourABSObject.Length;
byte[] buffer = new byte[length];

Marshal.Copy(buffer, 0, yourABSObject.Data, length);

You may need to clean up your memory when you are finished to avoid a leak, though I suspect the GC will clean it up when yourABSObject goes out of scope. Anyway, here is the cleanup code:

Marshal.FreeHGlobal(yourABSObject.Data);