stringtranslate.com

Servicios de invocación de plataforma

Los servicios de invocación de plataforma , comúnmente conocidos como P/Invoke , son una característica de las implementaciones de Common Language Infrastructure , como Common Language Runtime de Microsoft , que permite que el código administrado llame al código nativo .

El código administrado, como C# o VB.NET, proporciona acceso nativo a clases, métodos y tipos definidos dentro de las bibliotecas que componen .NET Framework. Si bien .NET Framework proporciona un amplio conjunto de funciones, es posible que no tenga acceso a muchas bibliotecas del sistema operativo de nivel inferior normalmente escritas en código no administrado o bibliotecas de terceros también escritas en código no administrado. P/Invoke es la técnica que un programador puede utilizar para acceder a funciones en estas bibliotecas. Las llamadas a funciones dentro de estas bibliotecas se producen declarando la firma de la función no administrada dentro del código administrado, que sirve como la función real que se puede llamar como cualquier otro método administrado. La declaración hace referencia a la ruta del archivo de la biblioteca y define los parámetros de función y el retorno en los tipos administrados que es más probable que Common Language Run-time (CLR) calcule implícitamente hacia y desde los tipos no administrados. Cuando los tipos de datos no administrados se vuelven demasiado complejos para una simple conversión implícita desde y hacia tipos administrados, el marco permite al usuario definir atributos en la función, el retorno y/o los parámetros para refinar explícitamente cómo se deben ordenar los datos para que no dar lugar a excepciones al intentar hacerlo implícitamente.

Hay muchas abstracciones de conceptos de programación de nivel inferior disponibles para los programadores de código administrado en comparación con la programación en lenguajes no administrados. Como resultado, un programador con experiencia únicamente en código administrado necesitará repasar conceptos de programación como punteros, estructuras y paso por referencia para superar algunos de los obstáculos en el uso de P/Invoke.

Arquitectura

Descripción general

Dos variantes de P/Invoke actualmente en uso son:

Explícito

Implícito

Detalles

Cuando se utiliza P/Invoke, CLR maneja la carga de DLL y la conversión de los tipos anteriores no administrados a tipos CTS (también conocido como clasificación de parámetros ). [1] [ cita necesaria ] Para realizar esto, el CLR :

P/Invoke es útil para usar DLL estándar (no administradas) de C o C++ . Puede usarse cuando un programador necesita tener acceso a la extensa API de Windows , ya que muchas funciones proporcionadas por las bibliotecas de Windows carecen de contenedores disponibles . Cuando .NET Framework no expone una API Win32, el contenedor de esta API debe escribirse manualmente.

Escollos

Escribir contenedores P/Invoke puede ser difícil y propenso a errores. El uso de DLL nativas significa que el programador ya no puede beneficiarse de la seguridad de tipos y la recolección de basura como se proporciona normalmente en el entorno .NET. Cuando se usan incorrectamente esto puede causar problemas como fallas de segmentación o pérdidas de memoria . Obtener las firmas exactas de las funciones heredadas para su uso en el entorno .NET puede resultar difícil, lo que puede provocar este tipo de problemas. Para ello existen herramientas y sitios web para obtener dichas firmas, lo que ayuda a prevenir problemas de firma. [1]

Otros peligros incluyen:

Cuando se utiliza C++/CLI, el CIL emitido es libre de interactuar con objetos ubicados en el montón administrado y simultáneamente con cualquier ubicación de memoria nativa direccionable. Un objeto residente del montón administrado puede llamarse, modificarse o construirse mediante el simple "objeto->campo"; notación para asignar valores o especificar llamadas a métodos. Se obtienen importantes ganancias de rendimiento al eliminar cualquier cambio de contexto innecesario y se reducen los requisitos de memoria (pilas más cortas).

Esto viene con nuevos desafíos:

Estas referencias especifican soluciones para cada uno de estos problemas, si se encuentran. Un beneficio principal es la eliminación de la declaración de estructura, el orden de la declaración de campos y los problemas de alineación no están presentes en el contexto de C++ Interop.

Ejemplos

Ejemplos básicos

Este primer ejemplo simple muestra cómo obtener la versión de una DLL en particular :

Firma de la función DllGetVersion en la API de Windows :

HRESULT DllGetVersion ( DLLVERSIONINFO * pdvi )   

P/Invocar código C# para invocar la función DllGetVersion :

[StructLayout(LayoutKind.Sequential)] estructura privada DLLVERSIONINFO { public int cbSize ; público int dwMajorVersion ; público int dwMinorVersion ; público int dwBuildNumber ; público int dwPlatformID ; } [DllImport("shell32.dll")] static extern int DllGetVersion ( ref DLLVERSIONINFO pdvi );                       

El segundo ejemplo muestra cómo extraer un icono en un archivo:

Firma de la función ExtractIcon en la API de Windows:

HICON ExtractIcon ( HINSTANCE hInst , LPCTSTR lpszExeFileName , UINT nIconIndex );        

P/Invocar código C# para invocar la función ExtractIcon :

[DllImport("shell32.dll")] IntPtr ExtractIcon externo estático ( IntPtr hInst , [MarshalAs(UnmanagedType.LPStr)] cadena lpszExeFileName , uint nIconIndex );            

El siguiente ejemplo complejo muestra cómo compartir un evento entre dos procesos en la plataforma Windows :

Firma de la función CreateEvent :

 HANDLE CreateEvent ( LPSECURITY_ATTRIBUTES lpEventAttributes , BOOL bManualReset , BOOL bInitialState , LPCTSTR lpName );          

P/Invocar código C# para invocar la función CreateEvent :

[DllImport("kernel32.dll", SetLastError=true)] externo estático IntPtr CreateEvent ( IntPtr lpEventAttributes , bool bManualReset , bool bInitialState , [MarshalAs(UnmanagedType.LPStr)] cadena lpName );              

Un ejemplo más complejo

// declaración nativa typedef struct _PAIR { DWORD Val1 ; DWORDVal2 ;} PAR , * PPPAR ;          
// Compilado con /clr; el uso de #pragma administrado/no administrado puede generar un doble procesamiento; // evitarlo mediante el uso de un .cpp independiente con .h include. // Esto estaría ubicado en un archivo .h.plantilla <> inline CLR_PAIR ^ marshal_as < CLR_PAIR ^ , PAIR > ( const PAIR & Src ) { // Tenga en cuenta el uso de des/referenciación. Debe coincidir con su uso. CLR_PAIR ^ Destino = gcnew CLR_PAIR ; Destino -> Val1 = Origen . Val1 ; Destino -> Val2 = Origen . Val2 ; devolver destino ; };                
CLR_PAIR ^ mgd_pair1 ; CLR_PAIR ^ mgd_pair2 ; PAR nativo0 , * nativo1 =& nativo0 ;   nativo0 = NativeCallGetRefToMemory ();  // Usando marshal_as. Tiene sentido para tipos grandes o de uso frecuente. mgd_pair1 = marshal_as < CLR_PAIR ^> ( * nativo1 );  // Uso directo del campo mgd_pair2 -> Val1 = Native0 . Val1 ; mgd_pair2 -> val2 = nativo0 . val2 ;    retorno ( mgd_pair1 ); // Regresar a C# 

Herramientas

Hay una serie de herramientas diseñadas para ayudar en la producción de firmas P/Invoke.

Escribir una aplicación de utilidad que importe archivos de encabezado C++ y archivos DLL nativos y produzca un ensamblaje de interfaz automáticamente resulta bastante difícil. El principal problema al producir un importador/exportador de este tipo para firmas P/Invoke es la ambigüedad de algunos tipos de parámetros de llamada a funciones de C++.

Brad Abrams tiene esto que decir sobre el tema: [4]

El problema radica en funciones de C++ como las siguientes:

__declspec ( dllexport ) void MyFunction ( char * params );   

¿Qué tipo debemos usar para los parámetros en nuestra firma P/Invoke? Esto podría ser una cadena terminada en nulo de C++, o podría ser una matriz de caracteres o podría ser un parámetro de caracteres de salida . Entonces, ¿deberíamos usar string , StringBuilder , char [] o ref char  ?

Independientemente de este problema, existen algunas herramientas disponibles para simplificar la producción de firmas P/Invoke.

Una de las herramientas que se enumeran a continuación, xInterop C++ .NET Bridge, resolvió este problema implementando múltiples anulaciones del mismo método C++ en el mundo .NET, los desarrolladores pueden elegir el correcto para realizar la llamada.

PInvoke.net

PInvoke.net es una wiki que contiene firmas P/Invoke para una gran cantidad de API estándar de Windows. Es propiedad de Redgate Software y tiene alrededor de 50.000 visitas al mes.

Las firmas son producidas manualmente por los usuarios de la wiki. Se pueden buscar utilizando un complemento gratuito para Microsoft Visual Studio .

PInvoker

PInvoker es una aplicación que importa archivos DLL nativos y archivos .h de C++ y exporta archivos DLL de interoperabilidad P/Invoke compilados y completamente formados . Supera el problema de la ambigüedad envolviendo los parámetros de la función de puntero nativo en clases de interfaz .NET específicas de PInvoker. En lugar de utilizar tipos de parámetros .NET estándar en las definiciones de métodos P/Invoke ( char[] , string , etc.), utiliza estas clases de interfaz en las llamadas a funciones P/Invoke.

Por ejemplo, si consideramos el código de ejemplo anterior, PInvoker produciría una función .NET P/Invoke que acepta una clase de interfaz .NET que envuelve el puntero char * nativo . La construcción de esta clase podría ser a partir de una cadena o de una matriz char [] . La estructura de memoria nativa real para ambos es la misma, pero los respectivos constructores de clases de interfaz para cada tipo llenarán la memoria de diferentes maneras. Por lo tanto, la responsabilidad de decidir qué tipo de .NET debe pasarse a la función recae en el desarrollador.

Asistente de interoperabilidad de Microsoft

Microsoft Interop Assistant es una herramienta gratuita disponible con binarios y código fuente disponibles para descargar en CodePlex . Tiene la licencia pública limitada de Microsoft (Ms-LPL).

Tiene dos partes:

Debido a que esta herramienta produce código fuente C# en lugar de un dll compilado, el usuario es libre de realizar los cambios necesarios en el código antes de su uso. Por lo tanto, el problema de ambigüedad se resuelve cuando la aplicación elige un tipo .NET particular para usarlo en la firma del método P/Invoke y, si es necesario, el usuario puede cambiarlo al tipo requerido.

P/Asistente de invocación

El Asistente P/Invoke utiliza un método similar al Asistente de interoperabilidad de Microsoft en el sentido de que acepta código de archivo .h C++ nativo y produce código C# (o VB.NET) para que usted lo pegue en el código de su aplicación .NET.

También tiene opciones para el marco al que desea apuntar: .NET Framework para el escritorio o .NET Compact Framework para dispositivos inteligentes Windows Mobile (y Windows CE).

Puente xInterop C++ .NET

xInterop C++ .NET Bridge es una aplicación de Windows para crear un contenedor C# para archivos DLL nativos de C++ y un puente C++ para acceder a ensamblados .NET. Viene con una biblioteca C#/.NET que encapsula las clases estándar de C++, como string, iostream, etc. , Se puede acceder a clases y objetos de C++ desde .NET.

Esta herramienta genera archivos DLL de contenedor de C# con código fuente de archivos DLL de C++ nativos existentes y los archivos de encabezado asociados que requiere la herramienta para crear un archivo DLL de contenedor de C#. La aplicación genera las firmas P/Invoke y la clasificación de datos. El contenedor de C# resultante tiene una interfaz similar a la de C++ con el tipo de parámetro convertido al código .NET.

Esta herramienta reconoce clases de plantilla que no se exportan desde la DLL de C++ y crea una instancia de la clase de plantilla y la exporta en una DLL complementaria y la interfaz C++ correspondiente se puede usar en .NET.

Ver también

Referencias

  1. ^ La clasificación de parámetros no debe confundirse con el término general clasificación , que significa serialización . Los parámetros ordenados se copian en la pila CLR después de su conversión a tipos CTS , pero no se serializan.
  2. ^ "Doble procesamiento (C++)".
  3. ^ "Inicialización de Montajes Mixtos".
  4. ^ "El problema de PInvoke". aprender.microsoft.com . 6 de febrero de 2004.

enlaces externos