C# 嵌套结构封送处理 - 对象
C# nested structure marshaling - object
我有以下嵌套结构。
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ERROR_ITEM
{
byte ErrorID;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ERROR_DATA
{
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 10)]
ERROR_ITEM[] ErrorItem;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct VCP_DATA
{
[MarshalAs(UnmanagedType.Struct)]
ERROR_DATA ErrorData;
};
我需要将一个字节数组复制到这个结构中,所以我尝试了以下方法
vcpBuffer = new VCP_DATA();
GCHandle handle = GCHandle.Alloc(vcpBuffer, GCHandleType.Pinned);
try
{
IntPtr pBuffer = handle.AddrOfPinnedObject();
Marshal.Copy(bytarray, 0, pBuffer, length);
}
finally
{
if (handle.IsAllocated)
handle.Free();
}
但是 GCHandle.Alloc() returns 错误 "An unhandled exception of type System.Argument.Execption" 发生在 mscorlib.dll。
附加信息:对象包含非原始数据或非 blittable 数据。
首先,ERROR_ITEM[] 是一个托管数组,所以它不是 blittable 结构。它只是一个管理参考。引用指向的内存有一个同步块、方法 table 指针和位于实际元素前面的长度说明符。
但是,使用 'fixed' (https://msdn.microsoft.com/en-us/library/zycewsya.aspxhttps://msdn.microsoft.com/en-us/library/zycewsya.aspx) 不会有帮助(但请检查一下)。要克服此错误,因为 ERROR_ITEM
[] 是固定长度的,只需将数组替换为其中的 16 个 ERROR_ITEM
字段。您仍然可以针对第一个 ERROR_ITEM
(ERROR_ITEM*
) 的地址使用数组语法来访问后续元素。
或者,只计算所有 16 个元素的大小,但只包括第一个作为字段,然后在 ERROR_DATA
的 StructLayout
属性上指定 Size
参数,这样它大到足以容纳它们。
此外,Resharper 有时会抱怨嵌套的东西,而实际的编译器对此非常满意。但这是因为它是一个数组。根据我的经验,即使是固定的不安全嵌入式数组也会使 C# 认为它是 unblittable。
vcpBuffer = new VCP_DATA();
GCHandle handle = GCHandle.Alloc(bytearray, GCHandleType.Pinned);
try
{
IntPtr pBuffer = handle.AddrOfPinnedObject();
vcpBuffer = (VCP_DATA)Marshal.PtrToStructure(pBuffer, typeof(VCP_DATA));
}
finally
{
if (handle.IsAllocated)
handle.Free();
}
我有以下嵌套结构。
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ERROR_ITEM
{
byte ErrorID;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct ERROR_DATA
{
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 10)]
ERROR_ITEM[] ErrorItem;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct VCP_DATA
{
[MarshalAs(UnmanagedType.Struct)]
ERROR_DATA ErrorData;
};
我需要将一个字节数组复制到这个结构中,所以我尝试了以下方法
vcpBuffer = new VCP_DATA();
GCHandle handle = GCHandle.Alloc(vcpBuffer, GCHandleType.Pinned);
try
{
IntPtr pBuffer = handle.AddrOfPinnedObject();
Marshal.Copy(bytarray, 0, pBuffer, length);
}
finally
{
if (handle.IsAllocated)
handle.Free();
}
但是 GCHandle.Alloc() returns 错误 "An unhandled exception of type System.Argument.Execption" 发生在 mscorlib.dll。 附加信息:对象包含非原始数据或非 blittable 数据。
首先,ERROR_ITEM[] 是一个托管数组,所以它不是 blittable 结构。它只是一个管理参考。引用指向的内存有一个同步块、方法 table 指针和位于实际元素前面的长度说明符。
但是,使用 'fixed' (https://msdn.microsoft.com/en-us/library/zycewsya.aspxhttps://msdn.microsoft.com/en-us/library/zycewsya.aspx) 不会有帮助(但请检查一下)。要克服此错误,因为 ERROR_ITEM
[] 是固定长度的,只需将数组替换为其中的 16 个 ERROR_ITEM
字段。您仍然可以针对第一个 ERROR_ITEM
(ERROR_ITEM*
) 的地址使用数组语法来访问后续元素。
或者,只计算所有 16 个元素的大小,但只包括第一个作为字段,然后在 ERROR_DATA
的 StructLayout
属性上指定 Size
参数,这样它大到足以容纳它们。
此外,Resharper 有时会抱怨嵌套的东西,而实际的编译器对此非常满意。但这是因为它是一个数组。根据我的经验,即使是固定的不安全嵌入式数组也会使 C# 认为它是 unblittable。
vcpBuffer = new VCP_DATA();
GCHandle handle = GCHandle.Alloc(bytearray, GCHandleType.Pinned);
try
{
IntPtr pBuffer = handle.AddrOfPinnedObject();
vcpBuffer = (VCP_DATA)Marshal.PtrToStructure(pBuffer, typeof(VCP_DATA));
}
finally
{
if (handle.IsAllocated)
handle.Free();
}