lunes, 25 de junio de 2007

Paquetes de C++ Builder

EliuX [aorozco@infomed.sld.cu]

Los paquetes son archivos que contienen datos binarios y recursos, listos para ser usados por una aplicación cliente, igual que las DLLs y los ensamblados de .NET. Éstos son incluso cargados y linkeados tanto dinámica cómo estáticamente. Ustedes se preguntarán: ¿entonces cuál es la diferencia entre una DLL y un paquete?

Para empezar, las DLLs se cargan con la función del API de Windows LoadLibrary; los inits son ejecutados por orden de prioridad y por orden de linkeo. Los datos y funciones de las DLLs se importan usando __declspec(dllimport) (muy pocas veces usado) o __import, y se exportan con __export.
Los paquetes, por su parte, se cargan con LoadPackage y los inits procesados, al revés del orden de dependencia de units, por orden de linkeo y por el de prioridad. Las funciones y los datos de los paquetes son exportados e importados usando __declspec(package).

Bueno, éstas son leves diferencias técnicas inherentes al uso de nuevas tecnologías, considerando principalmente que los paquetes BPL son propios del C++ Builder. Pero la principal diferencia entre los paquetes y las DLLs radica a la hora de linkear dinámicamente los BPI:

  • Las entradas inits no son copiadas dentro de una tabla init como en las DLLs, sino en un __PackageInfoTable que la función LoadPackage() sabe leer.
  • Al final de los BPL se agregan recursos adicionales.
  • El código de inicio no está en c0pkg32.obj, sino en c0d32.obj. c0pkg32.obj no puede llamar a ninguna init de ninguna unit (porque no procesa __PackageInfoTable), pero sí los procesa para un .obj, donde los inits de los paquetes son copiados en el mismo lugar que en una DLL y se comportará como esté en el resto de los aspectos. Más bien, un .bpl sin estar compuesto de ningún unit se comportará como una DLL común.

En pocas palabras: Un .bpl que sea dinámicamente cargado tendrá todas sus units inicializadas por LoadPackage en el orden mencionado. Cuando éste se carga estáticamente (usando los .bpi) sólo tendrá esos units que hayan sidos inicializados por el código del ejecutable que lo utilice, en el orden descrito anteriormente, aunque sea parcial.

Esta inicialización parcial tiene sus ventajas de velocidad, sobre todo vcl60.bpi (paquete que contiene funciones de la VCL) es bastante larga y no todo el mundo necesita usar todas estas units que residen en un ActiveX, un COM, etc. Si se analiza la inicialización parcial, sólo ocurrirá donde sean usado los units; los .obj regularmente son inicializados como las DLLs, donde ninguna parcialidad es permitida.

En resumen, un paquete es como una DLL que básicamente contiene units que permite la inicialización parcial cuando está linkeado estáticamente a un .exe; también usado para permitirle al IDE agregar un componente visual a la paleta, mediante un tipo de programación especifica (de componentes visuales del Borland).

Paquetes comúnmente usados::

Si usted programa en C++ Builder sabrá lo que es la VCL del Builder, y las facilidades que ésta permite -a diferencia del Visual C++ de la Microsoft- para desarrollar aplicaciones visuales creando los formularios y agregando componentes y controles visuales en tiempo de ejecución. Estas funciones y controles visuales de la VCL están contenidos en paquetes, lo cual se puede chequear. Por ejemplo, seleccione con la vista una página de la paleta de componentes visuales y observe los controles que posee. Ahora vaya a Component » Configure Palette... y verá como aparecerán las paletas con sus controles y, al lado de los controles que están en Components, aparecerá el nombre del paquete a que pertenecen. Usted verá algo cómo esto:

Paleta de componentes visuales

Note que los controles de la paleta Standard pertenecen al paquete dclstd60. Eso está muy bien, pero ¿pudiera agregar algún componente visual que yo halla conseguido o creado? Es sencillo: vaya a Components » Install Packages... y verá cómo aparece un ventana conteniendo el nombre completo de los controles y debajo la ruta completa de su BPL o paquete respectivo. Si seleccionan en Components verán cuáles son los componentes visuales que contiene y que aparecen disponibles en la paleta de componentes.

Opciones del proyecto

Para agregar un nuevo componente, deberán presionar sobre Add...; luego se les pedirá que agreguen un nuevo .bpl, y si éste es visual aparecerá en la paleta de componentes visuales en la página donde se halla programado el paquete (muchas veces es en Sample).

