Explorador de Librerías basado en .NET

Por Angel J. Hernández M.

Descarga Descargar Ejemplo de este artículo.

Contenido

 1. Introducción
 2. Librerías, librerías, ... Y más librerías
 3. Reflexiones sobre Reflection
 4. Aplicación de ejemplo (Visor.exe)
 5. Conclusión

 

1. Introducción

Hace un par de meses estuve lidiando con una librería de enlace dinámico (DLL) que conseguí en un CD de información respaldada; pensé que, quizás, a juzgar por el nombre del archivo, me podría ser útil. Sin embargo, no tenía idea si ésta exponía una función que yo necesitaba en ese preciso momento. Recordé una característica que tenía Windows 95: QuickView. Esta característica me mostraba el encabezado de los archivos junto a cierta información técnica en el caso de que se tratara de un archivo binario, y una "vista preliminar" del mismo, cuando el archivo no era binario (por ejemplo, una imagen de mapa de bits). Lo interesante de QuickView es que estaba ligado al Shell del Sistema Operativo (Windows Explorer) con lo que un solo clic me permitía visualizar toda esta información del archivo seleccionado. Dicen que la necesidad es la madre de toda invención; pues bien, me dije a mí mismo: "... Sería interesante tener algo similar a QuickView, que me permitiera revisar el contenido de una DLL sin importar si es nativa, COM ó .NET ...". El siguiente artículo trata justamente de esto: una aplicación que hace uso del .NET Framework y el SDK de la plataforma para tal fin; además, se muestra cómo podemos crear una solución que no esté basada en un solo lenguaje de programación. Sin más preámbulos, comencemos ...

 

2. Librerías, librerías, ... Y más librerías

Desde siempre, los desarrolladores han deseado crear código reutilizable; desde los días del DOS, cuando existían los archivos OVL, hasta el advenimiento de Windows y sus librerías de enlace dinámico (DLL). Aunque existan muchos archivos con la misma extensión, no necesariamente son del mismo tipo ya que pueden estar basados en tecnologías distintas. La siguiente sección menciona algunas de las diferencias existentes entre ellos.

DLL Win32 (Código Nativo)

Una DLL es código generalmente escrito en C ó C++, que reúne ciertas características y los parámetros del enlazador (Linker) son distintos que si fuera un .EXE común. Hay dos maneras que yo, como desarrollador, puedo beneficiarme de ellas:

  • Enlace dinámico en tiempo de carga (Load-Time Dynamic Linking)

    Es la manera como generalmente se utiliza una librería, por cuestiones de facilidad y practicidad. Se agrega la referencia de un archivo LIB al proyecto; el compilador valida los símbolos (funciones) importados en el proyecto proveniente desde la librería. El enlazador, al generar el archivo, también agrega referencias a las funciones que se hayan utilizado así como la dirección de memoria en donde éstas se cargan.

  • Enlace dinámico en tiempo de ejecución (Run-Time Dynamic Linking)

    En este caso es totalmente dinámico, pues sucede en tiempo de ejecución. Se carga la librería con LoadLibrary o LoadLibraryEx. Se ejecuta el punto de entrada de todo DLL que es la función DLLMain. Tanto LoadLibrary como LoadLibraryEx devuelven un handle si es que fue exitoso, entonces se debe obtener la dirección del proceso de la librería a través de la función GetProcAddress, que toma como primer parámetro el handle antes mencionado y se obtiene un puntero a una función o Callback, que utilizaremos para llamar la función en la cual estamos interesados. Después de utilizar la función liberamos la librería a través de FreeLibrary.

A continuación se muestra el código que utilizamos para crear la DLL:

DLLEjemplo.h (Archivo de cabecera) Ver Figura 1:

Bb972279.art279-img01-374x220(es-es,MSDN.10).gif
Figura 1. Volver al texto.

DLLEjemplo.cpp (Implementación de DLLEjemplo.h) Ver Figura 2:

Bb972279.art279-img02-570x506(es-es,MSDN.10).gif
Figura 2. Volver al texto.

Callback utilizado para llamar las funciones exportadas (Ver Figura 3):

Bb972279.art279-img03-259x22(es-es,MSDN.10).gif
Figura 3. Volver al texto.

Llamada de las funciones exportadas (Ver Figura 4):

Bb972279.art279-img04-570x315(es-es,MSDN.10).gif
Figura 4. Volver al texto.

Una vez que ejecutamos la aplicación (ProbadorDLL.exe) podemos observar los resultados que devuelve en este caso la función Suma (Ver Figura 5):

