【问题标题】:C# nested structure marshaling - objectC# 嵌套结构封送处理 - 对象
【发布时间】:2017-02-06 22:35:23
【问题描述】:

我有以下嵌套结构。

[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() 返回错误“系统.Argument.Execption 类型的未处理异常”发生在 mscorlib.dll 中。 附加信息:对象包含非原始或非 blittable 数据。

【问题讨论】:

    标签: c# nested structure marshalling


    【解决方案1】:
    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(); 
    }
    

    【讨论】:

      【解决方案2】:

      首先,ERROR_ITEM[] 是一个托管数组,所以它不是一个 blittable 结构。它只是一个托管参考。引用指向的内存有一个同步块、方法表指针和一个位于实际元素前面的长度说明符。

      但是,使用“固定”(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 个元素的大小,但仅将第一个元素作为字段包含在内,然后在 StructLayout 属性上为 ERROR_DATA 指定 Size 参数,使其足够容纳所有元素.

      此外,当实际的编译器对嵌套内容非常满意时,Resharper 有时会抱怨嵌套内容。但这是因为它是一个数组。根据我的经验,即使是固定的不安全的嵌入式数组,C# 也会认为它是不可复制的。

      【讨论】:

      • 感谢您的建议。我相信它们会起作用,但我找到了另一种做我需要的方法。 vcpBuffer = 新 VCP_DATA(); GCHandle 句柄 = GCHandle.Alloc(bytearray, GCHandleType.Pinned);尝试 { IntPtr pBuffer = handle.AddrOfPinnedObject(); vcpBuffer = (VCP_DATA)Marshal.PtrToStructure(pBuffer, typeof(VCP_DATA)); } 最后 { if (handle.IsAllocated) handle.Free(); }
      • @Hassan - 你应该回答并接受它!这样做并改进网站是合法的。
      猜你喜欢
      • 1970-01-01
      • 2015-12-12
      • 2023-03-18
      • 2013-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-10
      相关资源
      最近更新 更多