Cuando se va a compilar y linkear un proyecto se debe especificar se debe especificar cómo va a usar los paquetes que requiere: dinámica o estáticamente. Por defecto se usa el enlace dinámico. Es posible también escoger units que estén en otros paquetes para que sean linkeados dinámicamente a una unit de un proyecto de determinado. Para hacerlo, tienes que usar #pragma link "unitname". Esto hace que a la hora del linkeo incluya el obj de la clase requerida del paquete en el archivo .lib.

La tabla a continuación contiene los archivos que comúnmente se crean cada vez que compilamos un ejecutable. Recuerden que los paquetes pueden ser enlazados estática y dinámicamente, además de que su contenido puede estar formando parte de la aplicación cliente que lo usa, por lo que el .bpl no se crea.

Paquetes creados en una compilación exitosa
Extensión Descripción Tipo Propósito
.bpl Borland Package Library Biblioteca enlazable dinámicamente Contiene código ejecutable del paquete y exporta las funciones y datos del paquete.
Una biblioteca en tiempo de ejecución accedida por aplicaciones que están dinámicamente linkeada a ella.
Una biblioteca en tiempo de diseño que puede ser instalada dentro del IDE para hacer nuevos componentes o editores disponibles en tiempo de diseño.
.bpi Borland Import Library Biblioteca de Importación Contiene registros de importación para las funciones y datos exportados por el correspondiente archivo BPL requerido para el enlace dinámico a el archivo BPL.
.lib Static Library File Biblioteca de Objetos Una biblioteca que contiene los archivos object de los units contenidos por él. Usado para linkear dinámicamente datos y funciones a una aplicación cliente.

Consideraciones para usar Clases empaquetadas::

Para que una clase sea exportada o importada desde un paquete, se deberá usar la macro PACKAGE después de la palabra clave class en la definición de la clase:

class PACKAGE TMyComponent : public TComponent
{
// Definición de la clase componente
};

La macro PACKAGE también deberá ser usada en la función Register() del paquete. Ejemplo:

namespace Newcomponent
{
  void __fastcall PACKAGE Register()
  {
    TComponentClass classes[1] = {__classid(TMyComponent)};
    RegisterComponents("Samples", classes, 0);
  }
}

Por supuesto, también se aplica a las clases componentes y si usas el Wizard, Builder lo insertará por ti.

Para garantizar que la clase contenida en un paquete sea manipulada correctamente, la directiva #pragma package(smart_init) deberá aparece en archivo fuente de la unit. El propósito de esto es asegurar que los units empaquetados sean inicializados según sus dependencias. La directiva #pragma package(smart_init,weak) será usada cuando no se quiera que una unit en particular sea contenida en el archivo BPL; en su lugar será puesta en el BPI y linkeada estáticamente a la aplicación. Estos tipos de empaques débiles se usan para que no halla conflictos entre paquetes que dependan de una misma librería externa (o sea, para que los paquetes se puedan comunicar desde app-bpl).

Conclusiones:

Los paquetes son una excelente opción para crear componentes visuales, no visuales, clases, procedimientos y recursos. Es posible que tengas funciones que uses y rehuses en uno o más programas que has hecho, por lo que querrás desarrollar una biblioteca para compartir todas esas utilidades y tener mejor control y rendimiento de tus programas. Un ejemplo son los juegos que usan las bibliotecas del DirectX, imagínate si cada juego almacenara las DLLs del Direct3D en su carpeta... tendríamos una redundancia de archivos repetidos enorme. Lo que hacemos es instalar la última versión del DirectX que contiene las funciones anteriores muchas veces mejoradas y otras nuevas. Es como trabajar con clases para los novatos: cuando te acostumbras no dejas de hacerlo nunca más. Recuerda usar en tus grandes DLLs o paquetes, pero conociendo las ventajas de este último... bueno, tú sabrás ;).

Alguno de ustedes dirán: yo no he visto ningún programa que contenga paquetes en vez de DLLs. Bueno, por citarte uno muy bueno, instala el TuneUp Utilities 2007 (programa que recomiendo para mantener tu máquina estable y bien personalizada), haz clic derecho sobre su acceso directo, ve a Propiedades y cuando salga el cuadro de diálogo, presiona el botón Buscar destino; cuando estés en la carpeta del programa, verás los paquetes a tutiplén, incluso te darás cuenta de que inteligentemente el programa desglosa sus labores en distintos paquetes, para no tener que instalar recursos innecesariamente en caso de que no vayas a utilizar uno específico. Viste, bistec ;).

Recuerda escribirme tus experiencias,
saludos,
Eliux.



Artículos relacionados


No hay comentarios: