Beispiel für Strukturen
Dieses Beispiel demonstriert die Übergabe einer Struktur, die auf eine zweite Struktur zeigt, die Übergabe einer Struktur mit einer eingebetteten Struktur sowie die Übergabe einer Struktur mit einem eingebetteten Array.
Das Beispiel für Strukturen verwendet die folgenden nicht verwalteten Funktionen, die jeweils zusammen mit ihrer ursprünglichen Funktionsdeklaration aufgeführt werden:
TestStructInStruct aus PinvokeLib.dll exportiert.
int TestStructInStruct(MYPERSON2* pPerson2);
TestStructInStruct3 aus PinvokeLib.dll exportiert.
void TestStructInStruct3(MYPERSON3 person3);
TestArrayInStruct aus PinvokeLib.dll exportiert.
void TestArrayInStruct( MYARRAYSTRUCT* pStruct );
PinvokeLib.dll ist eine benutzerdefinierte, nicht verwaltete Bibliothek, die Implementierungen für die zuvor aufgelisteten Funktionen und vier Strukturen (MYPERSON, MYPERSON2, MYPERSON3 und MYARRAYSTRUCT) enthält. Diese Strukturen enthalten die folgenden Elemente:
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;
Die verwalteten Strukturen MyPerson, MyPerson2, MyPerson3 und MyArrayStruct besitzen das folgende Merkmal:
MyPerson enthält nur Zeichenfolgenmember. Das CharSet-Feld legt für die Zeichenfolgen bei Übergabe an die nicht verwaltete Funktion das ANSI-Format fest.
MyPerson2 enthält einen Zeiger vom Typ IntPtr auf die MyPerson-Struktur. Der IntPtr-Typ ersetzt den ursprünglichen Zeiger auf die nicht verwaltete Struktur, da .NET Framework-Anwendungen nur Zeiger verwenden, wenn der Code als unsafe gekennzeichnet ist.
MyPerson3 enthält MyPerson als eingebettete Struktur. Eine in eine andere Struktur eingebettete Struktur kann vereinfacht werden, indem die Elemente der eingebetteten Struktur direkt in der Hauptstruktur platziert werden, oder sie kann als eingebettete Struktur beibehalten werden (dies ist in diesem Beispiel der Fall).
MyArrayStruct enthält ein Array von Ganzzahlen. Das MarshalAsAttribute-Attribut legt für den UnmanagedType-Enumerationswert ByValArray fest. Damit wird die Anzahl der Elemente im Array angezeigt.
Für alle Strukturen in diesem Beispiel wird durch Verwendung des StructLayoutAttribute-Attributs sichergestellt, dass die Member im Speicher sequenziell in der Reihenfolge ihres Erscheinens angeordnet sind.
Die LibWrap-Klasse enthält verwaltete Prototypen für die von der App-Klasse aufgerufenen Methoden TestStructInStruct, TestStructInStruct3 und TestArrayInStruct. Jeder Prototyp deklariert, wie im Folgenden erläutert, einen einzigen Parameter:
TestStructInStruct deklariert als Parameter einen Verweis auf Typ MyPerson2.
TestStructInStruct3 deklariert als Parameter den Typ MyPerson3 und übergibt den Parameter durch einen Wert.
TestArrayInStruct deklariert als Parameter einen Verweis auf Typ MyArrayStruct.
Strukturen als Argumente für Methoden werden durch einen Wert übergeben, vorausgesetzt, der Parameter enthält nicht das Schlüsselwort ref (ByRef in Visual Basic). Die TestStructInStruct-Methode übergibt z. B. einen Verweis auf ein Objekt vom Typ MyPerson2 (den Wert einer Adresse) an nicht verwalteten Code. Um die Struktur zu verändern, auf die MyPerson2 zeigt, erstellt das Beispiel einen Puffer einer angegebenen Größe und gibt seine Adresse durch Kombination der Methoden Marshal.AllocCoTaskMem und Marshal.SizeOf zurück. Als nächstes wird im Beispiel der Inhalt der verwalteten Struktur in den nicht verwalteten Puffer kopiert. Zuletzt verwendet das Beispiel die Marshal.PtrToStructure-Methode, um Daten vom nicht verwalteten Puffer in ein verwaltetes Objekt zu marshallen, sowie die Marshal.FreeCoTaskMem-Methode, um den nicht verwalteten Speicherblock freizugeben.
Deklarieren von Prototypen
' 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);
};
Aufrufen von Funktionen
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]);
}
};
Siehe auch
Konzepte
Marshallen von Klassen, Strukturen und Unions