OutArrayOfStructs, exemple
Cet exemple montre comment passer un tableau de structures contenant des entiers et des chaînes comme paramètres Out vers une fonction non managée.
Cet exemple montre comment appeler une fonction native en utilisant la classe Marshal et en utilisant le code unsafe.
Cet exemple utilise des fonctions wrapper et des appels de plateforme définis dans PinvokeLib.dll, également fournis dans les fichiers sources. Il utilise la fonction TestOutArrayOfStructs et la structure MYSTRSTRUCT2. Cette structure contient les éléments suivants :
typedef struct _MYSTRSTRUCT2
{
char* buffer;
UINT size;
} MYSTRSTRUCT2;
La classe MyStruct contient un objet chaîne de caractères ANSI. Le champ CharSet spécifie le format ANSI. MyUnsafeStruct est une structure qui contient un type IntPtr au lieu d'une chaîne.
La classe LibWrap contient la méthode de prototype surchargée TestOutArrayOfStructs. Si une méthode déclare un pointeur en tant que paramètre, la classe doit être marquée avec le mot clé unsafe. Comme Visual Basic 2005 ne peut pas utiliser de code unsafe, la méthode surchargée, le modificateur unsafe et la structure MyUnsafeStruct ne sont pas nécessaires.
La classe App implémente la méthode UsingMarshaling qui exécute toutes les tâches nécessaires au passage du tableau. Le tableau est marqué avec le mot clé out (ByRef en Visual Basic) pour indiquer que les données passent de l'appelé vers l'appelant. L'implémentation utilise les méthodes de classe Marshal suivantes :
PtrToStructure pour marshaler des données à partir de la mémoire tampon non managée vers un objet managé.
DestroyStructure pour libérer la mémoire réservée aux chaînes dans la structure.
FreeCoTaskMem pour libérer la mémoire réservée au tableau.
Comme indiqué précédemment, C# autorise un code unsafe tandis que Visual Basic 2005 ne l'autorise pas. Dans l'exemple C#, UsingUnsafePointer est une autre implémentation de méthode qui utilise des pointeurs plutôt que la classe Marshal pour repasser le tableau contenant la structure MyUnsafeStruct.
Déclaration de prototypes
' 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);
}
// Declares a class member for each structure element.
[StructLayout(LayoutKind::Sequential, CharSet=CharSet::Ansi)]
public ref class MyStruct
{
public:
String^ buffer;
int size;
};
// Declares a structure with a pointer.
[StructLayout(LayoutKind::Sequential)]
public value struct MyUnsafeStruct
{
public:
IntPtr buffer;
int size;
};
public ref class LibWrap
{
public:
// Declares managed prototypes for the unmanaged function.
[DllImport("..\\LIB\\PInvokeLib.dll")]
static void TestOutArrayOfStructs(int% size,
IntPtr% outArray);
[DllImport("..\\LIB\\PInvokeLib.dll")]
static void TestOutArrayOfStructs(int% size,
MyUnsafeStruct** outArray);
};
Fonctions d'appel
Public Class App
Public Shared Sub Main()
Console.WriteLine( vbNewLine + "Using marshal class" + vbNewLine)
UsingMarshaling()
'Visual Basic 2005 cannot use unsafe code.
End Sub 'Main
Public Shared Sub UsingMarshaling()
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");
UsingMarshaling();
Console.WriteLine("\nUsing unsafe code\n");
UsingUnsafePointer();
}
public static void UsingMarshaling()
{
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 UsingUnsafePointer()
{
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);
}
}
public ref class App
{
public:
static void Main()
{
Console::WriteLine("\nUsing marshal class\n");
UsingMarshaling();
Console::WriteLine("\nUsing unsafe code\n");
UsingUnsafePointer();
}
static void UsingMarshaling()
{
int size;
IntPtr outArray;
LibWrap::TestOutArrayOfStructs(size, outArray);
array<MyStruct^>^ manArray = gcnew array<MyStruct^>(size);
IntPtr current = outArray;
for (int i = 0; i < size; i++)
{
manArray[i] = gcnew MyStruct();
Marshal::PtrToStructure(current, manArray[i]);
Marshal::DestroyStructure(current, MyStruct::typeid);
//current = (IntPtr)((long)current + Marshal::SizeOf(manArray[i]));
current = current + Marshal::SizeOf(manArray[i]);
Console::WriteLine("Element {0}: {1} {2}", i, manArray[i]->buffer,
manArray[i]->size);
}
Marshal::FreeCoTaskMem(outArray);
}
static void UsingUnsafePointer()
{
int size;
MyUnsafeStruct* pResult;
LibWrap::TestOutArrayOfStructs(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);
}
};
Voir aussi
Concepts
Marshaling de classes, de structures, et d'unions