2012-02-05 21 views
8

如果我用StructureToPtr编组这个结构,然后再用PtrToStructure解组它,我的第一个节点有y = {1,2},而我的第二个节点有y = {1,0}。Marshal.StructureToPtr失败与布尔和固定大小的数组?

我不知道为什么,也许我的结构不好?从结构中删除bool使其工作。

using System; 
using System.Runtime.InteropServices; 

namespace csharp_test 
{ 
    unsafe class Program 
    { 
     [StructLayout(LayoutKind.Sequential)] 
     public struct Node 
     { 
      public bool boolVar; 
      public fixed int y[2]; 
     } 

     unsafe static void Main(string[] args) 
     { 
      Node node = new Node(); 

      node.y[0] = 1; 
      node.y[1] = 2; 
      node.boolVar = true; 

      int size = sizeof(Node); 
      IntPtr ptr = Marshal.AllocHGlobal(size); 
      Marshal.StructureToPtr(node, ptr, false); 
      Node node2 = (Node)Marshal.PtrToStructure(ptr, typeof(Node)); 
      Marshal.FreeHGlobal(ptr); 
     } 
    } 
} 
+0

也许它必须做一些事情,把'bool'编组为4字节('BOOL')而不是1个字节?但我想不出确切的原因...... – Mehrdad 2012-02-05 19:37:07

+0

此外,它忽略了第一个数组元素之后的任何数组元素(将它们作为零写入非托管内存中)。如果'bool'出现在阵列之前或结构之后,也没有关系。 – GSerg 2012-02-05 19:42:29

回答

9

这的确是出了问题。这是StructureToPtr()调用无法复制足够的字节。你可以通过使用Debug + Windows + Memory + Memory1并在地址栏中输入“ptr”来看到这一点。使用sizeof运算符isn't correct但实际上不是问题的根源。无论数组长度如何,只有数组的第一个元素被复制。不知道是什么原因导致这个问题,我从来没有用固定在pinvoke。我只能推荐传统的PInvoke方法的正常工作:如果你希望把这种对CLR互操作高手的关注,您可以张贴到connect.microsoft.com

unsafe class Program { 
    [StructLayout(LayoutKind.Sequential)] 
    public struct Node { 
     public bool boolVar; 
     [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] 
     public int[] y; 
    } 

    unsafe static void Main(string[] args) { 
     Node node = new Node(); 
     node.y = new int[2]; 

     node.y[0] = 1; 
     node.y[1] = 2; 
     node.boolVar = true; 

     int size = Marshal.SizeOf(node); 
     IntPtr ptr = Marshal.AllocHGlobal(size); 
     Marshal.StructureToPtr(node, ptr, false); 
     Node node2 = (Node)Marshal.PtrToStructure(ptr, typeof(Node)); 
     Marshal.FreeHGlobal(ptr); 
    } 

+0

谢谢,您发布的链接中的评论确实可以解释问题,但实际上真正的答案是我不应该使用固定大小的缓冲区,而应该使用MarshalAs属性,如您所示。 我已经意识到你不应该真的使用sizeof(),只是我不确定是否在真实世界中它有什么区别。但无论如何,我已经改变了我的代码使用Marshal.SizeOf无论如何。 – junichiro 2012-02-05 20:19:56

+0

@Han缺少链接中的注释☹ – 2014-10-14 09:47:10

+0

只需添加到此:即使内存位置包含更多信息,PtrToStructure()也将仅复制固定数组的第一个字节。即使结构使用LayoutKind.Explicit它仍然失败:( – 2016-02-05 09:29:59

0

在使用它之前,您还应该打包结构或类。这适用于我,几乎和memcpy一样好

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
public class SomeClass 
{ 
}