Structures, exemple
Cet exemple montre comment passer une structure qui pointe vers une deuxième structure, comment passer une structure avec une structure incorporée et comment passer une structure avec un tableau incorporé.
L'exemple Structs utilise les fonctions non managées suivantes, illustrées avec leur déclaration de fonction d'origine :
TestStructInStruct exportée à partir de PinvokeLib.dll.
int TestStructInStruct(MYPERSON2* pPerson2);
TestStructInStruct3 exportée à partir de PinvokeLib.dll.
void TestStructInStruct3(MYPERSON3 person3);
TestArrayInStruct exportée à partir de PinvokeLib.dll.
void TestArrayInStruct( MYARRAYSTRUCT* pStruct );
PinvokeLib.dll est une bibliothèque non managée personnalisée qui contient des implémentations pour les fonctions précédemment répertoriées et quatre structures : MYPERSON, MYPERSON2, MYPERSON3, et MYARRAYSTRUCT. Ces structures contiennent les éléments suivants :
typedef struct _MYPERSON
{
char* first;
char* last;
} MYPERSON, *LP_MYPERSON;
typedef struct _MYPERSON2
{
MYPERSON* person;
int age;
} MYPERSON2, *LP_MYPERSON2;
typedef struct _MYPERSON3
{
MYPERSON person;
int age;
} MYPERSON3;
typedef struct _MYARRAYSTRUCT
{
bool flag;
int vals[ 3 ];
} MYARRAYSTRUCT;
Les structures managées MyPerson, MyPerson2, MyPerson3, et MyArrayStruct possèdent les caractéristiques suivantes :
MyPerson ne contient que des membres de type chaîne. Le champ CharSet définit les chaînes au format ANSI lorsqu'elles sont passées à la fonction non managée.
MyPerson2 contient un IntPtr vers la structure MyPerson. Le type IntPtr remplace le pointeur d'origine vers la structure non managée car les applications .NET Framework n'utilisent pas de pointeurs sauf si le code est marqué unsafe.
MyPerson3 contient MyPerson comme structure incorporée. Une structure incorporée au sein d'une autre structure peut être aplatie en plaçant les éléments de la structure incorporée directement dans la structure principale. Cette structure peut également rester comme structure incorporée comme c'est le cas dans cet exemple.
MyArrayStruct contient un tableau d'entiers. L'attribut MarshalAsAttribute affecte à l'énumération UnmanagedType la valeur ByValArray, qui est utilisée pour indiquer le nombre d'éléments dans le tableau.
Pour toutes les structures dans cet exemple, l'attribut StructLayoutAttribute est appliqué afin de garantir que les membres sont disposés en mémoire de manière séquentielle, dans l'ordre de leur apparition.
La classe LibWrap contient des prototypes managés pour les méthodes TestStructInStruct, TestStructInStruct3, et TestArrayInStruct qui sont appelées par la classe App. Chaque prototype déclare un seul paramètre comme suit :
TestStructInStruct déclare une référence au type MyPerson2 comme son paramètre.
TestStructInStruct3 déclare le type MyPerson3 comme son paramètre et passe le paramètre par valeur.
TestArrayInStruct déclare une référence au type MyArrayStruct comme son paramètre.
Des structures comme arguments aux méthodes sont passées par valeur sauf si le paramètre contient le mot clé ref (ByRef en Visual Basic). Par exemple, la méthode TestStructInStruct passe une référence (la valeur d'une adresse) à un objet de type MyPerson2 vers du code non managé. Pour manipuler la structure vers laquelle pointe MyPerson2, l'exemple crée une mémoire tampon d'une taille spécifiée et retourne son adresse en combinant les méthodes Marshal.AllocCoTaskMem et Marshal.SizeOf. Puis, l'exemple copie le contenu de la structure managée vers la mémoire tampon non managée. Enfin, l'exemple utilise la méthode Marshal.PtrToStructure pour marshaler des données à partir de la mémoire tampon non managée vers un objet managé et la méthode Marshal.FreeCoTaskMem pour libérer le bloc non managé de mémoire.
Déclaration de prototypes
' Declares a managed structure for each unmanaged structure.
<StructLayout(LayoutKind.Sequential, CharSet := CharSet.Ansi)> _
Public Structure MyPerson
Public first As String
Public last As String
End Structure 'MyPerson
<StructLayout(LayoutKind.Sequential)> _
Public Structure MyPerson2
Public person As IntPtr
Public age As Integer
End Structure 'MyPerson2
<StructLayout(LayoutKind.Sequential)> _
Public Structure MyPerson3
Public person As MyPerson
Public age As Integer
End Structure 'MyPerson3
<StructLayout(LayoutKind.Sequential)> _
Public Structure MyArrayStruct
Public flag As Boolean
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=3)> _
Public vals As Integer()
End Structure 'MyArrayStruct
Public Class LibWrap
' Declares managed prototypes for unmanaged functions.
Declare Function TestStructInStruct Lib "..\LIB\PinvokeLib.dll" ( _
ByRef person2 As MyPerson2) As Integer
Declare Function TestStructInStruct3 Lib "..\LIB\PinvokeLib.dll" ( _
ByVal person3 As MyPerson3) As Integer
Declare Function TestArrayInStruct Lib "..\LIB\PinvokeLib.dll" ( _
ByRef myStruct As MyArrayStruct) As Integer
End Class 'LibWrap
// Declares a managed structure for each unmanaged structure.
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
public struct MyPerson
{
public string first;
public string last;
}
[StructLayout(LayoutKind.Sequential)]
public struct MyPerson2
{
public IntPtr person;
public int age;
}
[StructLayout(LayoutKind.Sequential)]
public struct MyPerson3
{
public MyPerson person;
public int age;
}
[StructLayout(LayoutKind.Sequential)]
public struct MyArrayStruct
{
public bool flag;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=3)]
public int[] vals;
}
public class LibWrap
{
// Declares a managed prototype for unmanaged function.
[DllImport("..\\LIB\\PinvokeLib.dll")]
public static extern int TestStructInStruct(ref MyPerson2 person2);
[DllImport("..\\LIB\\PinvokeLib.dll")]
public static extern int TestStructInStruct3(MyPerson3 person3);
[DllImport("..\\LIB\\PinvokeLib.dll")]
public static extern int TestArrayInStruct(ref MyArrayStruct myStruct);
}
// Declares a managed structure for each unmanaged structure.
[StructLayout(LayoutKind::Sequential, CharSet=CharSet::Ansi)]
public value struct MyPerson
{
public:
String^ first;
String^ last;
};
[StructLayout(LayoutKind::Sequential)]
public value struct MyPerson2
{
public:
IntPtr person;
int age;
};
[StructLayout(LayoutKind::Sequential)]
public value struct MyPerson3
{
public:
MyPerson person;
int age;
};
[StructLayout(LayoutKind::Sequential)]
public value struct MyArrayStruct
{
public:
bool flag;
[MarshalAs(UnmanagedType::ByValArray, SizeConst=3)]
array<int>^ vals;
};
public ref class LibWrap
{
public:
// Declares a managed prototype for unmanaged function.
[DllImport("..\\LIB\\PinvokeLib.dll")]
static int TestStructInStruct(MyPerson2% person2);
[DllImport("..\\LIB\\PinvokeLib.dll")]
static int TestStructInStruct3(MyPerson3 person3);
[DllImport("..\\LIB\\PinvokeLib.dll")]
static int TestArrayInStruct(MyArrayStruct% myStruct);
};
Fonctions d'appel
Public Class App
Public Shared Sub Main()
' Structure with a pointer to another structure.
Dim personName As MyPerson
personName.first = "Mark"
personName.last = "Lee"
Dim personAll As MyPerson2
personAll.age = 30
Dim buffer As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf( _
personName))
Marshal.StructureToPtr(personName, buffer, False)
personAll.person = buffer
Console.WriteLine(ControlChars.CrLf & "Person before call:")
Console.WriteLine("first = {0}, last = {1}, age = {2}", _
personName.first, personName.last, personAll.age)
Dim res As Integer = LibWrap.TestStructInStruct(personAll)
Dim personRes As MyPerson = _
CType(Marshal.PtrToStructure(personAll.person, _
GetType(MyPerson)), MyPerson)
Marshal.FreeCoTaskMem(buffer)
Console.WriteLine("Person after call:")
Console.WriteLine("first = {0}, last = {1}, age = {2}", _
personRes.first, _
personRes.last, personAll.age)
' Structure with an embedded structure.
Dim person3 As New MyPerson3()
person3.person.first = "John"
person3.person.last = "Evans"
person3.age = 27
LibWrap.TestStructInStruct3(person3)
' Structure with an embedded array.
Dim myStruct As New MyArrayStruct()
myStruct.flag = False
Dim array(2) As Integer
myStruct.vals = array
myStruct.vals(0) = 1
myStruct.vals(1) = 4
myStruct.vals(2) = 9
Console.WriteLine(vbNewLine + "Structure with array before call:")
Console.WriteLine(myStruct.flag)
Console.WriteLine("{0} {1} {2}", myStruct.vals(0), _
myStruct.vals(1), myStruct.vals(2))
LibWrap.TestArrayInStruct(myStruct)
Console.WriteLine(vbNewLine + "Structure with array after call:")
Console.WriteLine(myStruct.flag)
Console.WriteLine("{0} {1} {2}", myStruct.vals(0), _
myStruct.vals(1), myStruct.vals(2))
End Sub 'Main
End Class 'App
public class App
{
public static void Main()
{
// Structure with a pointer to another structure.
MyPerson personName;
personName.first = "Mark";
personName.last = "Lee";
MyPerson2 personAll;
personAll.age = 30;
IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(personName));
Marshal.StructureToPtr(personName, buffer, false);
personAll.person = buffer;
Console.WriteLine("\nPerson before call:");
Console.WriteLine("first = {0}, last = {1}, age = {2}",
personName.first, personName.last, personAll.age);
int res = LibWrap.TestStructInStruct(ref personAll);
MyPerson personRes =
(MyPerson)Marshal.PtrToStructure(personAll.person,
typeof(MyPerson));
Marshal.FreeCoTaskMem(buffer);
Console.WriteLine("Person after call:");
Console.WriteLine("first = {0}, last = {1}, age = {2}",
personRes.first, personRes.last, personAll.age);
// Structure with an embedded structure.
MyPerson3 person3 = new MyPerson3();
person3.person.first = "John";
person3.person.last = "Evans";
person3.age = 27;
LibWrap.TestStructInStruct3(person3);
// Structure with an embedded array.
MyArrayStruct myStruct = new MyArrayStruct();
myStruct.flag = false;
myStruct.vals = new int[3];
myStruct.vals[0] = 1;
myStruct.vals[1] = 4;
myStruct.vals[2] = 9;
Console.WriteLine("\nStructure with array before call:");
Console.WriteLine(myStruct.flag);
Console.WriteLine("{0} {1} {2}", myStruct.vals[0],
myStruct.vals[1], myStruct.vals[2]);
LibWrap.TestArrayInStruct(ref myStruct);
Console.WriteLine("\nStructure with array after call:");
Console.WriteLine(myStruct.flag);
Console.WriteLine("{0} {1} {2}", myStruct.vals[0],
myStruct.vals[1], myStruct.vals[2]);
}
}
public ref class App
{
public:
static void Main()
{
// Structure with a pointer to another structure.
MyPerson personName;
personName.first = "Mark";
personName.last = "Lee";
MyPerson2 personAll;
personAll.age = 30;
IntPtr buffer = Marshal::AllocCoTaskMem(Marshal::SizeOf(personName));
Marshal::StructureToPtr(personName, buffer, false);
personAll.person = buffer;
Console::WriteLine("\nPerson before call:");
Console::WriteLine("first = {0}, last = {1}, age = {2}",
personName.first, personName.last, personAll.age);
int res = LibWrap::TestStructInStruct(personAll);
MyPerson personRes =
(MyPerson)Marshal::PtrToStructure(personAll.person,
MyPerson::typeid);
Marshal::FreeCoTaskMem(buffer);
Console::WriteLine("Person after call:");
Console::WriteLine("first = {0}, last = {1}, age = {2}",
personRes.first, personRes.last, personAll.age);
// Structure with an embedded structure.
MyPerson3 person3;// = gcnew MyPerson3();
person3.person.first = "John";
person3.person.last = "Evans";
person3.age = 27;
LibWrap::TestStructInStruct3(person3);
// Structure with an embedded array.
MyArrayStruct myStruct;// = new MyArrayStruct();
myStruct.flag = false;
myStruct.vals = gcnew array<int>(3);
myStruct.vals[0] = 1;
myStruct.vals[1] = 4;
myStruct.vals[2] = 9;
Console::WriteLine("\nStructure with array before call:");
Console::WriteLine(myStruct.flag);
Console::WriteLine("{0} {1} {2}", myStruct.vals[0],
myStruct.vals[1], myStruct.vals[2]);
LibWrap::TestArrayInStruct(myStruct);
Console::WriteLine("\nStructure with array after call:");
Console::WriteLine(myStruct.flag);
Console::WriteLine("{0} {1} {2}", myStruct.vals[0],
myStruct.vals[1], myStruct.vals[2]);
}
};
Voir aussi
Concepts
Marshaling de classes, de structures, et d'unions