Ejemplo Structs
Actualización: noviembre 2007
En este ejemplo se muestra cómo pasar una estructura que apunta a una segunda estructura, cómo pasar una estructura con otra estructura incrustada y cómo pasar una estructura con una matriz incrustada.
El código fuente de los ejemplos de código siguientes lo proporciona el Ejemplo de tecnología de invocación de plataformas de .NET Framework.
En el ejemplo Structs se utilizan las siguientes funciones no administradas, que se muestran con su declaración de función original:
TestStructInStruct exportada desde PinvokeLib.dll.
int TestStructInStruct(MYPERSON2* pPerson2);
TestStructInStruct3 exportada desde PinvokeLib.dll.
void TestStructInStruct3(MYPERSON3 person3);
TestArrayInStruct exportada desde PinvokeLib.dll.
void TestArrayInStruct( MYARRAYSTRUCT* pStruct );
PinvokeLib.dll es una biblioteca personalizada no administrada que contiene implementaciones para las funciones enumeradas anteriormente y cuatro estructuras: MYPERSON, MYPERSON2, MYPERSON3 y MYARRAYSTRUCT. Estas estructuras contienen los siguientes elementos:
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;
Las estructuras administradas MyPerson, MyPerson2, MyPerson3 y MyArrayStruct tienen las características siguientes:
MyPerson sólo contiene miembros de cadena. El campo CharSet establece las cadenas a formato ANSI cuando se pasan a la función no administrada.
MyPerson2 contiene un puntero IntPtr a la estructura MyPerson. El tipo IntPtr reemplaza el puntero original a la estructura no administrada porque las aplicaciones de .NET Framework no utilizan punteros a menos que el código tenga la marca unsafe.
MyPerson3 contiene MyPerson como una estructura incrustada. Una estructura incrustada en otra estructura se puede simplificar mediante la colocación de los elementos de la estructura incrustada directamente en la estructura principal o se puede dejar como estructura incrustada, como en este ejemplo.
MyArrayStruct contiene una matriz de enteros. El atributo MarshalAsAttribute establece el valor de la enumeración UnmanagedType en ByValArray, que se utiliza para indicar el número de elementos de la matriz.
En todas las estructuras de este ejemplo, el atributo StructLayoutAttribute se aplica para asegurar que los miembros se organizan en la memoria de forma secuencial, en el orden en que aparecen.
La clase LibWrap contiene prototipos administrados para los métodos TestStructInStruct, TestStructInStruct3 y TestArrayInStruct a los que se llama desde la clase App. Cada prototipo declara un único parámetro, de la forma siguiente:
TestStructInStruct declara una referencia al tipo MyPerson2 como su parámetro.
TestStructInStruct3 declara el tipo MyPerson3 como su parámetro y pasa el parámetro por valor.
TestArrayInStruct declara una referencia al tipo MyArrayStruct como su parámetro.
Las estructuras pasadas como argumentos de los métodos se pasan por valor a menos que el parámetro contenga la palabra clave ref (ByRef en Visual Basic). Por ejemplo, el método TestStructInStruct pasa una referencia (el valor de una dirección) a un objeto de tipo MyPerson2 al código no administrado. Para tratar la estructura a la que apunta MyPerson2, en el ejemplo se crea un búfer del tamaño especificado y se devuelve su dirección mediante la combinación de los métodos Marshal.AllocCoTaskMem y Marshal.SizeOf. A continuación, se copia el contenido de la estructura administrada en el búfer no administrado. Por último, se utiliza el método Marshal.PtrToStructure para calcular las referencias de los datos desde el búfer no administrado a un objeto administrado y el método Marshal.FreeCoTaskMem para liberar el bloque de memoria no administrado.
Declaración de prototipos
' 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 );
}
Llamadas a funciones
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 = "Evens"
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( ControlChars.CrLf & "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( ControlChars.CrLf & "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 = "Evens";
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 ] );
}
}
Vea también
Conceptos
Calcular referencias de clases, estructuras y uniones