Esempio di strutture
In questo esempio viene dimostrato come passare una struttura che punta a una seconda struttura, una struttura con una struttura incorporata e una struttura con una matrice incorporata.
Nell'esempio di strutture vengono utilizzate le seguenti funzioni non gestite, illustrate con le dichiarazioni di funzione originali:
TestStructInStruct esportata da PinvokeLib.dll.
int TestStructInStruct(MYPERSON2* pPerson2);
TestStructInStruct3 esportata da PinvokeLib.dll.
void TestStructInStruct3(MYPERSON3 person3);
TestArrayInStruct esportata da PinvokeLib.dll.
void TestArrayInStruct( MYARRAYSTRUCT* pStruct );
PinvokeLib.dll è una libreria non gestita personalizzata contenente implementazioni per le funzioni elencate in precedenza e quattro strutture, ovvero MYPERSON, MYPERSON2, MYPERSON3 e MYARRAYSTRUCT, le quali contengono i seguenti elementi:
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;
Le strutture gestite MyPerson, MyPerson2, MyPerson3 e MyArrayStruct hanno le seguenti caratteristiche:
MyPerson contiene solo membri stringa. Le stringhe vengono impostate sul formato ANSI dal campo CharSet, quando viene passato alla funzione non gestita.
MyPerson2 contiene un tipo IntPtr alla struttura MyPerson. Il tipo IntPtr sostituisce il puntatore originale alla struttura non gestita poiché nelle applicazioni .NET Framework non vengono utilizzati i puntatori a meno che il codice non sia contrassegnato come unsafe.
MyPerson3 contiene MyPerson come struttura incorporata. È possibile semplificare una struttura incorporata in un'altra struttura posizionandone gli elementi direttamente nella struttura principale oppure mantenerla incorporata, come accade in questo esempio.
MyArrayStruct contiene una matrice di integer. Il valore dell'enumerazione UnmanagedType viene impostato dall'attributo MarshalAsAttribute su ByValArray, che consente di indicare il numero di elementi nella matrice.
Per tutte le strutture di questo esempio, l'attributo StructLayoutAttribute viene applicato in modo che i membri vengano disposti in sequenza nella memoria, nell'ordine in cui appaiono.
La classe LibWrap contiene prototipi gestiti per i metodi TestStructInStruct, TestStructInStruct3 e TestArrayInStruct chiamati dalla classe App. Ciascun prototipo dichiara un singolo parametro, come indicato di seguito:
TestStructInStruct dichiara un riferimento al tipo MyPerson2 come parametro.
TestStructInStruct3 dichiara il tipo MyPerson3 come parametro e passa il parametro per valore.
TestArrayInStruct dichiara un riferimento al tipo MyArrayStruct come parametro.
Come argomenti per i metodi, le strutture vengono passate per valore a meno che il parametro non contenga la parola chiave ref (ByRef in Visual Basic). Ad esempio, il metodo TestStructInStruct passa un riferimento, ossia il valore di un indirizzo, a un oggetto di tipo MyPerson2 al codice non gestito. Per modificare la struttura alla quale punta MyPerson2, nell'esempio viene creato un buffer di dimensioni specificate e ne viene restituito l'indirizzo combinando i metodi Marshal.AllocCoTaskMem e Marshal.SizeOf. In seguito, il contenuto della struttura gestita viene copiato nel buffer non gestito. Infine, il metodo Marshal.PtrToStructure viene utilizzato per effettuare il marshalling dei dati dal buffer non gestito in un oggetto gestito, mentre il metodo Marshal.FreeCoTaskMem viene utilizzato per liberare il blocco di memoria non gestito.
Dichiarazione dei prototipi
' 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);
};
Chiamata delle funzioni
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]);
}
};
Vedere anche
Concetti
Marshalling di classi, strutture e unioni