Bb972279.art279-img05-570x288(es-es,MSDN.10).gif
Figura 5. Volver al texto.

DLL COM (Component Object Model)

Existe otro tipo de librería, sin embargo se la conoce también como biblioteca de tipos o biblioteca de clases, la cual está basadas en COM. Inicialmente eran conocidas con el nombre de Servidores de Automatización (OLE Automation Servers). COM (Component Object Model) ha estado con nosotros desde 1993, creado por la necesidad de composición dinámica de software y para solucionar algunos de los problemas encontradas con las librerías nativas, como los son el manejo de versiones y las llamadas a procedimientos remotos (RPC). COM se fundamenta en la implementación de interfaces; en C son estructuras typedefs sin herencia, y en C++ son declaradas como estructuras, pero con herencia, que son implementadas por las clases. En C++ cada clase al menos tiene una función virtual, por lo tanto las clases tienen una VTable (Tabla Virtual). A continuación se muestra un ejemplo:

struct IAnimal {
    virtual void Comer() = 0;
    virtual void Dormir() = 0;
    virtual void Caminar(int pasos) = 0; 
}
 
class CPerro: public IAnimal {
    protected:
       int _patas;
       int _ojos;
       char* _color;
 
    public:
       virtual void Comer();
       virtual void Dormir();
       virtual void Caminar(int pasos);
};

Todos los componentes implementan la interfaz IUnknown, la cual posee el método QueryInterface. IUnknown permite a los clientes obtener punteros de un objeto dado a través del método mencionado, además del manejo de las referencias del objeto mediante los métodos AddRef y Release. En la aplicación que mostramos más adelante (Visor.exe) hacemos uso de la función LoadTypeLibEx para determinar si una DLL seleccionada es COM.

Conocer los detalles y el funcionamiento interno de COM es complejo, y este artículo no pretende adentrarse tanto en dicho tema. Sin embargo, existen muchos recursos e información en línea en donde puedes profundizar más al respecto.

Otro punto importante a saber es que COM no está limitado sólo a desarrolladores C++, pues se pueden crear librerías en VB, Visual FoxPro, Delphi y otros. Las librerías COM muestran su funcionalidad al exponer sus interfaces; por ello los componentes nunca llegan a "tocarse" o interactuar completamente. Esto es debido en parte al proceso de traducir los tipos de datos de un entorno a otro (por ejemplo, una cadena en VB no ocupa lo mismo en C++, y viceversa). Al proceso de interpretar un tipo de dato en otro se le conoce como Marshaling.

En el caso de .net, es otra historia. Todos tenemos en claro que existen el CLR, el CTS y los fabricantes de compiladores deben regirse por las reglas del CLS, por lo cual los objetos sí llegan a "tocarse" porque los tipos de datos son los mismos y ocupan la misma memoria sin importar el lenguaje en el que se esté desarrollando.

DLL .NET (Biblioteca de Clases)

Una biblioteca de clases de .net es una colección de clases definidas por el usuario, así como de interfaces y estructuras que están basadas o utilizan otras clases del .net Framework. Se diferencian de un archivo ejecutable pues éstas no tienen un punto de entrada principal o función Main y que los parámetros pasados al enlazador son diferentes.

 

3. Reflexiones sobre Reflection

Reflection... ¿Qué es eso? Intentaré explicar en esta sección de qué trata esta característica de .net. Como es bien sabido, el CLR se encarga de administrar los dominios de aplicación (appdomains). Esta administración incluye la carga de cada ensamblaje dentro del dominio de aplicación apropiado y controla la distribución de memoria de la jerarquía de tipos dentro de cada ensamblaje. Los ensamblajes contienen módulos que a su vez contienen tipos y éstos contienen miembros. Reflection provee objetos que encapsulan ensamblajes, módulos y tipos. Así, de esta manera, se puede crear dinámicamente una instancia de un tipo, enlazar el tipo a un objeto existente o simplemente obtener el tipo de un objeto existente. Uno de los usos más comunes de Reflection es la obtención de información de tipos en tiempo de ejecución tal como se demuestra en la aplicación de ejemplo (Hay otras tecnologías que se benefician de Reflection; una de ellas, y que goza de gran publicidad actualmente, es la implementación de AJAX [Asyncronous Javascript And Xml] para ASP .net).

 

4. Aplicación de ejemplo (Visor.exe)

La aplicación de ejemplo, además de demostrar la interoperabilidad existente entre los distintos lenguajes que se utilizaron para la solución (C#, C++ y VB .net), hace uso de algunas funciones del API de depuración del SDK, además de... Reflection. La solución está conformada por 6 (seis) proyectos, que detallamos a continuación (Ver Figura 6):

Bb972279.art279-img06-318x160(es-es,MSDN.10).gif
Figura 6. Volver al texto.

  • DLLEjemplo (Basado en Visual C++)

    Biblioteca de enlace dinámico que exporta 4 (cuatro) funciones matemáticas (Suma, Resta, Multiplicación y División). Es cargada dinámicamente desde el proyecto ProbadorDLL.

  • ProbadorDLL (Basado en Visual C++)

    Aplicación basada en consola que carga dinámicamente a DLLEjemplo.

  • SoporteCodigoGestionado (Basado en Visual C#)

    Biblioteca de clases encargada de recuperar información de las bibliotecas del tipo (COM) u otra biblioteca de clases (.net). Hace uso de Reflection para dicho propósito. La información recuperada del archivo seleccionado es almacenada en un DataSet que posteriormente es utilizado para llenar la vista de árbol (Treeview) de la aplicación Visor. El DataSet contiene 8 (ocho) DataTables las cuales a su vez contienen información acerca de espacios de nombres, clases, interfaces, propiedades, métodos, eventos, delegados, enumeraciones, estructuras y constructores. Estos DataTables están relacionados de manera jerárquica; es decir, Espacio de Nombre -> Clase ó Interfaz -> Miembros.

  • SoporteCodigoNativo (Basado en Visual C++)

    Biblioteca de clases (extensiones de VC++ para .net). Encargado de recuperar información de las bibliotecas de enlace dinámico (nativo) a través de funciones de depuración del SDK.

  • SoporteCOM (Basado en VB .net)

    Biblioteca de clases encargada de convertir una biblioteca de tipos (COM) en un ensamblaje de .net en tiempo de ejecución.

  • Visor (Basado en VB .net)

    Aplicación Windows que sirve de interfaz al "Explorador de Librerías". Implementa los proyectos de SoporteCodigoGestionado, SoporteCodigoNativo y SoporteCOM. Soporta arrastrar y colocar (Drag 'n Drop) de bibliotecas de enlace dinámico (Nativo, COM y .net). Se hace uso de GDI+ para dibujar los resultados obtenidos después de analizar un DLL (nativo) y una vista de árbol que muestra de manera jerárquica la información de la biblioteca de clases (.net) o biblioteca de tipos (COM).

La Figura 7 muestra la interfaz de la aplicación "Visor.exe" cuando es seleccionada una biblioteca de enlace dinámico (nativo); en este caso es el archivo "DLLEjemplo.dll". Nota que los símbolos (funciones) exportados son los mencionados en el artículo (Suma, Resta, Multiplicación y División) así como la dirección en memoria en donde éstos son cargados:

Bb972279.art279-img07-570x447(es-es,MSDN.10).gif
Figura 7. Volver al texto.

La aplicación "Visor.exe" puede diferenciar el tipo de archivo (biblioteca de enlace dinámico) seleccionado, como se muestra en la Figura 8 . La información mostrada corresponde a una biblioteca de clases (.net); obsérvese cómo se llena el árbol así como el resumen mostrado en la parte inferior de la ventana. El archivo seleccionado es "consein.clases.dll":

Bb972279.art279-img08-552x570(es-es,MSDN.10).gif
Figura 8. Volver al texto.

 

5. Conclusión

Este artículo sólo muestra una pequeña parte de lo que podemos conseguir y lograr a través de Interop y Reflection. La tecnología .net nos ofrece un vasto conjunto de herramientas que nos permiten desarrollar aplicaciones dinámicas y seguras, además de auto-descriptivas, pues toda la información viaja con el ensamblaje y la metadata del mismo. Hoy en día una organización puede beneficiarse de .net sin necesidad de obligar o forzar a su equipo de desarrollo a aprender un nuevo lenguaje, sino que pueden utilizar el que ya conozcan, siempre y cuando cumpla con las reglas del CLS y CTS. La programación multihilo no es exclusiva para desarrolladores C++ sino para todos aquellos que quieran implementarla con .net.

Andy González es International Program Manager en Microsoft. Es responsable por la calidad de las herramientas de desarrollo en Latinoamérica y España. Sus productos incluyen Visual Studio, Visual Studio Team System, .NET Framework y Visual Studio Tools for the Office System.