2010-10-15 14 views
13

Sto usando API scritte in C++ nel mio codice (scrivendo in C#). API richiede un parametro come puntatore alla struttura. la struttura è costituita s "INT" e Char array: per esempioPassare una struttura all'API C++ utilizzando Marshal.StructureToPtr in C#

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

non posso passare direttamente il puntatore struttura API perché in questo caso, sto ottenendo errore come "puntatori non può fare riferimento strutture marshaled" . Il codice viene compilato correttamente ma questo errore si verifica quando eseguo (debug) il codice.

Ora ho due opzioni: 1 °: - Passing Structure by Ref: Voglio chiedere un API che richiede un puntatore di struttura può ricevere l'indirizzo quando passo la struttura di riferimento. Nota che l'API restituirà i dati in "Char [] Data".

2: - Utilizzo di Marshal.StructureToPtr: consente di convertire il puntatore di struttura in IntPtr. Di nuovo il dubbio è lo stesso, l'API lo riceverà correttamente?

Grazie per il tuo tempo!

saluti, Swanand

risposta

15

Se richiede solo puntatore, è possibile allocare una certa memoria non gestita, il maresciallo la struttura alla memoria, e passare che il puntatore alla funzione. In seguito, puoi tornare alla struttura (se lo desideri) e liberare la memoria. Prima di effettuare il marshalling di qualsiasi cosa, è necessario definire correttamente la struttura. Qualcosa di simile:

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

[modifica]
Per simulare array di lunghezza variabile, allocare memoria non gestita all'interno della struttura e inizializzare come al solito.

[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

Grazie mille! È stato perfetto!! Una domanda, l'API può restituire i dati nella matrice di caratteri? – Swanand

+0

AFAIK, sì. L'API non gestita può utilizzare la memoria puntata come qualsiasi altra memoria poiché non è gestita. In tal caso, vorrai tornare alla struttura per ottenere il risultato nel codice gestito. –

+0

Sta funzionando bene ... Ma sto affrontando un altro problema, ora voglio passare i dati all'API (diciamo la versione WriteToAPI dell'API sopra menzionata). Passerò ora i dati all'API. Ma dato che questi dati Char non sono di dimensione 255 (voglio passare dati di dimensioni variabili) danno errore come "Tipo non può essere effettuato il marshalling perché la lunghezza di un'istanza di Array incorporato non corrisponde alla lunghezza dichiarata nel layout" – Swanand