2010-10-15 19 views
13

Estoy usando API escrita en C++ en mi código (escribiendo en C#). API requiere un parámetro como Puntero a estructura. La estructura consta de s "Int" y Char matrices: por ejemploPasar una Estructura a C++ API usando Marshal.StructureToPtr en C#

unsafe public struct ToBePassed 
    { 
     Int32 Num1; 
     Int32 Num2; 
     Char[] Data; // or fixed Char Data[255]; 
    } 

no puedo pasar directamente el puntero de la estructura a la API porque en ese caso, estoy consiguiendo el error como "Los punteros no puede hacer referencia a las estructuras calcular las referencias" . El código se compila con éxito, pero este error aparece cuando ejecuto (depuración) el código.

Ahora tengo dos opciones: Primero: - Pasar Estructura por Ref: Quiero hacer una API que requiera Un Puntero de Estructura puede recibir la dirección cuando paso la estructura por ref. Tenga en cuenta que la API devolverá datos en "Datos [] Char []".

2º: - Usando Marshal.StructureToPtr: Esto convertirá el Puntero de Estructura a IntPtr. Nuevamente, The Doubt es lo mismo, ¿Recibirá la API correctamente?

¡Gracias por su tiempo!

Saludos, Swanand

Respuesta

15

Si sólo requiere puntero, puede destinar parte de la memoria no administrada, formar la estructura de la memoria, y pasar ese puntero a su función. Luego, luego, puedes regresar a la estructura (si lo deseas) y liberar la memoria. Antes de ordenar algo, debe definir correctamente la estructura. Algo como esto:

[StructLayout(
    LayoutKind.Sequential,  //must specify a layout 
    CharSet = CharSet.Ansi)] //if you intend to use char 
public struct ToBePassed 
{ 
    public Int32 Num1; 
    public Int32 Num2; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 255)] 
    public Char[] Data; //specify the size using MarshalAs 
} 

[DllImport("...")] 
public static extern void APICall(IntPtr argPtr); 


public static void CallFunction(ToBePassed managedObj) 
{ 
    IntPtr unmanagedAddr = Marshal.AllocHGlobal(Marshal.SizeOf(managedObj)); 

    Marshal.StructureToPtr(managedObj, unmanagedAddr, true); 

    APICall(unmanagedAddr); 

    Marshal.PtrToStructure(unmanagedAddr, managedObj); 

    Marshal.FreeHGlobal(unmanagedAddr); 
    unmanagedAddr = IntPtr.Zero; 
} 

[editar]
para simular matrices de longitud variable, asignar memoria no administrada dentro de la estructura e inicializar como de costumbre.

[StructLayout(LayoutKind.Sequential)] 
public struct SomeStruct 
{ 
    public Int32 X; 
    public Int32 Y; 
} 

[StructLayout(LayoutKind.Sequential)] 
public struct VLA 
{ 
    public Int32 intArrayLength; 
    public Int32 SomeStructArrayLength; 
    public IntPtr intArray; 
    public IntPtr SomeStructArray; 
} 

public static VLA CreateVLA(int[] intArray, SomeStruct[] SomeStructArray) 
{ 
    var vla = new VLA() 
    { 
     intArrayLength = intArray.Length, 
     SomeStructArrayLength = SomeStructArray.Length, 
     intArray = Marshal.AllocHGlobal(intArray.Length * Marshal.SizeOf(typeof(int))), 
     SomeStructArray = Marshal.AllocHGlobal(SomeStructArray.Length * Marshal.SizeOf(typeof(SomeStruct))), 
    }; 
    Marshal.Copy(intArray, 0, vla.intArray, intArray.Length); 
    //there's no overload to copy arbitrary arrays, do it manually 
    for (int i = 0; i < SomeStructArray.Length; i++) 
    { 
     Marshal.StructureToPtr(
      SomeStructArray[i], 
      vla.SomeStructArray + i * Marshal.SizeOf(typeof(SomeStruct)), 
      true); 
    } 
    return vla; 
} 
+0

Muchas gracias! ¡¡Eso fue genial!! Una pregunta: ¿Puede la API devolver datos en el Char Array? – Swanand

+0

AFAIK, sí. La API no administrada puede usar la memoria apuntada a la memoria como cualquier otra memoria ya que no está administrada. En ese caso, querría volver a la estructura para obtener el resultado en el código administrado. –

+0

Eso está funcionando bien ... Pero me enfrenta a un problema más, ahora quiero pasar datos a la API (digamos la versión WriteToAPI de la API mencionada) Pasaré los datos a la API ahora. Pero como este dato de Char no es del tamaño 255 (quiero pasar datos de tamaño variable) está dando error como "El tipo no se puede mapear porque la longitud de una instancia de matriz integrada no coincide con la longitud declarada en el diseño" – Swanand

Cuestiones relacionadas