Invocación a código nativo. Problemas de portabilidad básica
De Mono Hispano
Contents |
¿Qué es P/Invoke?
Platform Invocation Services es un servicio ofrecido por los runtimes que implementan CLI que permite realizar llamadas a funciones nativas contenidas en librerías dinámicas.
Llamada a una función contenida en una dll nativa
Supongamos que queremos utilizar una función nativa contenida en una librería dinámica.
Por ejemplo es usual que antiguos usuarios de C quieran usar las funciones estandar de dicho lenguaje. int atoi(char*) es un ejemplo de una función en C que dada una cadena la converte a un entero.
Creamos una función con el prototipo de la función y las marcamos con los modificadores extern y static. Por defecto, el runtime buscará en tiempo de ejecución en dicha librería una función con el mismo nombre y con un prototipo que coincida. En el caso de encontrarnos en un Sistema Unix la invocación sería la siguiente:
using System;
using System.Runtime.InteropServices;
class SampleClass
{
[DllImport("libc")]
public extern static int atoi(string value);
static void Main()
{
Console.WriteLine(atoi("4")*2);
}
}
NOTA: en windows, la funcionalidad estandar de C se encuentra en la librería dinámica msvcrt.dll9
Factores importantes cuando usamos P/Invoke
• La naturaleza de la función: tipos de parámetros y saber si son de entrada, entrada/salida o salida, tipo del retorno. Para tipos básicos suele haber una traducción directa(por ejemplo C/C#: int->Int32, void->Void, char*->String...), sin embargo para tipos mas complejos como clases y estructuras debe haber un tratamiento más específico y complejo.
• Ya que una librería dinámica no es mas que código nativo que se va a cargar en tiempo de ejecución es importante saber como fue compilada, por ejemplo los compiladores de C por defecto siguen la convención cdecl y esta misma es la que toma por defecto DllImport, por eso cualquier función compilada con esta convención funcionará sin problemas.
• En qué sistema operativo se encuentra la función que queremos usar.
Por ejemplo: las funciones estándar de c pueden encontrarse(además de en stdlib.lib) en la biblioteca dinámica msvcrt.dll Microsoft visual c runtime) en Windows o libc.so en linux
Problemas de portabilidad
Unos de los problemas principales en la invocación a codigo nativo es la portabilidad. El runtime puede ofrecernos en tiempo de ejecución sobre que sistema operativo está ejecutándose, por lo tanto, una posible solución si se cuenta con una librería nativa en diferentes sistemas operativos. En este caso queremos usar la función atoi, estándar de C en dos Sistemas operativos distintos: WindowsXP y Linux:
using System;
using System.Runtime.InteropServices;
class SampleClass
{
[DllImport("msvcrt", EntryPoint = "atoi")]
public extern static int WNTatoi(string value);
[DllImport("libc",EntryPoint="atoi")]
public extern static int UNIXatoi(string value);
static void Main()
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT)
Console.WriteLine("atoi from WINNT SO:"+WNTatoi("4") * 2);
else if (Environment.OSVersion.Platform == PlatformID.Unix)
Console.WriteLine("atoi from UNIX SO:" + UNIXatoi("4") * 2);
}
}
Nota: este código solo podría ser compilado en la versión 2.0 del estándar para c# y su BCL ya que en versiones anteriores la enumeración PlataformID no contiene el valor UNIX
Por lo tanto nuestro programa sería totalmente portable, por ejemplo probemos compilar csc(microsoft C Shap Compiler) sobre Windows y probarlo, posteriormente llevar el ejecutable a Linux y ejecutarlo con Mono:
D:\>csc Program.cs Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.42 for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727 Copyright (C) Microsoft Corporation 2001-2005. All rights reserved. D:\>Program.exe atoi from WINNT SO:8 //el mismo archivo compilado con csc de microsoft ejecutado en linux y mono como runtime root@GeuSubuntu:/ # mono Program.exe atoi from UNIX SO:8
Autor: Pablo Iñigo Blasco

Powered by MediaWiki