Nota del autor

Si la entrada que estás leyendo carece de imágenes, no se ve el vídeo que teóricamente lleva incrustado o el código fuente mostrado aparece sin formato, podéis conocer los motivos aquí. Poco a poco iré restableciendo la normalidad en el blog.
Este blog es un archivo de los artículos situados previamente en Lobosoft.es y ha dejado de ser actualizado. Las nuevas entradas pueden encontrarse en www.lobosoft.es. Un saludo,
Lobosoft.

sábado, 19 de abril de 2008

Usando código no manejado desde .NET (con C#)

Una de las situaciones con las que me he encontrado habitualmente en el trabajo, particularmente cuando lo hacía con autómatas y, especialmente, con entornos y lenguajes de programación diversos, era la necesidad de comunicar los diversos procesos, que podían ser aplicaciones completas (y complejas), con una funcionalidad específica e independiente, pero que trabajando en conjunto permitían obtener más beneficios para el usuario. Esto es particularmente cierto, y muy usado, en entornos UNIX, donde cientos de pequeñas (a la par que potentes) aplicaciones interactúan entre sí para permitir incluso la programación de scripts mediante los diversos lenguajes de shell que incorporan.

Sin embargo, hay ocasiones en las que las aplicaciones no han sido pensadas para facilitar este uso, y sus salidas y entradas pueden ser de lo más diversas: stdin/stdout, ficheros de texto o binarios, grabación en bases de datos, uso de sockets, etc. En estos casos, o bien tenemos acceso al código fuente y podemos establecer algún vínculo de comunicación específico, o debemos ingeniárnoslas como mejor podamos para comunicar estos procesos. Si es posible.

Recientemente me encontré en la tesitura de usar aplicaciones desarrolladas en diversos lenguajes (C, C++…) desde .NET Framework. Aunque podría tratarse de ejecutables como tales, lo ideal en este caso, de cara a una futura integración con .NET y ante la imposibilidad de reciclar a todo el personal, el equipo material, etc., lo ideal era reconvertir estas aplicaciones en otras "huecas" que usasen la funcionalidad actual a través de su compilación como librerías DLL, e implementar las futuras que se desarrollasen también mediante DLLs. Sin embargo, aún me encontraba con un pequeño problema. ¿Cómo usar dichas librerías desde .NET? Por un lado, habría que tener en cuenta que las librerías .DLL de .NET Framework no son iguales a las .DLL "de toda la vida", sino que contienen código para ser ejecutado por el CLR. Sin embargo, las .DLLs de C, por ejemplo, contienen código no manejado, que es ejecutado directamente por el sistema operativo, y no por una máquina virtual, como ocurre en .NET o Java. Esto es posible mediante el uso de las librerías que aporta el propio sistema operativo, como veremos a continuación.

Usando una .DLL creada en C, desde C#

El modo más sencillo de usar una librería de C desde .NET es, sin duda, importarla en la compilación de nuestro código. Esto lo conseguimos mediante el atributo [DllImport()], en el que indicaremos la DLL a cargar. Posteriormente declararemos las funciones que deseamos usar de la misma, y listo. Por ejemplo, imaginemos el siguiente código C:int

[c]Sum(int a, int b)
{
return a+b;
}[/c]

Una función que toma dos números enteros, y devuelve el resultado. Para probarlo, creamos un proyecto vacío de Visual C++, de tipo librería DLL, y creamos un archivo con dicha función. Añadimos un fichero de definición del módulo (.def), y le agregamos las líneas:

LIBRARY "c_math_lib"
EXPORTS
Sum


Mediante las mismas, declaramos el nombre de la librería así como las funciones que pone a disposición de sus usuarios (en cierto modo, las que son públicas). Compilamos en modo Release para obtener la librería.

Creamos ahora otra solución (aunque el anterior podría ser un proyecto dentro de la misma) de consola en Visual C#, e incluimos la DLL generada anteriormente.

[csharp]namespace Lobosoft.UsoDLLNoManejadas
{
///
/// Entrada al programa.
/// Usa la librería mediante una importación en tiempo de compilación
///

class Program
{
static void Main(string[] args)
{
[DllImport("c_math_lib.dll")]
static extern int Sum(int a, int b);

int resultado, operando;
resultado = 0;

for (int i = 0; i < args.Length; i++)
{
int.TryParse(args[i], out operando);
resultado = Sum(resultado, operando);
}
Console.WriteLine("El resultado de la operación es " + resultado);
}
}[/csharp]

El atributo DllImport indica a Visual Studio que importe la librería en tiempo de compilación, de modo que reservará la memoria y permitirá usar la función Sum declarada como externa. El programa simplemente recuperará los valores que se pasen como argumentos en la ejecución del programa, irá sumándolos, y devolverá el resultado por pantalla.

suma1.PNG



Puede verse que es bastante simple hacer uso de código no manejado en .NET, aunque surgen otras dudas, como, por ejemplo, cómo cargar dinámicamente una DLL, en tiempo de ejecución o cómo conocer qué funciones pone a nuestra disposición. Esto lo veremos en sucesivos artículos.

1 comentario: