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