Beispiel zu Unions

Dieses Beispiel demonstriert die Übergabe von Strukturen, die nur Werttypen enthalten, sowie von Strukturen, die einen Werttyp und eine Zeichenfolge als Parameter enthalten, an eine nicht verwaltete Funktion, die eine Union erwartet. Eine Union stellt einen Speicherbereich dar, der von zwei oder mehreren Variablen gemeinsam verwendet werden kann.

Das Beispiel für Unions verwendet die folgende nicht verwaltete Funktion, die zusammen mit ihrer ursprünglichen Funktionsdeklaration aufgeführt wird:

  • TestUnion aus PinvokeLib.dll exportiert.

    void TestUnion(MYUNION u, int type);
    

PinvokeLib.dll ist eine benutzerdefinierte, nicht verwaltete Bibliothek, die eine Implementierung für die zuvor aufgelistete Funktion und zwei Unions (MYUNION und MYUNION2) enthält. Diese Unions enthalten die folgenden Elemente:

union MYUNION
{
    int number;
    double d;
}

union MYUNION2
{
    int i;
    char str[128];
};

In verwaltetem Code sind Unions als Strukturen definiert. Die MyUnion-Struktur enthält zwei Werttypen als Member: integer und double. Das StructLayoutAttribute-Attribut wird so festgelegt, dass es die genaue Position der einzelnen Datenmember steuert. Das FieldOffsetAttribute-Attribut gibt die physische Position von Feldern innerhalb der nicht verwalteten Darstellung einer Union an. Beide Member haben dieselben Offsetwerte, wodurch sie denselben Speicherbereich definieren können.

MyUnion2_1 und MyUnion2_2 enthalten einen Werttyp (integer) bzw. eine Zeichenfolge. In verwaltetem Code dürfen Werttypen und Referenztypen einander nicht überlappen. In diesem Beispiel wird dem Aufrufer durch das Überladen von Methoden ermöglicht, beim Aufruf derselben nicht verwalteten Funktion beide Typen zu verwenden. Das Layout von MyUnion2_1 ist explizit und besitzt einen genauen Offsetwert. Das Layout von MyUnion2_2 hingegen ist sequenziell, da explizite Layouts im Zusammenhang mit Referenztypen nicht zulässig sind. Das MarshalAsAttribute-Attribut legt die UnmanagedType-Enumeration auf ByValTStr fest. Dieser Wert wird zum Identifizieren der Inlinearrays fester Länge verwendet, die innerhalb der nicht verwalteten Darstellung der Union erscheinen.

Die LibWrap-Klasse enthält die Prototypen für die TestUnion-Methode und die TestUnion2-Methode. TestUnion2 ist zum Deklarieren von MyUnion2_1 oder MyUnion2_2 als Parametern überladen.

Deklarieren von Prototypen

' 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);
};

Aufrufen von Funktionen

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);
    }
};

Siehe auch

Konzepte

Marshallen von Klassen, Strukturen und Unions

Datentypen für den Plattformaufruf

Erstellen von Prototypen in verwaltetem Code