Unions, exemple
Cet exemple montre comment passer des structures contenant uniquement des types valeur et comment passer des structures contenant un type valeur et une chaîne comme paramètres vers une fonction non managée nécessitant une union. Une union représente un emplacement de mémoire qui peut être partagé par deux ou plusieurs variables.
L'exemple Unions utilise la fonction non managée suivante, illustrée avec sa déclaration de fonction d'origine :
TestUnion exportée à partir de PinvokeLib.dll.
void TestUnion(MYUNION u, int type);
PinvokeLib.dll est une bibliothèque non managée personnalisée qui contient une implémentation pour les fonctions précédemment répertoriées et deux unions, MYUNION et MYUNION2. Ces unions contiennent les éléments suivants :
union MYUNION
{
int number;
double d;
}
union MYUNION2
{
int i;
char str[128];
};
Dans du code managé, les unions sont définies comme structures. La structure MyUnion contient deux types valeur comme membres : un entier et un double. L'attribut StructLayoutAttribute est défini pour contrôler la position précise de chaque donnée membre. L'attribut FieldOffsetAttributefournit la position physique des champs au sein de la représentation non managée d'une union. Remarquez que ces deux membres possèdent les mêmes valeurs offset, les membres peuvent ainsi définir la même zone de la mémoire.
MyUnion2_1 et MyUnion2_2 contiennent respectivement un type valeur (entier) et une chaîne. Dans du code managé, les types valeur et les types référence ne peuvent pas se chevaucher. Cet exemple utilise la surcharge de méthode afin de permettre à l'appelant d'utiliser les deux types lors de l'appel de la même fonction non managée. La disposition de MyUnion2_1 est explicite et possède une valeur offset précise. En revanche, MyUnion2_2 possède une disposition séquentielle car les dispositions explicites ne sont pas autorisées avec les types référence. L'attribut MarshalAsAttribute affecte à l'énumération UnmanagedType la valeur ByValTStr, qui est utilisée pour identifier les tableaux de caractères de longueur fixe inline qui apparaissent au sein de la représentation non managée de l'union.
La classe LibWrap contient les prototypes pour les méthodes TestUnion et TestUnion2. TestUnion2 est surchargé pour déclarer MyUnion2_1 ou MyUnion2_2 en tant que paramètres.
Déclaration de prototypes
' Declares managed structures instead of unions.
<StructLayout(LayoutKind.Explicit)> _
Public Structure MyUnion
<FieldOffset(0)> Public i As Integer
<FieldOffset(0)> Public d As Double
End Structure 'MyUnion
<StructLayout(LayoutKind.Explicit, Size := 128)> _
Public Structure MyUnion2_1
<FieldOffset(0)> Public i As Integer
End Structure 'MyUnion2_1
<StructLayout(LayoutKind.Sequential)> _
Public Structure MyUnion2_2
<MarshalAs(UnmanagedType.ByValTStr, SizeConst := 128)> _
Public str As String
End Structure 'MyUnion2_2
Public Class LibWrap
' Declares managed prototypes for unmanaged function.
Declare Sub TestUnion Lib "..\LIB\PinvokeLib.dll" ( _
ByVal u As MyUnion, ByVal type As Integer)
Overloads Declare Sub TestUnion2 Lib "..\LIB\PinvokeLib.dll" ( _
ByVal u As MyUnion2_1, ByVal type As Integer)
Overloads Declare Sub TestUnion2 Lib "..\LIB\PinvokeLib.dll" ( _
ByVal u As MyUnion2_2, ByVal type As Integer)
End Class 'LibWrap
// Declares managed structures instead of unions.
[StructLayout(LayoutKind.Explicit)]
public struct MyUnion
{
[FieldOffset(0)]
public int i;
[FieldOffset(0)]
public double d;
}
[StructLayout(LayoutKind.Explicit, Size=128)]
public struct MyUnion2_1
{
[FieldOffset(0)]
public int i;
}
[StructLayout(LayoutKind.Sequential)]
public struct MyUnion2_2
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]
public string str;
}
public class LibWrap
{
// Declares managed prototypes for unmanaged function.
[DllImport( "..\\LIB\\PInvokeLib.dll")]
public static extern void TestUnion(MyUnion u, int type);
[DllImport( "..\\LIB\\PInvokeLib.dll")]
public static extern void TestUnion2(MyUnion2_1 u, int type);
[DllImport( "..\\LIB\\PInvokeLib.dll")]
public static extern void TestUnion2(MyUnion2_2 u, int type);
}
// Declares managed structures instead of unions.
[StructLayout(LayoutKind::Explicit)]
public value struct MyUnion
{
public:
[FieldOffset(0)]
int i;
[FieldOffset(0)]
double d;
};
[StructLayout(LayoutKind::Explicit, Size=128)]
public value struct MyUnion2_1
{
public:
[FieldOffset(0)]
int i;
};
[StructLayout(LayoutKind::Sequential)]
public value struct MyUnion2_2
{
public:
[MarshalAs(UnmanagedType::ByValTStr, SizeConst=128)]
String^ str;
};
public ref class LibWrap
{
public:
// Declares managed prototypes for unmanaged function.
[DllImport("..\\LIB\\PInvokeLib.dll")]
static void TestUnion(MyUnion u, int type);
[DllImport("..\\LIB\\PInvokeLib.dll")]
static void TestUnion2(MyUnion2_1 u, int type);
[DllImport("..\\LIB\\PInvokeLib.dll")]
static void TestUnion2(MyUnion2_2 u, int type);
};
Fonctions d'appel
Public Class App
Public Shared Sub Main()
Dim mu As New MyUnion()
mu.i = 99
LibWrap.TestUnion(mu, 1)
mu.d = 99.99
LibWrap.TestUnion(mu, 2)
Dim mu2_1 As New MyUnion2_1()
mu2_1.i = 99
LibWrap.TestUnion2(mu2_1, 1)
Dim mu2_2 As New MyUnion2_2()
mu2_2.str = "*** string ***"
LibWrap.TestUnion2(mu2_2, 2)
End Sub 'Main
End Class 'App
public class App
{
public static void Main()
{
MyUnion mu = new MyUnion();
mu.i = 99;
LibWrap.TestUnion(mu, 1);
mu.d = 99.99;
LibWrap.TestUnion(mu, 2);
MyUnion2_1 mu2_1 = new MyUnion2_1();
mu2_1.i = 99;
LibWrap.TestUnion2(mu2_1, 1);
MyUnion2_2 mu2_2 = new MyUnion2_2();
mu2_2.str = "*** string ***";
LibWrap.TestUnion2(mu2_2, 2);
}
}
public ref class App
{
public:
static void Main()
{
MyUnion mu;// = new MyUnion();
mu.i = 99;
LibWrap::TestUnion(mu, 1);
mu.d = 99.99;
LibWrap::TestUnion(mu, 2);
MyUnion2_1 mu2_1;// = new MyUnion2_1();
mu2_1.i = 99;
LibWrap::TestUnion2(mu2_1, 1);
MyUnion2_2 mu2_2;// = new MyUnion2_2();
mu2_2.str = "*** string ***";
LibWrap::TestUnion2(mu2_2, 2);
}
};
Voir aussi
Concepts
Marshaling de classes, de structures, et d'unions