Calificación:
  • 0 voto(s) - 0 Media
  • 1
  • 2
  • 3
  • 4
  • 5
[Tutorial] C# Invocación de la plataforma
#1


Tutorial de invocación de la plataforma
Visual Studio .NET 2003
Los servicios de invocación de plataforma (PInvoke) permiten llamar desde código administrado a funciones no administradas e implementadas en una DLL.

Este tutorial muestra todo lo necesario para poder llamar a funciones de DLL no administradas desde C#. Los atributos debatidos en el tutorial permiten llamar a esas funciones y realizar correctamente el cálculo de referencias para tipos de datos.

Archivos de ejemplo

Vea Ejemplo de invocación de la plataforma para descargar y generar los archivos de ejemplo que se utilizan en este tutorial.

Invocación de la plataforma

Información adicional

Una mirada detallada a la invocación de plataforma
Utilizar atributos
DllImportAttribute (Clase)
MarshalAsAttribute (Clase)
StructLayoutAttribute (Clase)
InAttribute (Clase)
OutAttribute (Clase)
Tutorial

Hay dos formas de llamar directamente a código no administrado desde código C#:

Llamar directamente a una función exportada desde una DLL.
Llamar a un método de interfaz en un objeto COM (para obtener más información, vea Interoperabilidad COM, parte 1: tutorial de clientes de C#).
Para ambas técnicas es necesario proporcionar al compilador de C# una declaración de la función no administrada; puede que también resulte necesario indicar una descripción de cómo realizar el cálculo de referencias de los parámetros y el valor devuelto al código no administrado y viceversa.

El tutorial se compone de los siguientes temas:

Llamar directamente desde C# a una exportación DLL
Cálculo de referencias predeterminado y especificación de cálculo de referencias personalizado para parámetros a métodos no administrados
Especificar un cálculo de referencias personalizado para estructuras definidas por el usuario
Registrar métodos de devolución de llamada
El tutorial incluye los siguientes ejemplos:

Ejemplo 1: utilizar DllImport
Ejemplo 2: reemplazar el cálculo de referencias predeterminado
Ejemplo 3: especificar un cálculo de referencias personalizado
Llamar directamente desde C# a una exportación DLL

Para declarar un método cuya implementación proceda de una exportación DLL, haga lo siguiente:

Declare el método con las palabras clave static y extern de C#.
Asocie el atributo DllImport al método. El atributo DllImport permite especificar el nombre de la DLL que contiene el método. Lo habitual es dar el mismo nombre al método de C# que al método exportado; si bien se puede usar también un nombre diferente para el método de C#.
Opcionalmente se puede especificar información personalizada de cálculo de referencias para los parámetros y valor devuelto del método, que reemplazará el cálculo de referencias predeterminado de .NET Framework.
Ejemplo 1

Este ejemplo muestra cómo usar el atributo DllImport para generar un mensaje y llamar a puts desde msvcrt.dll.

// PInvokeTest.cs
using System;
using System.Runtime.InteropServices;

class PlatformInvokeTest
{
[DllImport("msvcrt.dll")]
public static extern int puts(string c);
[DllImport("msvcrt.dll")]
internal static extern int _flushall();

public static void Main()
{
puts("Test");
_flushall();
}
}
Resultado

Test
Descripción del código

El ejemplo precedente muestra los requisitos mínimos para declarar un método de C# que se implementa en una DLL no administrada. El método PlatformInvokeTest.puts se declara con los modificadores static y extern y posee el atributo DllImport, que indica al compilador que la implementación procede de msvcrt.dll, usando el nombre predeterminado puts. Para poder usar un nombre diferente del método C# como putstring, se debe usar la opción EntryPoint en el atributo DllImport, es decir:

[DllImport("msvcrt.dll", EntryPoint="puts")]
Para obtener más información sobre la sintaxis del atributo DllImport, vea DllImportAttribute (Clase).

Cálculo de referencias predeterminado y especificación de cálculo de referencias personalizado para parámetros a métodos no administrados

Al llamar a una función no administrada desde código C#, Common Language Runtime debe realizar el cálculo de referencias de los parámetros y valores devueltos.

Por cada tipo de .NET Framework hay un tipo no administrado predeterminado, que Common Language usará para calcular las referencias en una llamada de función administrada a otra función no administrada. Por ejemplo, el cálculo de referencias predeterminado para los valores de cadena de C# es al tipo LPTSTR (puntero a un búfer de caracteres TCHAR). Se puede reemplazar el cálculo de referencias predeterminado utilizando el atributo MarshalAs en la declaración de C# de la función no administrada.

Ejemplo 2

Este ejemplo usa el atributo DllImport para generar una cadena. También muestra cómo reemplazar el cálculo de referencias predeterminado de los parámetros de función mediante el atributo MarshalAs.

// Marshal.cs
using System;
using System.Runtime.InteropServices;

class PlatformInvokeTest
{
[DllImport("msvcrt.dll")]
public static extern int puts(
[MarshalAs(UnmanagedType.LPStr)]
string m);
[DllImport("msvcrt.dll")]
internal static extern int _flushall();


public static void Main()
{
puts("Hello World!");
_flushall();
}
}
Resultado

Al ejecutar este ejemplo, la cadena

Hello World!
aparecerá en la consola.

Descripción del código

En el ejemplo precedente, el cálculo de referencias predeterminado del parámetro de la función puts queda reemplazado por el predeterminado de LPTSTR a LPSTR.

El atributo MarshalAs puede colocarse en parámetros de métodos, valores devueltos por métodos y campos de estructuras y clases. Para establecer el cálculo de referencias de un valor devuelto por un método, coloque el atributo MarshalAs en un bloque de atributos, en el método que contiene el reemplazo de la ubicación de atributo devuelta. Por ejemplo, para establecer el cálculo de referencias del valor devuelto del método puts:

...
[DllImport("msvcrt.dll")]
[return : MarshalAs(UnmanagedType.I4)]
public static extern int puts(
...
Para obtener más información sobre la sintaxis del atributo MarshalAs, vea MarshalAsAttribute (Clase).

Nota Los métodos In y Out pueden usarse para anotar parámetros de métodos no administrados. Se comportan de manera similar a los modificadores in y out en archivos de código fuente MIDL. Observe que el atributo Out es diferente del modificador de parámetro de C# out. Para obtener más información sobre los atributos In y Out, vea InAttribute (Clase) y OutAttribute (Clase).
Especificar un cálculo de referencias personalizado para estructuras definidas por el usuario

Es posible especificar atributos de cálculo de referencias personalizados para campos de estructuras y clases pasados a o desde funciones no administradas. Para ello, se agregan atributos MarshalAs a los campos de la estructura o clase. También se debe utilizar el atributo StructLayout para establecer el diseño de la estructura, para controlar (opcionalmente) el cálculo de referencias predeterminado de los miembros de cadena y para establecer el tamaño predeterminado de empaquetado.

Ejemplo 3

Este ejemplo muestra cómo especificar atributos de cálculo de referencias personalizados para una estructura.

Considere la siguiente estructura en C:

typedef struct tagLOGFONT
{
LONG lfHeight;
LONG lfWidth;
LONG lfEscapement;
LONG lfOrientation;
LONG lfWeight;
BYTE lfItalic;
BYTE lfUnderline;
BYTE lfStrikeOut;
BYTE lfCharSet;
BYTE lfOutPrecision;
BYTE lfClipPrecision;
BYTE lfQuality;
BYTE lfPitchAndFamily;
TCHAR lfFaceName[LF_FACESIZE];
} LOGFONT;
En C# se puede describir la estructura precedente usando los atributos StructLayout y MarshalAs como sigue:

// logfont.cs
// compile with: /target:module
using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public class LOGFONT
{
public const int LF_FACESIZE = 32;
public int lfHeight;
public int lfWidth;
public int lfEscapement;
public int lfOrientation;
public int lfWeight;
public byte lfItalic;
public byte lfUnderline;
public byte lfStrikeOut;
public byte lfCharSet;
public byte lfOutPrecision;
public byte lfClipPrecision;
public byte lfQuality;
public byte lfPitchAndFamily;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=LF_FACESIZE)]
public string lfFaceName;
}
Para obtener más información sobre la sintaxis del atributo StructLayout, vea StructLayoutAttribute (Clase).

