2012-02-05 13 views
8

Si clasifico esta estructura con StructureToPtr y luego la elimino de nuevo con PtrToStructure, mi primer nodo tiene y = {1,2} mientras que mi segundo nodo tiene y = {1,0}.Marshal.StructureToPtr falla con bool y matriz de tamaño fijo?

No tengo idea de por qué, tal vez mi estructura es mala de alguna manera? Eliminar el bool de la estructura lo hace funcionar.

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

Tal vez tiene que hacer algo con 'bool' siendo clasificado como 4 bytes (' BOOL') en lugar de 1 byte? Pero no puedo pensar en la razón exacta ... – Mehrdad

+0

Además, ignora los elementos de la matriz después de la primera (los escribe como ceros en la memoria no administrada). Tampoco importa si 'bool' viene antes de la matriz o después en la estructura. – GSerg

Respuesta

9

Esto de hecho va mal. Es la llamada StructureToPtr() que no puede copiar suficientes bytes. Puede ver esto usando Debug + Windows + Memory + Memory1 y poniendo "ptr" en el cuadro de dirección. Utilizando el operador sizeof isn't correct pero no es realmente la fuente del problema. Solo se copia el primer elemento de la matriz, independientemente de la longitud de la matriz. No estoy seguro de qué causa este problema, nunca uso fijo en pinvoke. Sólo puedo recomendar la manera tradicional PInvoke que funciona muy bien:

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

Puede publicar en connect.microsoft.com si quieres llevar esto a la atención de los maestros CLR de interoperabilidad.

+0

gracias, el comentario en el enlace que publica realmente explica el problema, aunque en realidad la verdadera respuesta es que no debería usar búferes de tamaño fijo y debería usar el atributo MarshalAs, como lo demuestra. Ya sabía que no debería usar sizeof(), simplemente no estoy seguro de si en el mundo real hace alguna diferencia. Pero de todos modos, ahora he cambiado mi código para usar Marshal.SizeOf independientemente. – junichiro

+0

@Hans faltan comentarios en su enlace ☹ –

+0

Solo para agregar a esto: PtrToStructure() también solo copiará el primer byte de la matriz fija, incluso si la ubicación de la memoria contiene más información. Incluso si la estructura usa LayoutKind.Explicit aún falla :( –

0

También debe empaquetar la estructura o clase antes de usarla. Eso funciona para mí, casi tan bueno como memcpy

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