Esempio di OutArrayOfStructs

In questo esempio viene illustrato come passare una matrice di strutture contenente valori integer e stringhe come parametri out a una funzione non gestita. Il codice sorgente di esempio è incluso nell'Esempio di tecnologia di richiamo piattaforma.

In questo esempio viene illustrato come chiamare una funzione nativa utilizzando la classe Marshal e utilizzando codice unsafe.

In questo esempio vengono utilizzate funzioni wrapper e operazioni pInvoke definite in PinvokeLib.dll e fornite anche nei file di origine. Vengono utilizzate inoltre la funzione TestOutArrayOfStructs e la struttura MYSTRSTRUCT2, la quale contiene i seguenti elementi:

typedef struct _MYSTRSTRUCT2
{
   char* buffer;
   UINT size; 
} MYSTRSTRUCT2;

Nella classe MyStruct è contenuto un oggetto stringa di caratteri ANSI. Nel campo CharSet viene specificato il formato ANSI. MyUnsafeStruct è una struttura contenente un tipo IntPtr anziché una stringa.

La classe LibWrap contiene il metodo di prototipo di overload TestOutArrayOfStructs. Se un metodo dichiara un puntatore come parametro, la classe deve essere contrassegnata con la parola chiave unsafe. Poiché in Visual Basic 2005 non è possibile utilizzare codice di tipo unsafe, il metodo di overload, il modificatore unsafe e la struttura MyUnsafeStruct non sono necessari.

Con la classe App viene implementato il metodo UsingMarshal, mediante cui si eseguono tutte le attività necessarie per passare la matrice. La matrice è contrassegnata con la parola chiave out (ByRef in Visual Basic) per indicare che i dati passano dal chiamato al chiamante. Nell'implementazione vengono utilizzati i seguenti metodi della classe Marshal:

  • PtrToStructure per effettuare il marshalling dei dati dal buffer non gestito a un oggetto gestito.

  • DestroyStructure per rilasciare la memoria riservata alle stringhe nella struttura.

  • FreeCoTaskMem per rilasciare la memoria riservata alla matrice.

Come illustrato in precedenza, diversamente da quanto avviene in Visual Basic 2005, in C# è possibile utilizzare codice di tipo unsafe. Nell'esempio di C# UsingUnsafe è un'implementazione di metodo alternativa in cui si utilizzano i puntatori anziché la classe Marshal per passare la matrice contenente la struttura MyUnsafeStruct.

Dichiarazione dei prototipi

' Declares a class member for each structure element.
< StructLayout( LayoutKind.Sequential, CharSet:=CharSet.Ansi )> _
Public Class MyStruct 
   Public buffer As String 
   Public someSize As Integer
End Class 'MyStruct

Public Class LibWrap
' Declares a managed prototype for the unmanaged function.
   Declare Sub TestOutArrayOfStructs Lib "..\\LIB\\PinvokeLib.dll" ( _
      ByRef arrSize As Integer, ByRef outArray As IntPtr )
End Class 'LibWrap
// Declares a class member for each structure element.
[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi )]
public class MyStruct 
{
   public String buffer;
   public int size;
}
// Declares a structure with a pointer.
[ StructLayout( LayoutKind.Sequential )]
public struct MyUnsafeStruct 
{
   public IntPtr buffer;
   public int size;
}

public unsafe class LibWrap
{
   // Declares managed prototypes for the unmanaged function.
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern void TestOutArrayOfStructs( out int size, 
      out IntPtr outArray );
   [ DllImport( "..\\LIB\\PinvokeLib.dll" )]
   public static extern void TestOutArrayOfStructs( out int size, 
   MyUnsafeStruct** outArray );
}

Chiamata delle funzioni

Public Class App
   Public Shared Sub Main()
      Console.WriteLine( ControlChars.CrLf & "Using marshal class" & _
ControlChars.CrLf )
      UsingMarshal()
      'Visual Basic 2005 cannot use unsafe code.
   End Sub 'Main
   
   Public Shared Sub UsingMarshal()   
      Dim arrSize As Integer
      Dim outArray As IntPtr
      LibWrap.TestOutArrayOfStructs( arrSize, outArray )
      Dim manArray(arrSize - 1) As MyStruct
      Dim current As IntPtr = outArray
      Dim i As Integer
      
      For i = 0 To arrSize - 1
      
         manArray(i) = New MyStruct()
         Marshal.PtrToStructure( current, manArray(i))
         
         Marshal.DestroyStructure( current, GetType( MyStruct )) 
         current = IntPtr.op_explicit( current.ToInt64() _
           + Marshal.SizeOf( manArray(i) ))
         
         Console.WriteLine( "Element {0}: {1} {2}", i, manArray(i)._
           buffer, manArray(i).someSize )
      Next i
      Marshal.FreeCoTaskMem( outArray )
   End Sub 'UsingMarshal
End Class 'App
public class App
{
   public static void Main()
   {
      Console.WriteLine( "\nUsing marshal class\n" );
      UsingMarshal();
      Console.WriteLine( "\nUsing unsafe code\n" );
      UsingUnsafe();
   }
   
   public static void UsingMarshal()   
   {
      int size;
      IntPtr outArray;
      LibWrap.TestOutArrayOfStructs( out size, out outArray );
      MyStruct[] manArray = new MyStruct[ size ];
      IntPtr current = outArray;
      for( int i = 0; i < size; i++ )
      {
         manArray[ i ] = new MyStruct();
         Marshal.PtrToStructure( current, manArray[ i ]);
         
         //Marshal.FreeCoTaskMem( (IntPtr)Marshal.ReadInt32( current ));
         Marshal.DestroyStructure( current, typeof(MyStruct) );
         current = (IntPtr)((long)current + 
            Marshal.SizeOf( manArray[ i ] ));
         
         Console.WriteLine( "Element {0}: {1} {2}", i, 
            manArray[ i ].buffer, manArray[ i ].size );
      }
      Marshal.FreeCoTaskMem( outArray );
   }
   
   public static unsafe void UsingUnsafe()
   {
      int size;
      MyUnsafeStruct* pResult;
      LibWrap.TestOutArrayOfStructs( out size, &pResult );
      MyUnsafeStruct* pCurrent = pResult;
      for( int i = 0; i < size; i++, pCurrent++ )
      {
         Console.WriteLine( "Element {0}: {1} {2}", i, 
            Marshal.PtrToStringAnsi( pCurrent->buffer ), pCurrent->size );
         Marshal.FreeCoTaskMem( pCurrent->buffer );
      }
      Marshal.FreeCoTaskMem( (IntPtr)pResult );
   }
}

Vedere anche

Concetti

Marshalling di classi, strutture e unioni
Tipi di dati del richiamo piattaforma
Creazione di prototipi nel codice gestito