A continuación puede utilizarse la estructura en código de C# como se muestra a continuación:

// pinvoke.cs
// compile with: /addmodule:logfont.netmodule
using System;
using System.Runtime.InteropServices;

class PlatformInvokeTest
{
[DllImport("gdi32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr CreateFontIndirect(
[In, MarshalAs(UnmanagedType.LPStruct)]
LOGFONT lplf // characteristics
);

[DllImport("gdi32.dll")]
public static extern bool DeleteObject(
IntPtr handle
);

public static void Main()
{
LOGFONT lf = new LOGFONT();
lf.lfHeight = 9;
lf.lfFaceName = "Arial";
IntPtr handle = CreateFontIndirect(lf);

if (IntPtr.Zero == handle)
{
Console.WriteLine("Can't creates a logical font.");
}
else
{

if (IntPtr.Size == 4)
Console.WriteLine("{0:X}", handle.ToInt32());
else
Console.WriteLine("{0:X}", handle.ToInt64());

// Delete the logical font created.
if (!DeleteObject(handle))
Console.WriteLine("Can't delete the logical font");
}
}
}
Ejecución de ejemplo

C30A0AE5
Descripción del código

En el ejemplo precedente, el método CreateFontIndirect utiliza un parámetro del tipo LOGFONT. Los atributos MarshalAs e In se utilizan para calificar el parámetro. El programa muestra el valor numérico devuelto por el método como una cadena hexadecimal en mayúsculas.

Registrar métodos de devolución de llamada

Para registrar una devolución de llamada administrada que llama a una función no administrada, declare un delegado con la misma lista de argumentos y pase una instancia de él a través de PInvoke. En la parte no administrada aparecerá como un puntero a función. Para obtener más información sobre PInvoke y la devolución de llamada, vea Una mirada detallada a la invocación de plataforma.

Por ejemplo, considere la siguiente función no administrada, MyFunction, que requiere la devolución de llamada como uno de sus argumentos:

typedef void (__stdcall *PFN_MYCALLBACK)();
int __stdcall MyFunction(PFN_ MYCALLBACK callback);
Para llamar a MyFunction desde código no administrado, declare el delegado, asocie DllImport a la declaración de función y, opcionalmente, haga el cálculo de referencias de los parámetros existentes o del valor devuelto:

public delegate void MyCallback();
[DllImport("MYDLL.DLL")]
public static extern void MyFunction(MyCallback callback);
Asimismo, asegúrese de que la duración de la instancia de delegado abarca la duración del código no administrado; de lo contrario, el delegado no estará disponible después de la recolección de elementos no utilizados.


Posibles temas similares...
Tema Autor Respuestas Vistas Último mensaje
  Mejor plataforma para un AulaVirtual xvvrsoftware 4 230 04-10-2016, 06:47 AM
Último mensaje: garcon
Información [Tutorial] Certificado SSL Gratis StartSSL 2016 Tutorial DarkMaster 26 5,109 28-04-2016, 03:39 AM
Último mensaje: Lob3zNo
Bombilla [Tutorial] SSL Gratis, Conseguir e Instalar Certificado DarkMaster 16 871 06-01-2016, 01:32 AM
Último mensaje: DarkMaster
  [PUBLICO] Tutorial Botones con perspectiva 3D AngelKrak 0 234 17-01-2015, 05:44 AM
Último mensaje: AngelKrak
  Paiza.io plataforma web para programar jlgarduza 0 248 23-11-2014, 06:22 AM
Último mensaje: jlgarduza
  Quiero hacer un proyecto ayuda con la plataforma TeraByte 16 818 28-02-2014, 10:54 AM
Último mensaje: aperpen
  [Tutorial] Aumentar el Tamaño Máximo al Cargar Archivos con PHP y Apache papanoel 0 668 22-01-2014, 04:38 AM
Último mensaje: papanoel
  Tutorial Css Primera Parte para phpost JNeutron 4 1,052 24-02-2013, 04:01 AM
Último mensaje: Echizen
  [TUTORIAL] Conexión a una Base de Datos desde [PHP] lapipichapa 0 491 15-02-2013, 05:52 PM
Último mensaje: lapipichapa
  Tutorial de .htaccess | Control de acceso a carpetas diringax 11 1,453 13-01-2013, 12:28 PM
Último mensaje: papi



Usuarios navegando en este tema: 1 invitado(s)