0% encontró este documento útil (0 votos)
3 vistas

Tutorial Delphi

El documento es un curso introductorio sobre programación en Delphi, que abarca desde la creación de un proyecto hasta conceptos avanzados como la programación orientada a objetos y el acceso a bases de datos. Se detalla la estructura de un programa Delphi, el uso del IDE y la creación de componentes, así como la interacción con el sistema operativo y el Internet. Además, incluye una encuesta para mejorar el contenido del curso y menciona que algunos capítulos están en construcción.

Cargado por

Jose Antonio
Derechos de autor
© © All Rights Reserved
Formatos disponibles
Descarga como DOC, PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
3 vistas

Tutorial Delphi

El documento es un curso introductorio sobre programación en Delphi, que abarca desde la creación de un proyecto hasta conceptos avanzados como la programación orientada a objetos y el acceso a bases de datos. Se detalla la estructura de un programa Delphi, el uso del IDE y la creación de componentes, así como la interacción con el sistema operativo y el Internet. Además, incluye una encuesta para mejorar el contenido del curso y menciona que algunos capítulos están en construcción.

Cargado por

Jose Antonio
Derechos de autor
© © All Rights Reserved
Formatos disponibles
Descarga como DOC, PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 89

Índice

 Capítulo 0. Introducción
 Capítulo 1. La aplicación - El "archivo de Proyecto de Delphi"
 Capítulo 2. Nuestro primer programa de Delphi - Una Forma
 Capítulo 3. Objetos, Unidades, Formas y Two-Way Tools
 Capítulo 4. Usando Delphi Wizards - Primera Aplicación
 Capítulo 5. Acceso de Bases de Datos en Delphi
 Capítulo 6. Escribiendo una Aplicacion de Base de Datos
o Capítulo 6.1. Cómo funciona Cliente/Servidor en 20 minutos
o Capítulo 6.2. Continuando con nuestro catálogo. Manejando parámetros [Fuentes!]
o Capítulo 6.3. Los módulos de datos (En Construcción)
o Capítulo 6.4. Migrando nuestra aplicación a módulos de datos [Fuentes!]
o Capítulo 6.5. MIDAS y nuevos paradigmas: Objetos de negocios
o Capítulo 6.6. Migrando nuestra aplicación a MIDAS [Fuentes!]
 Capítulo 7. Componentes y Paquetes
 Capítulo 7.1. Dos Modos Fáciles de Escribir un Componente [Fuentes!] [Fuentes (ActiveX)!]
 Capítulo 8. Open Tools API
o Capítulo 8.1 Creando una pequeña ayuda para el desarrollador.
 Capítulo 9. Teoría de Interfases
o Capítulo 9.1. Interfaces COM en Delphi (En Construcción)
o Capítulo 9.2. Controlando Word y Outlook 98 desde Delphi
o Capítulo 9.3. Interfaces CORBA en Delphi
o Capítulo 9.4. Mezclando Lenguajes y Plataformas con CORBA: Cómo Platicar con
programas en Java [Fuentes!]
 Capítulo 10. Delphi y el Internet
o Capítulo 10.1. Teoría de Comunicaciones en Internet
o Capítulo 10.2. Programando Sockets en Delphi [Fuentes!]
o Capítulo 10.3. Delphi como Cliente de Internet
o Capítulo 10.4. Programando un lector de e-mail (POP3/SMTP) (En construcción)
o Capítulo 10.5. Delphi como auxiliar de servidor de Web (En construcción)
o Capítulo 10.6. Haciendo un servidor de CGI para Web
 Capítulo 11. Utilizando el Sistema Operativo (En Construcción)
o Capítulo 11.1. Hilos de Ejecución [Fuentes!]
o Capítulo 11.2. Manejo de Ventanas en Bajo Nivel
o Capítulo 11.3. Utilizando el Registro de Windows
o Capítulo 11.4. Manejo de Procesos en Windows
 Artículo: Consideraciones de Diseño en Delphi (En Construcción)

Encuesta

Su opinión es importante. Por favor llene esta encuesta. Su información meserá enviada via e-mail
privado y no será compartida con nadie. Utilizaré las respuestas que reciba para mejorar mi
página.

Capítulo 0. Introducción

Este curso esta enfocado para programadores de computación. No es necesario tener experiencia
con ningun lenguaje en particular, pero es importante haber programado antes, ya que los
conceptos básicos de programación solo se mencionan una vez. Los tipos de letra utilizados
cambiarán mientras cambio el diseño de mi página poco a poco.
El código en Delphi, dentro de las posibilidades de mis utilerías, esta escrito en
HTML con los fonts y sintaxis de colores, de una manera análoga a lo que
encontrará en el editor de Delphi. Muchas gracias a Gerald Nunn et al, autores de
las ayudas de Diseño de Delphi "GExperts", por el convertidor de PAS a HTML con
sintaxis de colores. Este es un ejemplo de código:

program Project1;

uses
Forms,
Unit1 in 'Unit1.pas' {Form1};

{$R *.RES}

begin
{Estos son comentarios}
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

Capítulo 1. La aplicación - El "Archivo de Proyecto de Delphi"


Esta sección esta enfocada para entender como funciona una aplicación en el ambiente Delphi
dentro de Windows, y cuales son las principales partes de un programa de "Object Pascal" en
Windows (object pascal es el nombre formal del lenguaje de programación - asi como en Visual
Basic el lenguaje es Basic, en Delphi el lenguaje es Object Pascal). Si quiere usted comenzara a
programar en Delphi de inmediato, vaya a la siguiente seccion (y asombrese de lo facil que es
programar con Delphi!), pero asegurese de regresar a esta seccion para tener una buena
fundacion de la manera en que funciona una aplicación de Delphi.

Nota: No se preocupe si no entiende la totalidad de lo mencionado en esta


sección. Muchos programadores muy exitosos no comprenden mucho de
lo especificado en este capítulo. Pero creo que en estos dias de lenguajes
tan diferentes para programación en Windows (e incluso en otros sistemas
operativos) es muy importante tener una idea clara de lo que el lenguaje
que utilizamos tiene que hacer para lograr su "magia". Los programadores
de C++ para Windows reconeceran muchos contrastes con este lenguaje,
y encontrarán que Delphi es casi tan flexible en este campo como C++.

Delphi se divide en tres secciones, el compilador (con su "encadenador"), la libreria, y el IDE


(Ambiente de desarrollo integrado, o Integrated Development Environment). El
compilador/encadenador es un programa que crea el archivo ejecutable de Windows (PE) estilo
Intel, sin ningun interprete de por medio. La librería es código que nos permite usar todas las
capacidades de Delphi. La libreria esta escrita en su totalidad en Object Pascal (es una libreráa "de
clases" estilo MFC, llamada VCL), y esta totalmente orientada a objetos. Veremos objetos y su
repercusión en programación mas adelante.

Una nota interesante es que el IDE esta hecho en Delphi, y utiliza las mismas librerias que usted
utiliza para compilar su programa. Esto quiere decir dos cosas:
 Primero, que todo lo que puede hacer el IDE es posible para usted (lo cual es notorio
contraste con lenguajes como Visual Basic).
 Segundo, que el IDE esta abierto, lo cual quiere decir que usted puede no solo extender la
libreria para que Delphi utilice los "componentes" diseñados por usted, sino que además
puede extender el IDE para hacer "expertos" y ayudas de programación.

Un programa es una serie de instrucciones que son ejecutadas por la computadora en secuencia.
En los viejos tiempos de BASIC, la secuencia estaba especificada por números de linea. En los
demás lenguajes la secuencia está simplemente especificada por las líneas del programa, que van
una detrás de otra (a menos que el programa se haya ido de fiesta anoche). En DOS, cuando el
programa ejecuta la ultima línea, el programa termina.

Nota: Los que han programado en DOS recordaran lo siguiente: El hecho


de que el programa termina despues de su ultima linea obligaba a los
programadores a hacer un ciclo para controlar el programa. Este ciclo (ya
sea usando Goto, Do-While o otra clase de recursión) mostraba el menu
principal y respondía a lo que el usuario seleccionaba. Un programa en
Windows no es muy diferente en este sentido de una aplicación en DOS.
El ciclo sigue ahi, pero ahora el ciclo lo controla la librería de clases y no el
programador. Lo que anteriormente llamabamos "ciclo del menú
principal" (o algo parecido) ahora se llama "message loop" (ciclo de
mensajes).

El "programa principal" de Delphi es un archivo de texto ASCII con extensión .DPR. Ésta extensión
quiere decir Delphi PRoject (proyecto de Delphi).

Para cada una de las ventanas que usted diseña en el IDE, Delphi crea una "unidad". Una unidad
es un archivo individual (tambien de texto ASCII) que representa en general a un objeto, o a una
agrupación logica de funciones. En el caso de los "objetos" que son formas, Delphi también crea
un archivo "DFM" (Delphi Form) para guardar la apariencia del diseño de las mismas (las formas
son simplemente archivos de recursos en un formato especial que solo funciona en Delphi - ver
"archivos de recursos (RES)").

El siguiente ejemplo muestra el archivo DPR que se crea cuando comienza usted
Delphi. En general usted puede crear programas muy complejos sin jamás
modificar el archivo DPR (tambien llamado archivo de proyecto). Pero es
importante saber como funciona. El archivo de Proyecto "Project1.Dpr" tiene la
siguiente apariencia:

program Project1;

uses
Forms,
Unit1 in 'Unit1.pas' {Form1};

{$R *.RES}

begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Analicemos este archivo. La sentencia "program project1" nos dice que el programa se llama
project1. El nombre de programa debe ser el mismo que el nombre del archivo (sin extensión).

La seccion USES nos dice que archivos son usados. Forms es la librería de Delphi que contiene los
comandos para crear y manipular ventanas (que en Delphi se llaman Formas). El otro renglón en
la sección "uses" nos dice que la unidad llamada "Unit1" se encuentra en el archivo "unit1.pas", y
Delphi nos hace un comentario {} que dice que la forma en esta unidad se llama Form1.

$R es una "directiva del compilador". Una directiva es un comando para el compilador, no para el
IDE. Cuando el compilador encuentra la directiva {$R *.RES} un archivo de "recursos" con el
mismo nombre del programa (pero con extension RES) es encadenado junto con el programa.

Nota: Un archivo de recursos (RES) es un archivo con especificaciones


para bitmaps, textos en general, iconos, y en algunos casos cajas de
dialogo o menus. Delphi utiliza el mismo formato para sus archivos RES
que C, y cualquier editor de recursos para C de 32 bits (como los que se
encuentran en Visual C++ 4/5) pueden crear archivos de recursos que
Delphi puede leer y utilizar.

Una vez que Delphi ha especificado todo lo que va a usar el proyecto, el programa inicializa la
aplicación (Application.Initialize), crea la forma Form1 a partir de la definición de objeto "TForm1"
(veremos el significado de esto mas adelante) usando "CreateForm", y la aplicación "corre"
(Application.Run). Cualquier forma creada con CreateForm está "viva" (aunque podria ser
invisible) hasta que el Application.Run termina. Despues de esto (normalmente cuando "Run"
recibe el mensaje "Terminate") el programa termina.

¿Porqué Application.Run?

"Run" en Delphi es un método de la aplicación que hace al programa entrar en el ciclo de


mensajes de Windows. El ciclo de mensajes es un ciclo estilo "Do While" que recibe mensajes de
Windows (clicks de botones, tecleos, movimientos del "mouse") y procesa los mensajes en una
manera consistente para todas las "ventanas" de la aplicación. En los viejos días de la
programación de sistemas de ventanas, los programadores de C tenian que escribir el ciclo de
mensajes ellos mismos. Pero hoy en dia, librerías de clases como MFC y el VCL de Delphi manejan
la tediosa programación del ciclo de mensajes.

En el siguiente capítulo veremos como Delphi nos facilita la construccion de una aplicación, y
escribiremos una sola línea de código para ver el poder que nos proporciona Delphi para el
desarrollo de aplicaciones.
Capitulo 2. Nuestro primer programa de Delphi - Una Forma
¿Listos para escribir nuestro primer programa? Comencemos entonces. Como mencioné
anteriormente, Project1 es un proyecto vacío que simplemente contiene una forma vacía.

El IDE de Delphi se divide en tres secciones:

La parte de arriba contiene el menú principal de Delphi, y contiene botones para hacer cosas con
el proyecto (abrir, salvar, compilar) en la parte izquierda. La parte derecha contiene la "paleta de
componentes" que es un menú de botones con todos los componentes que podemos poner en la
forma, en distintas páginas.

Nota: Mi paleta contiene add-ons y varios componentes que pruebo. En éste directorio de Delphi
usted encontrará los sitios donde puede usted evaluar y comprar muchísimos
add-ons para Delphi. Estos add-ons pueden hacer que mi Delphi no sea
exactamente igual al suyo.

A la izquierda, podemos ver el inspector de objetos, que


contiene las "propiedades" y "eventos" de el objeto
seleccionado en el diseñador. Usted puede hacer click con el
mouse en cualquier propiedad para modificarla. En las
propiedades que vienen entre parentesis, haga doble-click para
mostrar un diálogo (por ejemplo, al hacer doble-click a la
propiedad (Font), Delphi muestra el diálogo de Tipos de
Letra). Cuando usted extiende la librería con sus propios
componentes, usted puede diseñar sus propios editores.
La otra página contiene los eventos, que son los mensajes que
Delphi "atrapa" y que usted puede asignar a procedimientos.
Cuando diseña sus propios componentes, también puede
añadir eventos y relacionarlos con mensajes.
/td>
El diseñador nos muestra la(s) forma(s) que podemos diseñar, y puede mostrar tantas formas
como usted desee al mismo tiempo. Detras del diseñador, podemos ver la ventana del editor. El
editor es donde escribimos el programa.

Lo que queremos hacer para este primer ejemplo es simplemente crear un botón que, cuando se
presione, de un mensaje de bienvenida (como en la imagen anterior). Para esto hagamos lo
siguiente:

Seleccione, de la "paleta de componentes", el botón (button). Despues de seleccionarlo, haga click


en donde lo quiera ver en la forma. Utilizando la ventana "Object Inspector", cambie la propiedad
"Caption", escribiendo "&Botoncito". El caracter "&" le dice a Windows que ponga un subrayado
bajo la B y permita al usuario utilizar Alt-B para presionar el Botón.

Ahora haga doble click en el botón que acaba de crear. Delphi:

1. Creará un procedimiento en su programa "unit1.pas" llamado Button1Click. En este


procedimiento usted especificará lo que va a ocurrir cuando el usuario haga click en el
boton. El "begin/end" de pascal especificando donde comienza y termina el botón sera
tambien añadido por Delphi.
2. Asignará el evento "OnClick" del botón (que dice al botón qué procedimiento ejecutar
cuando el usuario haga click en el mismo) al procedimiento "Button1Click" recién creado.

Teclee lo siguiente:

ShowMessage('Esto está Padrísimo!');


Incluya el punto y coma al final; el lenguaje Pascal necesita saber donde termina cada línea o
agrupación de lineas y el símbolo de punto y coma es lo que utiliza para este propósito.

Ahora, presione el botón "Run" de menú de botones de Delphi. Si todo sale bien, Delphi compilará
y encadenará su programa. Despues esconderá las ventanas de diseño y desplegará "[Running]"
en su barra de título.

Felicidades! Acaba usted de crear, compilar y encadenar un programa de Windows. Veamos lo que
puede hacer su programa "de una linea"

Su programa tiene una forma. La forma se puede maximizar, minimizar, cambiar de tamaño y de
posición en exactamente la misma manera que cualquier programa de Windows - sin una linea de
codigo de su parte (en el futuro, cuando usted sea un super-experto y empieze a manejar
"mensajes de windows", en cualquier lenguaje, se dara cuenta de cuanto trabajo Delphi le ahorró).

Su forma tambien tiene un botón. Presiónelo. Verá un mensaje que dice que "esto está Padrísimo"
con un botón de Ok.

Para cerrar el programa, presione el ícono de la "X" en la parte superior derecha, como en
cualquier otro programa de Windows. Su programa regresara al diseñador.
Capítulo 3. Objetos, Formas, Unidades y Two-Way Tools
Este capítulo nos ayudará a entender como funciona la POO (programación orientada a objetos),
cómo funcionan las formas y unidades en Delphi, y cómo maneja delphi la sincronía entre código y
diseño.

Objetos

La programación orientada a objetos ya no es una "moda". Ahora la programación por objetos esta
cambiando la forma en que vemos los problemas. Este no es el momento ni el lugar para hablar
de la teoría de objetos (un buen libro de tecnologia de objetos de Grady Booch dará una mucha
mejor explicación que este curso acerca de lo que es un objeto en programación). Pero es
importante saber las bases de lo que es un objeto para saber cómo se aplica a Delphi.

Un objeto es un tipo de datos que incorpora datos y código (comportamiento) en un solo


"paquete". Ántes de la era de la orientacion a objetos, el código y los datos eran dos cosas
separadas. La orientación por objetos nos permite representar de un modo mucho más
conveniente al mundo real.

¿Cómo podemos modelar un objeto del mundo real con objetos "de computadora"? Veamos un
ejemplo:

Ejemplo de un Objeto en Object Pascal

Supongamos que estamos haciendo un juego acerca de un Acuario. Para este juego queremos
diseñar un Bonito Delfín que va a brincar con el aro y jugar con la pelota, pero queremos en el
futuro extender el juego para cualquier tipo de animal marino porque va a ser una simulación bien
picuda. Tal como en el mundo real, necesitamos comenzar con un objeto llamado "pescado"
(Para los amantes de la biologia: Ya se que el delfín es un mamífero y no un
pescado, pero éste es un ejemplo). El objeto pescado tiene sus datos, como son
alto, largo, peso y color. Pero el pescado tambien puede hacer otras cosas, como
por ejemplo nadar y sumergirse. Entonces primero hacemos nuestro objeto
pescado, que tiene la siguiente forma:

TPescado = class(TObject)
Largo : Float; // El largo del pescado, en centimetros
Alto : Float; // La altura del pescado, en centimetros
Ancho : Float; // El ancho del pescado, en centimetros
Peso : Float; // Cuanto pesa el pescado, en gramos
public
procedure Nadar(AdondeXY, AdondeXZ, AdondeYZ : TPoint);
procedure Sumergirse(Profundidad : Float);
end;

Este código le dice a la computadora: TPescado es una clase que hereda de TObject (o "Un
Pescado es un Objeto") . Tiene los campos Largo, Alto, Ancho y Peso, que son números de punto
flotante. Sus métodos públicos (lo que todo mundo sabe que un pez puede hacer) son Nadar y
Sumergirse.

Si esto parece complejo, por favor sigan leyendo. Muy pronto todo quedará claro.
Ahora el Delfín. He decidido para este ejemplo que hay dos clases de delfines, los
entrenados y los salvajes (no entrenados). Asi que comencemos con el delfin
entrenado:

TDelfin = class(TPescado)
LargodeNariz : Float; // El largo de la nariz del delfin
public
procedure TomarAire;
procedure HacerRuido( Decibeles : Integer );
end;

Ahora bien, este codigo le dice a la computadora: El TDelfin es una clase que hereda de TPescado
(o "Un Delfin es un Pescado"). Esto quiere decir que un Delfin puede hacer todo lo que un
pescado puede hacer (tiene largo, alto, ancho, peso y además puede nadar y
sumergirse). Entonces yo ya terminé mi delfin, y no tuve que implementar de
nuevo las funciones para nadar y sumergirse, que el pescado (y ahora tambien el
delfin) puede hacer. Ahora vamos a entrar en la materia del jueguito, el delfin
entrenado:

TDelfinEntrenado = class(TDelfin)
public
procedure JugarConPelota( Segundos : LongInt; );
procedure BrincarElAro( Circunferencia : Integer );
end;

El TDelfinEntrenado es una clase que hereda no de TPescado, sino de TDelfin (o "Un delfín
entrenado sigue siendo un delfin, pero..."). Al igual que la vez anterior, un delfín entrenado puede
hacer todo lo que un delfin puede hacer, pero además puede jugar con pelota y brincar el aro.

¿Porqué hacer tres objetos nada más para representar un delfín? Supongamos
que ahora quiero hacer un tiburón...

TTiburon = class(TPescado);
NumeroDeDientes : LongInt;
Bocon : Booolean;
ComeHombres : Boolean;
public
procedure Enojarse;
procedure ComerPersona( Quien : TPersona);
procedure EspantarVisitantes;
end;

Gracias a Delphi y la orientación a objetos, ahora estoy "re-utilizando" el código


que usé para implementar mi delfín. Ahora, si mañana descubro que los pescados
pueden nadar de una manera especial, o quiero hacer la simulación detallada y
quiero hacer que hagan algo más, como nacer y morirse, todos los objetos de tipo
pescado (tiburon, delfín, delfín entrenado, pez dorado) van a nacer y morir igual
que el pescado, porque la implementación aplica al tipo y a todos los tipos de la
misma clase. Ahora bien, la "jerarquía" de los objetos que hemos hecho es como
sigue:

TObject
+----- TPescado
|
+----- Delfin
| |
| +----- Delfin Entrenado
|
+----- Tiburon

La jerarquía de objetos es una especie de "árbol genealógico" que nos dice qué objetos se
"derivan" de otros objetos. Como conceptualizamos esta jerarquía? Es de hecho bastante sencillo
una vez que nos acostumbramos al árbol. Por ejemplo, supongamos que queremos saber que
interfaces soporta el "Delfín Entrenado". Leemos todos los "padres" de la siguiente manera: "Un
TDelfin ES UN TPescado, que ES UN TObjeto". Esto quiere decir que un objeto de tipo TDelfin
soporta todas las interfaces que el objeto Tpescado y el objeto TObject.

TForm vs Form1; Clases vs variables; Concepto Básico de Punteros

Los lectores mas perceptivos han notado que Delphi utiliza una T para especificar que algo es un
objeto. De hecho, aqui Delphi se parece mucho a C: Un TObjeto es la definición de la clase del
objeto, mientras Objeto1 es una variable de tipo TObjeto. Asi, TForm es la clase, pero la variable
que usted usa para sus formas se llama Form1. La variable Button1 es un "puntero" a la instancia
de clase TButton.

Supongamos que usted tiene el siguiente código en algun lugar de una forma con
un boton (como la que acabamos de escribir). No lo intente, esto es teoría:

var
ElBoton : TButton;
begin
ElBoton := Button1;
Button1.Free;
ElBoton.Caption := 'ESTO VA A TRONAR!!!';
end;

La definición de variable nos dice que "ElBoton" es una variable que apunta a un objeto de clase
TBoton. Despues hacemos que ElBoton "apunte" (recordemos que a final de cuentas son punteros)
al Button1 de la forma. Después liberamos el Button1. Ahora tratamos de cambiar el texto del
botón. Obtendremos una de esas horribles "Fallas de protección general". ¿Por qué?

Pues es muy sencillo. En la linea Button1.Free, la memoria a la que Button1


apunta es liberada. Ya no nos pertenece porque efectivamente "borramos" el
botón. Pero ElBoton sigue apuntando a la posición de memoria que Button1
apuntaba. Delphi, aunque es un lenguaje muy elegante, es lo suficientemente
poderoso para no preguntarnos cuando queremos manipular memoria (Delphi
asume, como C++, que nosotros somos el jefe y sabemos lo que hacemos). Asi
que cometemos el error de tratar de cambiar el texto de un objeto que no existe.
CRASH!

Lista de Variables Memoria

Button1 = $01A73F

ElBoton := Button1, o sea


ElBoton := $01A73F $01A73F..$01A7FF (TButton)

Esto lo menciono porque en cuanto un nuevo programador de Delphi trata de manipular objetos,
tarde o temprano se encuentra con un problema de este tipo. Es un error común para el
programador de objetos tanto en C como en Pascal, y es la escencia de la "Falla de Protección
General", o GPF. El motivo de esta falla es básicamente que estas tratando de utilizar memoria
que ya no existe en tu aplicación.

Formas y Unidades

Las formas en Delphi son objetos de tipo "TForm". Delphi viene con una tabla con la "jerarquía" de
objetos de la libreria VCL. El programa que diseñamos en el capitulo anterior tenía un objeto tipo
"TForm". Este objeto es la ventana estándar de Windows para Delphi. Cuando hicimos nuestro
programa con una línea de codigo, usted no tuvo que decirle a TForm como minimizar, maximizar,
restaurar, mover o cambiar la ventana de tamaño. Usted sólo le dijo a la computadora: Mi TForm1
es un objeto tipo TForm. Delphi sabe que TForm tiene la capacidad de hacer todo lo anterior (y
más). Entonces el comportamiento de todas las formas que usted cree a base de TForm es el
mismo. Usted no tuvo que hacer nada para utilizar la magia de TForm - ni siquiera fue necesario
saber que TForm era un objeto.

(Delphi tambien le ofrece poder. Si usted quiere hacer cosas muuuy raras, puede usted evitar
TForm y utilizar TCustomForm, que es una clase abstracta para que usted haga su formas con
comportamientos muy extraños, si se avienta - pero primero hay que aprender más).

Cada forma es guardada en un par de archivos: El archivo PAS (donde escribimos el código) y el
archivo DFM (donde diseñamos la forma).

El Archivo PAS

El archivo PAS es un archivo de texto donde escribimos el código de nuestro


programa. Delphi nos ayuda a escribir el código, pero eso no quiere decir que
tome totalmente el control del editor, o que guarde el archivo en un formato
"desconocido". Es un simple archivo de texto escrito en "Object Pascal". El
siguiente codigo es el contenido completo del programa que diseñamos.

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);


begin
ShowMessage('Esto esta Padrisimo!');
end;

end.

Tour de dos minutos de Object Pascal

Object Pascal divide los programas en dos secciones: La interfase ( interface) y la


implementacion ( implementation ).

Examinemos la interface de este programa: La primera sección nos dice que esta unidad utiliza las
librerias Windows, Messages, SysUtils, etc. Despues viene la definición de typos (type), donde
Delphi ha definido por nosotros la TForm1 que ha creado (en Delphi, las cosas no solo "aparecen"
como en otros lenguajes. Delphi es un lenguaje decente y siempre pone la
representación de todo el diseño en archivos legibles y modificables con el
editor). Object Pascal es un lenguaje "strong-typed", lo cual quiere decir que
cualquier variable, objeto o rutina debe ser declarado antes de ser escrito. La
declaración de la forma tambien declara el Botón que le pusimos. Si usted se
pone a poner mas botones a la forma, verá que Delphi añade secciones Button2,
Button3 a la unidad de la siguiente manera:

type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Button3: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
También podemos ver que Delphi definió el procedimiento Button1Click para cuando el usuario
apriete el botón, y este procedimiento pasará el parametro (Sender) lo cual le dirá a nuestra rutina
qué objeto fue el que ejecutó el evento (normalmente Button1, pero esto nos da el poder de
compartir un "procedimiento manejador de eventos" para mas de un objeto - veremos como hacer
esto mas tarde).

Si usted quiere añadir sus propias rutinas manualmente, Delphi ya nos pre-escribio una seccion
privada ( private) y publica ( public ) para que podamos añadir funciones manualmente (existen
mas directivas, como "protected" o "automated", pero las mas usadas son estas dos, por lo cual
Delphi las define por nosotros. Delphi trata de ayudar sin estropear nuestro código con mucha
basura que no vamos a usar). Las funciones privadas solo son visibles para TForm1, mientras que
las funciones públicas son visibles para cualquier objeto que use TForm1.

Ahora la última seccion. Si usted es muy perceptivo habra notado que he hablado de TForm1 (la
clase) pero la variable que inicializaría la clase (de la cual hablamos con anterioridad) no ha sido
definida. Bueno, pues la última sección del área de la interface lo define:

var
Form1: TForm1;

Aquí le decimos a Delphi que la variable Form1 es una variable de tipo TForm1. ¿Y quién inicializa
la variable Form1? Bueno, presione Control-F12 (View Unit=Ver Unidad) y seleccione Project1. Una
de las líneas en el archivo de proyecto dice:

Application.CreateForm(TForm1, Form1));

Dentro de la función de TApplication CreateForm, el objeto aplicación crea un TForm1 y lo asigna a


la variable Form1. ¿Y porque el objeto aplicación? Esto es porque si Windows quiere matar la
aplicacion, la aplicacion necesita tener una lista de todas las formas en tu programa para que
puede llamar el metodo "Close" de todas tus formas. TApplication tiene un arreglo (array) llamado
Forms donde se encuentran todas las formas de tu proyecto.

Two Way Tools y el archivo DFM

Borland ha perfeccionado una tecnología llamada "Two-way tools". Esto quiere decir que su
programa esta escrito en un archivo de texto que usted puede editar inmediatamente, pero al
mismo tiempo está representado en los diferentes diseñadores de Delphi. Cada vez que usted
añade un objeto, modifica una propiedad o agrega un evento, el IDE "sabe" donde añadir ese
objeto, propiedad o evento en la interface, y muchas veces escribe código de inicializacion con
bloques "begin-end ", listo para que usted escriba su código y siga su camino. Los "two way tools"
de Borland son los mas estables y rápidos del mercado, y son los unicos que le permiten editar la
forma en el diseñador o directamente como texto.

En el capítulo anterior, cuando usted hizo doble click en el botón, los "two-way-tools" de Delphi
escribieron el código para el evento Click del botón y lo asignaron al mismo.

Regresando a nuestro proyecto, ahora veamos como guarda Delphi las


propiedades de nuestro objeto Form1. La forma se guarda en un archivo llamado
"DFM" (Delphi Form File), en un formato estilo "res". Pero Delphi procura
mantener su arquitectura abierta, asi que nosotros podemos editar el archivo
directamente en Delphi. Presione Shift-F12. De la lista de formas que Delphi
despliega (View Form), seleccione Form1. Delphi regresa al diseñador de la forma.
Ahora presione "Alt-F12". Su unit1.pas desaparece del editor, y en su lugar el
texto de unit1.dfm aparece. Su forma tambien desaparece, porque ahora la
estamos editando "como texto":

object Form1: TForm1


Left = 200
Top = 112
Width = 1088
Height = 750
Caption = 'Form1'
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'MS Sans Serif'
Font.Style = []
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 240
Top = 112
Width = 75
Height = 25
Caption = '&Botoncito'
TabOrder = 0
OnClick = Button1Click
end
end

Éste es el texto de nuestra forma. Como verá, todas las propiedades "publicadas" son guardadas
aquí. Cada vez que usted cambia una propiedad en el "inspector de objetos", este archivo es
modificado. Por ejemplo, cuando hicimos doble-click en el botón para escribir el código de OnClick,
Delphi modificó el archivo PAS para declarar la rutina "Button1Click", pero ademas añadió un
renglon a esta definición de la forma ( OnClick = Button1Click), diciendole al compilador que
el evento OnClick del Boton 1 esta enlazado al procedimiento Button1Click. Cuando modificamos
el "Caption" del objeto botón, Delphi lo modifico en este archivo. Si quiere Ud. puede modificar el
texto "&Botoncito" para que diga "&Botonzote".

Delphi ha escrito bastante código por nosotros, no cree? Pero aún asi, nos permite ver y modificar
lo que queramos. En general usted no necesita modificar la forma de esta manera. Pero si lo
quiere intentar, tenga cuidado. Delphi puede perder "el hilo" de como esta guardada la forma si
usted modifica las secciones con los nombres o tipos de los objetos. Siempre mantenga un
respaldo de su DFM antes de modificar la forma como texto.

Para salir de la vista de la forma "Como texto", presione Alt-F12. Delphi. Delphi leerá la forma de
nuevo (para interpretar sus cambios) y regresara al diseñador.

Capitulo 4. Usando Delphi Wizards - Primera Aplicacion


En este capitulo veremos otras maneras de comenzar una aplicacion en Delphi. Delphi nos
ayudara a escribir algun codigo de inicio para diferentes tipos de proyecto. Veremos que facil es
comenzar con una base estandarizada para nuevas aplicaciones. Tambien veremos como el Code
Repository nos puede ayudar a compartir codigo en un ambiente de trabajo (muy importante en
desarrollos grandes). Ademas, haremos nuestra primera aplicacion en Delphi!

Object Repository

El Object Repository es un directorio donde usted puede poner codigo fuente basico y
componentes que usted utiliza una y otra vez, como formas, su "aplicacion estandar" y cosas asi.
Cuando usted selecciona File-New, el Code Repository muestra un una pagina con todas las
opciones de Wizards y lo que contiene el repositorio para que usted eliga. Usted puede no solo
copiar el codigo a su proyecto, sino "heredar" y "usar".

Heredar una forma (inherit) es una manera muy util de, por ejemplo, hacer que las formas de su
aplicacion tengan una apariencia fija. Si usted siempre tiene un Toolbar vacio y su forma siempre
tiene el caption rojo, por ejemplo, usted puede heredar de esa forma para todas las formas de su
aplicacion, y Delphi creara las formas basadas en su forma en vez de basarlas en TForm. Cualquier
objeto puede ser heredado. Simplemente "usar" quiere decir que no vamos a mantener una copia
del objeto en el repositorio y tampoco lo vamos a utilizar.

Wizards y Add-Ins

Un wizard es un DLL (o DPL) de Delphi que nos ayuda a escribir codigo. Los Wizards pueden ser
desde muy sencillos (wizard para "New Dialog"), hasta muy complejo codigo que cambia la
totalidad del IDE (como Coderush, o GExperts). Cuando son muy complejos y cambian el IDE se
llaman "Add-Ins" o IDE Enhancements.

Porque el rango tan amplio de complejidad y son lo mismo? Aunque eso es para otro capitulo, por
ahora le puedo decir que Delphi esta hecho en Delphi (y la libreria sigue siendo el VCL), asi que
cuando usted hace un Add-In, todos los objetos del IDE de Delphi estan disponibles para que usted
los manipule. El IDE de Delphi tiene ademas interfaces que hacen estas modificaciones faciles,
llamadas Open Tools API. Eso quiere decir que su Add-In puede manipular el menu añadiendo
items, cajas de dialogo, modificando las ventanas del IDE e incluso reemplazando tareas de
Delphi! Este es el poder de un ambiente totalmente abierto a que usted juege con el. Coderush es
el ejemplo mas extremo en el mercado (hasta ahora) de lo que se puede hacer con este API.

Utilizando el Object Repository

Comencemos por algo facil, utilizar uno de los wizards que vienen con Delphi. Para esto no
tenemos que saber nada...! Simplemente, seleccione File-New... (No use File-New application
porque esto creara una aplicacion vacia tal como la que ve cuando comienza Delphi) - la ventana
del repositorio de objetos desplegara las opciones de los nuevos elementos que puede crear:
Delphi tiene templates categorizadas por pagina:

 New - Esta pagina contiene templates para crear nuevos elementos como Aplicaciones,
componentes, modulos de datos, DLLs, Formas, Paquetes de componentes (DPL), Modulos
de datos remotos (MIDAS/DCOM/Multi-tier), reportes, threads y servidor de Web.
 ActiveX - Con esta pagina puede usted crear ActiveForms (que funcionan en la pantalla
muy parecido a los applets de Java), Control de ActiveX (OCX para usar en Delphi, C++,
Visual Basic o VBScript en paginas de web), Automation Object (objeto COM basico sin
interface de usuario, pero con conteo de referencia integrado), Pagina de propiedades
ActiveX, y Type Library.
 Su Proyecto - El proyecto que se encuentra abierto tambien aparece como pagina para
que usted pueda heredar rapidamente unas formas basadas en otras. Haremos esto mas
tarde.
 Forms - Varias formas y reportes diferentes (About, list box, labels, etc).
 Dialogs - Varios dialogos, asi como un Wizard que lleva paso a paso por la creacion de un
dialogo.
 Projects - Wizard para aplicaciones, Aplicacion MDI, SDI y aplicacion compatible con el
logo de Win95 (esta ultima te permite hacer una aplicacion basica con los "esqueletos" de
todo lo que Microsoft pide para que te ganes un logo de "Diseñado para Windows 95".
 Data Modules- Los modulos de datos que haga usted pueden ir aqui. En la seccion de
bases de datos veremos como funcionan los modulos de datos.
 Business - Esta pagina tiene un wizard para hacer una forma con campos (lista para
ejecutar) a partir de una base de datos, un "cubo de decisiones", un wizard para hacer
reportes, y un wizard para graficacion.

Cuando use Delphi para producir sus aplicaciones, podra usar Tools-Repository del menu de Delphi
para hacer mas paginas y organizar sus wizards o los modulos de datos que haga. Ademas,
usando Tools-Environment options - Shared repository directory podra usted cambiar el directorio
para que este en su directorio de datos, o en algun lugar de la red (asegurese de copiar los
archivos de C:\Program Files\Borland\Delphi 3\ObjRepos, o equivalente, al nuevo directorio para
que los wizards sigan funcionando).

Ahora que sabemos lo que es el repositorio de objetos, por que no usamos nuestro primer Wizard?
Y de paso creamos nuestra primera aplicacion de a deveras...!

Seleccione File-New... y vaya a la pagina de Projects. Seleccione "Application Wizard" y


presione OK. A continuacion, veremos que el wizard nos pregunta que menus queremos utilizar.
Seleccione File, Edit, Window y/o Help (los que desee). Presione Next. Despues Delphi nos pide (si
seleccionamos File) que especifiquemos las extensiones. Presione Add y conteste "Rich Text
Format" y "*.rtf" como descripcion y extension.

A continuacion, nos presentara con una interface para añadir botones dependiendo en los
comandos que seleccionamos:
Utilice la parte izquierda para seleccionar la pagina y la derecha para cambiar los botones. Los
botones Insert, Remove y Space agregan, eliminan y ponen espacio entre los botones. En la parte
superior vera usted la barra de botones tal y como se va a ver. El pequeño triangulo en esta barra
representa donde se insertara el boton y puede ser movido para que usted ponga botones en
medio si olvido alguno.

Cuando termine, le preguntara el Nombre de la applicacion y el directorio donde lo quiere guardar.


Tambien encontrara las siguientes opciones:

 Create MDI Application - Si elige esta opcion, su aplicacion sera estilo MDI (este estilo no
debe ser usado en Windows 95 segun Microsoft, pero paradojicamente todas las
aplicaciones de MS-Office 95 y 97 lo utilizan). El estilo MDI muestra una ventana "maestra"
para la aplicacion y documentos adentro de esta (su nombre proviene de las siglas de
Multiple Document Interface, en alusion a esto). Si no elige esta opcion, su aplicacion sera
SDI (single document interface).
 Create a Status Line - Si elige esta opcion, Delphi creara una barra de status y codigo
para que cada vez que el cursor se ponga sobre un boton el texto de "hint" se muestre en
la barra de status.
 Enable Hints - Con esta opcion, Delphi hara que todos los objetos de la aplicacion tengan
el desplegado de Hints automatico habilitado (enabled).

Seleccione Create Status line y Enable hints. Delphi se ira a trabajar y dejara su programa listo
para ejecutar por primera vez. Felicidades! Acaba usted de crear su primera aplicacion en Delphi.
Todavia no hace nada, pero haremos un mini-editor de textos, nada mas para ver que tan facil es.
Nuestra Primera Aplicacion en Delphi

Esta es la apariencia de nuestra primera aplicacion en Delphi, la cual acabamos de crear utilizando
el Wizard de Aplicacion nueva dentro del Object Repository. Utilizando el Object Inspector, cambie
el Caption a "Mi Editorcito". Si usted quiere, puede ejecutar este programa tal como esta. Presione
el boton de "Run" en el IDE y pruebelo. Trate de presionar los botones y note que ciertos botones
despliegan dialogos (Open, Save)! Pronto veremos como se hace esto. Seleccione File-Exit para
salir de su aplicacion de ejemplo y note como Delphi ya ha escrito codigo para salir del programa
desde una opcion del menu.

Como se dio cuenta al ejecutarla, esta aplicacion tiene ciertos componentes que no se mostraran
al usuario en tiempo de ejecucion (Delphi los ha agrupado en medio de la forma sin alinearlos). El
VCL de Delphi se divide en dos clases de componentes: Componentes Visuales y componentes
No Visuales. Los componentes no visuales son representados por Delphi como iconos con
sombra menos "obscura" en el diseñador, y no se pueden contener dentro de un panel o barra de
botones (porque como no se ven, no tiene caso ponerlos "adentro" de un componente visual).

Nota: El hecho de que el VCL se llame "Visual Component Library" y


tenga componentes "No Visuales" ha inspirado a gente a decir que el
nombre "VCL" esta mal utilizado. En mi opinion particular, el nombre esta
bien utilizado porque la libreria es visual durante su diseño.

Los componentes no visuales en esta forma son el Menu principal, el dialogo "Open", el dialogo
"Save", el Dialogo "Print" y el dialogo "Print Setup". Estos objetos del VCL son los dialogos
estandard de Windows encapsulados en un objeto de Delphi (o sea que se veran en español,
ingles, aleman, etc., dependiendo del idioma de Windows en la maquina "cliente").

Nota: El menu principal se representa en la pantalla como un


componente no visual, pero lo podemos ver durante ejecucion y diseño.
La razon es que Delphi, en su enfasis de dar un "look-and-feel" identico al
diseñador, decidio poner un menu "de adeveras" en tiempo de diseño
(para que responda a los cambios globales de Font y color en tiempo real,
etcetera. Pero si usted pudiera modificar ESE menu en-linea, Delphi
tendria que encadenar el codigo de modificacion de TMainMenu dentro del
ejecutable final, lo cual agregaria "basura" a su ejecutable (el no hacerlo
violaria las reglas de orientacion a objetos). Asi que tenemos en este caso
en particular un componente no visual que se despliega en la pantalla (o
un componente visual con un editor por separado, como lo quiera ver).
Cuando veamos como escribir editores de propiedades en Delphi todo
esto quedara muy claro. Si no entiene, por mientras "tenga fe" en que
Delphi esta bien diseñado, pero MainMenu es un caso un tanto especial.

Para editar el MainMenu, haga doble-click en el icono del menu (componente no visual) y vera un
editor de menus.

Como utilizamos un componente no visual? De hecho, no es muy dificil, pero si


requiere un poquito de Codigo. Al ponerlo en la forma Delphi se encarga de
crearlo y destruirlo sin tenernos que preocupar. Veamos el codigo que Delphi nos
ayudo a escribir. Dentro de la ventana de diseño de su aplicacion (como la que se
muestra arriba), vaya al menu de File y seleccione Open. Delphi ira al evento de
FileOpen dentro de su codigo (que por cierto, Delphi ha escrito para usted con
todo y logica basica, listo para que lo implemente):

procedure TMainForm.FileOpen(Sender: TObject);


begin
if OpenDialog.Execute then
begin
{ Add code to open OpenDialog.FileName }
end;
end;

Este evento, que esta enlazado al evento "Onclick" del item del menu FileOpenItem, nos muestra
que para accesar uno de estos objetos "invisibles" solo tenemos que mencionarlo por nombre y
llamar uno de sus "metodos" (procedimientos o funciones de los objetos) con un punto en medio,
en el formato Objeto.Metodo. (de la misma manera en que C++ utiliza el formato Objeto-
>Metodo ). En el caso de todos los Dialogs estandar de Delphi que se encuentran en la pagina
"Dialogs" de la paleta de componentes (Open, Save, Print, Print Setup, Find, etc), el metodo para
mostrar el dialogo al usuario se llama Execute. Execute es una funcion que devuelve un valor
Boolean (logico). Si Execute devuelve True, quiere decir que el usuario completo el dialogo con
exito y salio con OK. Si Execute devuelve False, quiere decir que el usuario no completo el dialogo.
Es por esto que Delphi ha encerrado la seccion donde dice "Añada codigo para abrir..." dentro del
If-Then. De este modo el archivo solo abrira cuando el usuario seleccione OK (y Cancel funcionara
tal como esperamos como usuarios, no haciendo nada). Si se asoma al codigo de Save, print, etc.,
vera que es el mismo asunto.

Ahora que ya probamos nuestro programa comencemos a hacer cosas para que de hecho haga
algo. Dijimos que vamos a crear un editor de textos. Pues comencemos. En la paleta de
componentes, vaya a Win32 y seleccione el componente RichEdit. Ponga uno de estos en medio
de la forma. En el Object inspector, cambie la propiedad Align a alClient.

Nota: Delphi tiene nombres para diferentes items asociados con un tipo
de propiedad. Estos se llaman "enumeraciones" o "enums". En este caso,
la propiedad Align del objeto TControl (y sus derivados, que incluyen a
TRichEdit) es de tipo TAlignment, que puede ser alNone, alTop,
alBottom, alLeft, alRight o alClient. Internamente durante compilacion,
Delphi compila esto en un set numerico. C tiene capacidades parecidas a
traves de la directiva typedef enum, pero en Delphi es mucho mas
simple (por supuesto). Internamente, las imagenes creadas por Delphi con
este metodo en memoria son identicas a las de C y por ende, es igual de
rapido.

Veremos que el RichEdit contiene el texto "RichEdit1". Esto como que no va en un programa, asi
que vamos a borrarlo. Haga doble click en la propiedad "Lines" y vera una ventanita para editar
textos. Elimine el texto.

Ahora vamos a escribir un poco de codigo, asi que truenese los dedos y agarrese del teclado
(como yo) 

Vamos de nuevo a nuestro codigo. Primero necesitamos permitir al usuario grabar el texto que
escriba en el RichEdit. Asi que vayamos a File-Open utilizando el menu dentro del
diseñador. Delphi nos mostrara el codigo dentro de esa seccion. En el codigo,
escriba lo siguiente:

procedure TMainForm.FileOpen(Sender: TObject);


begin
if OpenDialog.Execute then
begin
{ Add code to open OpenDialog.FileName }
RichEdit1.Lines.LoadFromFile(OpenDialog.Filename);
end;
end;

Fue solo una linea... Pero una linea bastante poderosa. Vamos a probarla primero y despues
explicare. Ejecute su programa. Ahora, antes de hacer nada, ejecute WordPad (el editorcito que
viene con Windows). Escriba algo bonito, con Fonts y cosas. Ahora grabelo a disco, seleccionando
el formato RTF. Corra nuestro programa (que ahora puede leer un archivo) y ejecutelo. Cargue el
mismo archivo. Ahora compare:

Heeey... No esta mal para una linea de codigo, verdad? Nuestro programa, aunque todavia no
tiene botones para edicion especifica de fonts y colores, soporta los mismos. Tambien, si se da
cuenta, soporta "word wrapping". Felicidades! Acaba usted de terminar de hacer la parte mas
pesada de los editores de Windows 3.1, el soporte interno de Fonts.

Esto es codigo optimizado, compilado en un ejecutable de 273K en mi caso. Si voy a Project-


Options y elimino el "debug Info" puedo reducir el tamaño un poco. Y si decido utilizar "paquetes"
Seleccionando Project- Options-Packages- Compile with Runtime Packages del menu de
Delphi, mi ejecutable se reduce a la irrisoria cantidad de 34K, haciendolo un paquete facil de
distribuir por el web.

Nota: Paquetes son un tipo de DLLs especifico para Delphi y C++ Builder
que son capaces de pasar objetos en vez de solo tipos basicos (usan la
extension DPL y se encuentran en Windows\System32). Los archivos son
compartidos y cada objeto esta implementado en un paquete. Usted tiene
que poner en el paquete de instalacion los archivos DPL en los que los
objetos con los que programo se encuentran, de preferencia en un
"paquete de web" (CAB) diferente. En el servidor de Borland hay un
paquete CAB con solo los DPLs al cual usted puede hacer referencia en las
dependencias de su propio CAB. De este modo el navegador solo baja el
paquete con los objetos de Delphi una vez, y las veces subsiguientes baja
unicamente 32K. Tambien hay un CAB por separado para la Database
Engine que solo se usa si usted usa tablas o queries.

Como funciona? Bueno, de hecho es muy simple: El objeto RichEdit ya tiene


soporte para diferentes tipos de letra, y entiende el formato RTF. La propiedad
Lines del objeto es a su vez un objeto de tipo TStrings. TStrings es una muy veloz
encapsulacion de una lista de cadenas de caracteres. Cada linea del control
TRichEdit esta "mapeada" a una linea del objeto TStrings contenido dentro del
RichEdit. RichEdit despliega el contenido del TStrings siguiendo las reglas del
formato RTF. Por ejemplo, la ultima seccion del RTF contiene, en realidad, lo
siguiente:

{\rtf1\ansi\ansicpg1252\deff0\deftab720{\fonttbl{\f0\fswiss MS Sans Serif;}{\f1\froman\fcharset2


Symbol;}{\f2\froman Times New Roman;}{\f3\froman\fprq2 Bookman Old Style;}{\f4\fswiss\fprq2
Arial Black;}{\f5\fswiss\fprq2 Tahoma;}{\f6\fswiss\fprq2 System;}} {\colortbl\red0\green0\blue0;\
red0\green0\blue255;\red0\green255\blue0;\red0\green255\blue255;\red128\green0\blue0;\red128\
green0\blue128;\red0\green128\blue0;\red255\green0\blue0;} \deflang1033\horzdoc{\*\fchars }{\
*\lchars }\pard\plain\f2\fs32 Tengo que poner \plain\f3\fs32 Tipos de letra \plain\f5\fs52
diferentes\plain\f3\fs32 \plain\f2\fs32 y \plain\f4\fs48\cf4 c\plain\f4\fs48\cf1 o\plain\f4\fs48\cf2 l\
plain\f4\fs48\cf3 o\plain\f4\fs48\cf7 r\plain\f4\fs48\cf5 e\plain\f4\fs48\cf6 s\plain\f2\fs32 .}

RichEdit interpreta esto como los diferentes colores y tipos de letra especificos. Imaginese cuanto
tiempo nos han ahorrado implementando todo esto! Un poco de credito debe ir a Microsoft, ya que
RichEdit es uno de los controles estandar de Win95 definidos en commctrl32.dll - pero ellos
cambiaron las complejidades de usar el formato RichEdit con las complejidades de mantener
Window Handles y mensajes de Windows a todo momento. Delphi nos da un componentito que
ponemos en la formay punto.

El Objeto TStrings es uno de los objetos internos que mas se utilizan en Delphi. Tiene la capacidad
de grabarse y cargarse del disco con una metodo (LoadFromFile/SaveToFile), de buscar una
cadena dentro de la lista con el metodo IndexOf, de mantener un puntero de memoria por cada
objeto dentro de la cadena, lo cual lo hace ideal para poner descripciones de texto en una lista de
objetos (como por ejemplo una lista de bitmaps con nombres de archivo) en memoria, y
muchisimas cosas mas. Vea la ayuda de TStrings para saber todo lo que puede hacer con listas, y
por ende, todo lo que puede hacer con la propiedad Lines del RichEdit.

Bueno, yo ya explique como cargar archivos, ahora es responsabilidad de usted terminar el


programa y hacerlo que tambien grabe. Recuerde que Windows graba con dos eventos diferentes;
save y save as. Save debe funcionar solo cuando el FileName de SaveDialog no este especificado.
De otro modo, Save debe llamar a Save as. Si se siente aventurero, trate de hacerlo imprimir (es
muy facil). Notara que RichEdit "sabe" imprimir en colores y con sus tipos de letra, sin
preocuparse por drivers, etc (lo cual sacara lagrimas de felicidad a todos los que vienen de
programar ambientes DOS)...! Buena suerte!
Capítulo 5. Acceso a Bases de Datos en Delphi
En este capítulo veremos como Delphi maneja el acceso a bases de datos, incluyendo las librerías
requeridas y los componentes que Delphi utiliza. Se asume que usted sabe lo que es una tabla y
ha usado sistemas de base de datos básicos, como dBase. No se asume experiencia previa con
SQL, pero ayudaría :-) En este curso estaré utilizando SQL local en general. Si hay algo para lo cual
necesito utilizar una base de datos grande (porque SQL local no soporte esa función o que no
funcione como debe ser para efectos de los ejemplos), utilizaré formato generico SQL-92
exclusivamente (pero si deveras quiere saber exactamente lo que uso, estoy utilizando InterBase,
que viene con Delphi 3 Profesional y Cliente/Servidor).

Estructura de Acceso de Datos en Delphi

Desde los inicios de Delphi, Borland decidió crear una estructura de acceso de datos abierta. Una
buena parte de la librería de clases VCL esta dedicada a trabajar con acceso de datos de una
manera abierta y flexible. Delphi y C++ Builder tienen métodos de acceso a bases de datos únicos
en la industria por su flexibilidad y facilidad de uso.

Nota: Si usted tiene C++ Builder (BCB), la estructura de acceso de datos


es idéntica a la de Delphi, gracias a que comparten la librería de clases
VCL. La version 1 de BCB tiene el VCL de Delphi 2, y la version 3 de BCB
tiene el VCL de Delphi 3 (mas unas cuantas cosas que están en el nuevo
C++ y que Delphi seguramente tendrá).

Gracias al hecho de que todo en Delphi es un objeto, los creadores de Delphi crearon, entre otros,
un componente abstracto llamado "TDataset". Como su nombre lo indica, un dataset es un "set de
datos". Como podra ver, el set de datos abstracto no especifica el origen de la base de datos,
modo de conexión o marca del producto que está en el servidor. Ni siquiera especifica si nuestro
set de datos es una tabla física, un query de SQL o un archivo de texto! De esta manera se
generaron los componentes que heredan de TDataset bajo una base común.

Los componentes TTable y TQuery son los componentes mas comúnmente usados para acceso
básico a bases de datos (pero no los únicos). Estos componentes representan una tabla y un query
de SQL, respectivamente. Para mantener el acceso de datos compatible con los diferentes
productos de Borland, se desarrolló una serie de librerías redistribuibles llamada "Borland
Database Engine" (BDE). Esta librería debe ser instalada en la máquina del cliente para que TTable
y TQuery funcionen correctamente.

El Borland Database Engine es primordialmente una librería para manejar cursores de SQL.
Muchos lenguajes son capaces de operar con un sólo "renglón" de datos de la tabla a la vez, por lo
cual el manejo de los cursores de SQL no es muy satisfactorio. Pero Delphi utiliza el Database
Engine como una "traducción" de cursores de SQL en el formato de Queries y Tablas interno de
Delphi. Ademas, el Database Engine nos permite accesar el origen de los datos (la base de datos
para la cual estamos escribiendo) a través de "drivers" intercambiables de acceso directo, o si asi
deseamos, utilizar ODBC para accesar estos datos.

Un cursor es un concepto de SQL que se refiere a un set de renglones, un


orden en que se encuentran esos renglones, y un "renglon actual" dentro
de ese orden. Por ejemplo, cualquier "set de resultados" de un enunciado
SELECT de SQL, si no devuelve un error, devolvera un cursor (vacío o con
información).
Para soportar las muchas maneras en que Delphi puede accesar datos, y para facilitar
enormemente al programador preocupaciones acerca de cambios en la base de datos que utilizan
tus programas (por ejemplo: "Chin, soy programador de Sybase y ahora la compañía cambio a
Oracle... Oracle y Sybase utilizan DLL's de acceso muy diferentes... AAAARRRRGHHH!"), Borland
ha creado un muy elaborado set de BDE (Borland Database Engine), drivers para BDE y
componentes en el VCL. Como resultado, usted puede programar de una manera muy parecida
(casi idéntica!), ya sea que usted utilice tablas de dBase (a traves de una parte del BDE conocido
como Local SQL) o bases de datos grandes como Oracle, Sybase o Interbase.

El siguiente diagrama muestra las maneras en que Delphi y la base de datos


pueden conectarse (está un poco simplificado, ya que hay algunos componentes
intermedios - para mayor información consulte la documentación de Delphi):

¿Complicado? No se preocupe, esta imagen cubre todas las posibilidades de acceso de datos,
incluyendo la nueva tecnología MIDAS, asi que no lo tiene que entender en su totalidad.
Usualmente usted solo seleccionará uno de los métodos de acceso a bases de datos (dependiendo
en su software existente y necesidades de conexión), y se olvidará de todos los demás. Cuando
siga las secciones prácticas en los siguientes capítulos, refiérase a este diagrama para "descubrir"
qué modo de acceso de datos estamos utilizando en cada sesión práctica. Esta estructura pone
todo el poder de acceso a bases de datos de muy diferentes tipos en sus manos, en forma de
simples componentes que usted puede poner en sus formas. Al mismo tiempo, le proporciona
suficiente poder para escribir su propia estructura de base de datos si eso es lo que usted quiere,
sin cambiar los componentes en el lado del cliente.

¿Porqué SQL?

Muchos programadores de Clipper, dBase y FoxBase me preguntan "qué


onda con SQL, y por qué es tan importante aprenderlo?". La respuesta es
sencilla: COMPATIBILIDAD. Si bien es cierto que muchas compañías
tienen su propio "tipo" de SQL, la especificación SQL-92 es soportada por
todos y cada uno de los lenguajes de bases de datos grandes. Ademas,
Microsoft y Borland han añadido soporte SQL para todos sus lenguajes. El
resultado de esto es que, si usted aprende SQL-92, usted puede
programar básicamente para cualquier base de datos sin importar su
tamaño y complejidad. Claro está, despues de aprender SQL, se puede
especializar en cualquier "sabor" de SQL en particular. Pero recuerde,
cualquier cosa que programe en Delphi para un específico "tipo" de SQL
funcionará, pero le hara mas dificil moverse a otro tipo de servidor en el
futuro. Dependerá de usted hacer este tipo de decisiones.

Un buen libro de SQL es "SQL for Dummies", por Allen G. Taylor. Ademas
de ser un libro de SQL en general muy facil de entender, el autor utiliza
las herramientas de Delphi! El libro explica SQL en general sin especificar
una versión de base de datos en particular (Yo sospecho que, ya que esta
usando las herramientas de Delphi, esta programando en Interbase). Si
usted cree que le pueda interesar migrar a una base de datos SQL en el
futuro y utiliza Delphi o C++ Builder, programe en Delphi como si ya
tuviera una, utilizando los drivers de SQL local de Paradox, dBase o
MSAccess. Despues le será mas facil migrar su base de datos.

Configuración del BDE - Aliases

Un Driver de BDE es un componente de software que actua como intermediario entre la librería de
cursores del BDE y los datos Físicos. Delphi viene con drivers para dBase, Paradox e Interbase,
además de un driver para ODBC, que le permite accesar cualquiera de las bases de datos que
ODBC soporta. En ediciones cliente/servidor, Delphi cuenta con drivers "nativos" de SyBase,
Oracle y MS-SQL Server.

ODBC es un producto de Microsoft que es utilizado para accesar datos con


Office, Visual Basic y otras aplicaciones de Microsoft y de terceros. Es
analogo al BDE en el sentido de que tiene drivers que actuan como
intermediarios entre los datos y conexiones físicas y el software de
acceso, pero es diferente porque ODBC se limita a traducir llamadas SQL
a la conexion fisica, sin libreria de cursores que traduzca los resultados.

Esta estructura requiere de un concepto llamado "Alias". Un alias de BDE es un conjunto de


especificaciones que describen el metodo que el BDE utilizará para accesar el servidor, incluyendo
driver físico, mapa de caracteres internacionales, etc.

Los Aliases le permiten especificar todos aquellos parámetros que hacen a su aplicación depender
de un servidor en particular afuera de su ejecutable, en un archivo de configuración en la maquina
del cliente. El programa de instalacion InstallShield que viene con Delphi Professional y Client
Server (no estoy seguro si viene con Delphi Standard) le permite instalar el BDE con su aplicación
y especificar los aliases necesarios, respetando las configuraciones ya existentes.

Componentes No Visuales de Acceso a Datos

Del lado del cliente en Delphi, la paleta de componentes llamada "Data Access" contiene todos los
componentes no visuales que usted puede poner en su aplicación para conectarse a una base de
datos. Los componentes más importantes incluyen:

TSession

Un alias se conecta a una "sesión", representada por el componente TSession. Esta sesión es una
conexión Física a la base de datos. Los programas de Borland pueden compartir sesiones
globalmente, y cada programa puede tener cualquier número de sesiones simultáneas. De este
modo, usted puede compartir una sola conexión (sesión) a la base de datos para economizar
licencias, sin importar cuantos ejecutables este utilizando para accesar los datos, o si las licencias
por conexion no son limitadas en su base de datos, puede utilizar varias sesiones en una sola
aplicacion para programar sus queries con multitarea.

Incluso si usted no pone un componente TSession en su aplicación, Delphi define uno por cada
aplicación, representado por la variable de objeto global "Session".

TDatabase

TDatabase es la representación de una base de datos. Tal como en su servidor de SQL usted
puede crear más de un "contenedor de base de datos", Delphi puede compartir una conexión
(TSession) entre varios contenedores de bases de datos (TDatabase). Tal como en la sesión, si
usted no pone un TDatabase en su aplicación Delphi especifica uno en la variable de objeto global
"Database".

Programadores de dBase/Clipper: Una base de datos, en el sentido de


SQL, es una colección de tablas, vistas, procedimientos SQL y tipos de
datos. En los viejos tiempos de dBase, muchos programadores
"entendían" que una base de datos era un archivo DBF, y el concepto de
Tablas no existía. Ahora, si usted utiliza DBF o Paradox, Delphi entenderá
por base de datos el directorio donde se encuentran los DBFs en
cuestión, y las Tablas serán cada uno de los DBFs. Esto quiere decir
que si usted está acostumbrado a poner sus DBFs en diferentes
subdirectorios (que es algo que yo acostumbraba a hacer en
Clipper/dBase), cada directorio representará un TDatabase diferente. En
Delphi un TDatabase para tablas locales no especifica el tipo de tabla, así
que usted puede mezclar tablas Paradox y dBase en el mismo directorio
sin problemas.

TTable

TTable es la representación de una tabla, y es a lo que están acostumbrados los programadores


en Clipper. TTable representa una tabla entera en Delphi. TTable contiene información acerca del
tipo de tabla (que solo se usa en tablas locales - paradox, dbase, etc) y del nombre del índice, así
como filtros. TTable tiene entre sus métodos, First, Next, Last, etc.

Programadores dBase/Clipper/Paradox: Es MUY IMPORTANTE


aprender que, mientras ustedes estarán más inclinados en un principio a
usar TTable que su "primo" TQuery, TTable representa la tabla COMPLETA.
Esto puede parecer trivial para los usuarios de bases de datos locales,
pero en SQL es muy importante. El abrir un TTable por sí mismo (sin filtro)
contra un servidor SQL hara que Delphi ejecute un SELECT * FROM
LATABLAQUESEA, lo cual, en un ambiente de producción, ¡puede querer
decir traerse dos o tres millones de renglones por el cable! En general
TTable no es muy usado en un ambiente Cliente/Servidor (aunque tiene
sus usos). ¡Tenga cuidado!

TQuery

TQuery es la representación de cualquier comando de SQL que regresa un cursor de SQL (ya sea
de tipo SELECT o un "Stored Procedure" - vea TStoredProc). Este cursor de SQL se comporta como
una tabla. Los programadores con experiencia en SQL encontrarán a TQuery muy útil, ya que se
comporta como un TTable (en el sentido de que tiene First, Next, Last, etc), pero al mismo tiempo
es un comando de SQL. El programador de SQL no tiene que hacer "Fetch". Además, cuando el
usuario edita campos asociados a un TQuery, Delphi se encarga de generar los comandos
"UPDATE" y "DELETE" si el resultado del Query es Read/Write (vea TUpdateSQL).

Programadores dBase/Clipper/Paradox: Probablemente una de las


mejores cosas que Delphi tiene para los usuarios de tablas locales es que
Delphi tiene un pequeño SQL a traves de los drivers de tablas locales. Esto
quiere decir que usted puede programar TQuery como si su tabla DBF
tuviera un "servidor SQL". De esta manera, usted puede mantener (si
programa con atención a los detalles particulares de cada version de SQL)
una sola base de código para tablas locales y bases de datos gigantescas.

TDataSource

El Datasource es, como su nombre lo indica, una representación del "origen de los datos".
DataSource no requiere el BDE, pero es el componente que "mapea" los componentes visuales de
base de datos con los no visuales. El hacer un componente intermedio es importante porque de
este modo podemos tener varias representaciones de los mismos datos sin tener que "atar" la
representación de los datos en pantalla a la representación "física" de los datos. Un DataSource se
conecta a su vez a cualquier componente tipo Dataset, como TQuery, TTable, TClientDataset, ¡o el
que usted haya creado! DataSource nos permite ser consistentes en la representación de nuestros
datos en pantalla sin preocuparnos de donde vengan los mismos (Tablas, queries, o nuestros
propios metodos).

TUpdateSQL

En SQL-92, existe una limitación en cuanto a los enunciados "Select". Existen muchas
circunstancias en las cuales SQL regresará un cursor de solo lectura, en vez de el cursor de
Lectura/Escritura que nos gustaría obtener. Por ejemplo, si el enunciado SQL especifica una unión
de tablas, SQL nos devolverá un cursor que podemos representar como el resultado de un Query
en Delphi, pero no podremos editar el resultado. Obviamente esta limitación es muy severa si
queremos hacer ciertas "maravillas" con nuestra aplicación (queries editables con referencias en
texto es una de estas cosas).

Aqui es donde UpdateSQL hace su magia. Todos los queries tienen un Edit, Insert y Delete.
UpdateSQL puede ser encadenado a un query cuyo resultado será de lectura unicamente para
decirle a Delphi qué vamos a hacer cuando el usuario edite, inserte y borre un registro. En el Edit,
podemos poner un SQL UPDATE, en Insert podemos poner un SQL INSERT, etcétera. De este
modo nos "brincamos" la limitación de SQL utilizando sentencias específicas, pero lo mantenemos
automatizado gracias a Delphi.

TStoredProc

Aunque TQuery puede ejecutar un stored procedure que devuelva un valor (y tenemos que usar
un TQuery si queremos recuperar ese valor), a veces el stored procedure no devuelve nada.
TQuery espera un valor de regreso, y nos devolvera un error si el servidor no devuelve un valor.
Por este motivo, para esos procedimientos necesitamos un objeto que nos permita ejecutar un
comando SQL sin esperar ninguna respuesta. TStoredProc es ese comando.

En SQL, un "Stored Procedure" es un procedimiento escrito en lenguaje


SQL. Puede ser tan sencillo como un Select con variables y un "join" de
tablas, o tan complicado como un procedimiento Batch que calcula los
salarios de todos los empleados y los pone en la tabla de nómina.
Existen más componentes no visuales de acceso a datos, pero estos son suficientes para hacer
muchas aplicaciones cliente servidor sin problemas. Cuando veamos "Multi-Tier" y Objetos de
Negocios (Business Objects), que es una nueva capacidad de Delphi Cliente/Servidor, veremos
otros modos de acceso de bases de datos un poco más "indirectos".

Componentes Visuales de Acceso a Datos

Los componentes visuales de base de datos son los que ponemos directamente en la forma para
desplegar información y permitir al usuario editarla. Todos los componentes de este tipo son
llamados "Data-aware", y tienen el prefijo "DB". De este modo, un componente de edición "Edit"
en su versión "Data Aware" es llamado "DBEdit". ComboBox se convierte en "DBComboBox".
Muchos de los componentes visuales (Incluyendo el Grid) tienen una versión "Data Aware".
Además, usted puede crear sus propios componentes data aware.

Ademas, existe un componente llamado "DBNavigator", que es una serie de botones "mapeados"
a los comandos Next, Prior, Last, Edit, Delete, etc., de cualquier DataSource.

Todo esto le permite a usted poner unos cuantos componentes data aware en su forma (junto con
un DBNavigator), conectarlos a un DataSource (que se encontraria conectado a un Dataset
abierto), y correr su programa, y asi de fácil tendria usted una aplicacion básica con acceso a base
de datos, ¡sin tener que escribir una sola línea de codigo! Lo cual nos lleva a nuestro
próximo capitulo, donde haremos una aplicación de base de datos casi sin tener que usar código!

Capítulo 6. Escribiendo una Aplicación de Base de Datos

En este capítulo escribiremos una aplicacion pequeña de base de datos. Como necesitamos
asegurar que todos tengamos los mismos datos, comenzaremos por utilizar los datos que vienen
con Delphi, en el alias DbDemos.

Nota: En este ejemplo, aunque estamos utilizando el alias DbDemos (que


es un directorio con tablas de dBase), estoy programando como si
estuvieramos desarrollando para un servidor SQL (dBase, Paradox, etc).
Con esto, mi intención es convencerlo de que: 1. Usted puede (y en mi
opinion debería) programar en SQL local para hacer más fácil la migración
posterior a bases de datos SQL, y 2. Si usted comprende como funciona
Delphi en programación con un TQuery, la programación usando un
TTable es sencilla y trivial. Además, usted estará listo más rápido para
programación en SQL, y un desarrollador de Cliente/Servidor es mejor
pagado que uno de "tablas". El saber y entender SQL es, hoy por hoy, una
de las mayores ventajas para un desarrollador, ya que cualquier paquete
de base de datos entiende al menos una "especie" de SQL. Si usted quiere
usar una versión poderosa de SQL para saber cómo es programar para
ella, Delphi Professional y Client/Server cuentan con una versión de
desarrollo de Interbase. Pero antes de desarrollar sobre Interbase,
asegúrese de entender el contrato de licencia, donde Interbase se cobra
"por asiento", como Oracle, Ms SQL Server o Progress. Pero usarlo para
aprender SQL es gratis.

Accesando Datos en Delphi

Delphi utiliza una librería llamada BDE (Borland Database Engine) para su acceso
a bases de datos. El acceso de datos en Delphi es muy diferente, pero análogo, al
acceso de datos en lenguajes como Clipper, Foxpro y dBase. En estos lenguajes,
usted tiene "áreas" de trabajo. Dentro de esas areas usted puede tener abierta
una tabla, y le puede decir a esa tabla que vaya al principio, al final, o brinque o
retroceda. Bueno, en principio, en Delphi puede usted hacer lo mismo:

En Clipper (area) En Delphi (dataset)


GO TOP Dataset.First;
GO BOTTOM Dataset.Last;
Skip Dataset.Next;
Skip -1 Dataset.Prior;

En Delphi usted puede tener un sinnúmero de estas "areas", pero como en Delphi todo es un
objeto, obviamente tienen su nombre. Las clases que representan sets de datos navegables
(datasets) son llamadas "TDataset".

Nota: Me refiero a "sets de datos navegables" en lugar de especificar


tablas o áreas de trabajo. ¿Porqué es esto? Un set de datos navegable en
Delphi puede representar virtualmente cualquier cosa. Delphi tiene una
clase llamada TCustomDataset, que implementa los conceptos básicos de
la navegación de datos (First, Next, Last, etc). Bajo esta clase,
customBDEDataset está implementado. Esto es un set de datos abstracto
que utiliza el BDE. Una vez implementado BDEDataset, todos los sets de
datos (TQuery, TTable) están implementados bajo el mismo. ¿Porqué
tanta complicación? ¿Porqué no simplemente hacer acceso de datos
directamente? Delphi tiene como concepto básico la implementación de
clases y programación por objetos. El uso de estas clases intermedias
garantiza que usted puede hacer acceso a datos sin utilizar el BDE, por
ejemplo (utilizando CustomDataset en vez de CustomBDEDataset). De
hecho, usted puede manejar el acceso de datos de una manera
totalmente diferente mientras Delphi cree que está utilizando los mismos
datasets. El cambio en su programa se vuelve mínimo.

Vamos a entrar en materia y comenzar nuestra primera aplicación de base de datos. Utilizaremos
los datos que vienen con Delphi, ya que son los que nos aseguran que todos veamos las mismas
pantallas. Más adelante veremos otros tipos.

Con Delphi recién abierto, busque en la paleta y ponga los siguientes


componentes en su forma, ya sea utilizando doble-click (que pone los
componentes automáticamente) o haciendo click en uno de los componentes y
haciendo click donde lo quiera ver en la forma. Para cambiarle de nombre,
seleccione "name" en el object inspector y escriba el nombre nuevo.

De la página.. Inserte el componente... Y Cambie las propiedades:


Data Access TQuery Name: "qryClientes"
Data Access TDataSource Name: "dsClientes"
Data Controls TDBNavigator Name: "dbnNavegador"
Los componentes Query y DataSource que acabamos de insertar representan las partes "no
visuales" del acceso a base de datos. TQuery es una representación de un Query de SQL, mientras
que TDataSource nos permite conectar controles "data aware" a su aplicación. Si todo esto suena
un tanto confuso no se preocupe, se volverá muy claro cuando el programa esté corriendo.

Estándares, comentarios y notación.- Como programador profesional,


tarde o temprano se dará cuenta de que las "convenciónes de código" (los
estándares que usted utiliza para nombrar sus objetos, indentar y estilo
en general) es muy importante. Aunque esta convención es algo que es
un tanto personal, es importante tener en cuenta que es importante tener
una. Cualquier programador veterano te dirá que aunque la convención
sea muy diferente, es más fácil leer el código de alguien que tiene una
(aunque sea muy diferente a la nuestra) que el de alguien que no tiene
ninguna. Así que aquí van dos de mis primeros estándares de
programación: Primero, SIEMPRE póngale nombre a todo. Cualquier
control que ponga en la forma debe tener un nombre puesto por usted, no
por Windows o Delphi. Eso hace su programa mucho más legible cuando
regresa después de un año y necesita saber que hacía su programa.

¿Como nombrar sus objetos y variables? La mayoría de los programadores


utilizan una de las miles de variaciones de la "notación húngara", creada
por Charles Simonyi en Microsoft. La notación húngara especifica un
prefijo que nos dice qué a clase de objeto o variable el nombre se refiere,
y después el nombre, primero mayúscula y después minúsculas. Lo más
usual es usar "i" para Integer, "b" para Boolean (lógico), "s" para string o
"c" para caracter, etcétera. Yo utilizo ciertas extensiones para especificar
objetos de Delphi como "qry" para Query, "ds" para DataSource, o "dbn"
para DBNavigator. Esto hace el código más legible y fácil de seguir.

También es muy importante poner comentarios en el código. No existe


programa con demasiados comentarios, así que explique todo lo que Ud.
quiera. Mientras escribe, imagíne que usted es un maestro que quiere
enseñar el código a sus alumnos para algún ejercicio.

Ahora, héchele una ojeada a su código. Delphi ha insertado declaraciones dentro


de su declaración de la forma especificando el nombre de la variable y el tipo de
objeto que representa:

TForm1 = class(TForm)
qryClientes: TQuery;
dsClientes: TDataSource;
dbnNavegador: TDBNavigator;
private
{ Private declarations }
public
{ Public declarations }
end;

Ahora, vaya al TQuery y cambie la propiedad "Databasename" a DBDemos. Lo puede escribir


textualmente o seleccionarlo de la lista. DBDemos es un alias local que apunta a su directorio de
Demos de Delphi. Lo puede ver utilizando el programa BDE Administrator que viene con Delphi. Ya
que tenga especificado el contenedor de base de datos que desee usar por medio del alias, puede
usted lanzar comandos de base de datos a cualquier tabla que se encuentre dentro del
contenedor. Si usted en esta propiedad especifica un alias que esté configurado a una base de
datos SQL, entonces Delphi hará una conexión a la base de datos y mostrará la caja de "login"
para que usted escriba su nombre de usuario y clave de acceso en la base de datos.

Ahora seleccione el TDatasource. En la propiedad Dataset, seleccione qryClientes.


Tal como en el párrafo anterior, puede seleccionarlo de la lista. Esto quiere decir
que, la "fuente" de los datos va a tomar la información del set de datos
qryClientes. Finalmente, en la propiedad DataSource de su TDBNavigator,
seleccione dsClients. De inmediato podrá notar que los botones del navegador se
desactivan, volviéndose grises y opacos. Esto es porque los componentes "data-
aware" de Delphi son dinámicos, es decir, se comportan en modo de diseño tal
como se comportarán en modo de ejecución. Como su Query está vacío y cerrado,
el navegador está desactivado.

El TDbNavigator se desactiva cuando el query está cerrado.

¿Como le hacemos para que se active el Query? Lo que vamos a hacer es aprovechar al máximo
las capacidades de diseño de Delphi. Primero, necesitamos hacer un Query en SQL que Delphi
pueda utilizar en el alias DbDemos para que Delphi sepa la información de la tabla que podemos
utilizar para diseñar.

Seleccione el Query, y haga doble-click en su propiedad "SQL". A continuación verá el "Editor de


listas de textos" (String List Editor). Este editor es un editor de textos muy simple y chiquito que
simplemente permite escribir más de una línea de texto a la vez. Escriba lo siguiente y después
presione OK

SELECT * FROM "CLIENTS.DBF" CLIENTES


WHERE CLIENTES.ACCT_NBR = :Cuenta

La palabra ":Cuenta" le dice a Delphi que este query necesitará un parámetro


llamado Cuenta, para el número de cuenta. Ahora, haga Doble-click en la
propiedad "Params" del Query. Seleccione tipo de datos Integer y valor 1023495
por ahora. Después le daremos al usuario oportunidad de cambiarlo.

Asegúrese de que el número de cuenta sea el correcto (consulte la tabla usando Database
Explorer si tiene dudas) para que su query devuelva un registro. Si su query no devuelve nada,
todavía podrá diseñar (Delphi devuelve la información de los campos sin registros), pero no verá el
registro en tiempo de diseño.

El diseñar especificando siempre un número de cuenta (o la "clave


primaria") es algo que SIEMPRE debemos de hacer en ambientes SQL, a
menos que estemos SEGUROS de que la tabla está vacía o no tiene
muchos registros. Delphi ejecutará este SQL cuando activemos el query
para elegir campos, preparar relaciones o cualquier cosa. Aunque Delphi
nunca abre un query dos veces si no es necesario, si usted no pone una
sentencia WHERE en una base de datos grande, tendrá que esperar a que
el SELECT completo ejecute antes de continuar con su diseño. Tenga esto
en mente cada vez que haga un Select sin WHERE, ya sea en diseño o en
tiempo de ejecución.

A continuación, vaya a la propiedad "RequestLive" de su Query y póngala en "True". Esto es


importante porque SQL siempre devuelve resultados "Read-Only", o "muertos" (dead) a menos
que especifiquemos que nuestro query debe ser "vivo" (live). Esto querría decir que nuestro
usuario no podría editar el registro! Hay otras condiciones que podrían no permitirnos el recibir un
query "vivo", pero las veremos más adelante. Cualquier manual de SQL le explicará qué clase de
queries pueden ser modificados y cuales no.

Ahora lo que queremos hacer es diseñar usando todas las ayudas de Delphi, así que, con el Query
todavía cerrado, haga doble-click en el query. A continuación verá una ventana vacía que dice
Form1.qryClientes. Ésta es la lista de registros existentes en el resultado de nuestro query
"Clientes". Presione Control-A (o haga click con el boton derecho del mouse y seleccione "Add
Fields"). Delphi ejecuta el Query internamente y nos proporciona la lista de las "columnas"
(campos) del resultado del Query. Todos los campos están preseleccionados (Delphi asume que
usted quiere añadir todos los campos a la forma). Así que simplemente presione {Enter} para
aceptar el añadir todos los campos a su definición.

La información que Delphi recupera para saber la estructura del archivo


se llama Metadata. Esto quiere decir a groso modo "datos acerca de los
datos"; es decir, la estructura física de la información resultante del
Query. Para extraer el Metadata, Delphi ejecuta el SQL en su Query y
extrae la información a partir de los datos recibidos. Si el query no
devuelve nada, pero es sintacticamente correcto, Delphi también recibe el
metadata, pero sin registros.

Ahora usted tiene una definicion de campos como parte de la definición de su


forma. Puede usted comenzar a diseñar. Cuando usted selecciona uno de los
campos, el Object Inspector muestra las propiedades de los campos. Mientras no
cambie propiedades importantes como Largo y Nombre del campo, puede usted
cambiar la apariencia, el "display name", y el formato de edición (Edit Mask) del
campo en tiempo de diseño. Por ejemplo, seleccione el campo Last_Name y trate
de cambiar su "DisplayName a "Apellido". El nombre del campo para efectos de
diseño sigue siendo el mismo, pero ahora desplegará "Apellido" en el TLabel
cuando lo pongamos en la forma. Además, programáticamente, el objeto
qryClientesLAST_NAME, de tipo TStringField, tiene como propiedad "DisplayName"
el texto "Apellido". Esto será útil para hacer mensajes de error para nuestros
usuarios...

Nota: Aunque es muy bonito el poder hacer esto en tiempo de diseño, el


atar su forma a los datos de esta manera quiere decir que, cuando usted
cambie los nombres, añada o cambie el tamaño de las columnas de su
tabla, deberá volver a esta forma y hacer que los cambios se reflejen
correctamente. El diseñar visualmente de esta manera, aunque
conveniente, "ata" su diseño al formato de la tabla. Más tarde veremos
maneras de evitar esto hasta cierto punto (pero todo tiene su precio).

Cambie la propiedad "DisplayName" en todos sus campos y ponga títulos convenientes en cada
uno de ellos (¡y por favor en Español, Chihuahua!)... Una vez que termine de "amasar sus datos",
estará usted listo para diseñar...
Para diseñar su forma, simplemente "jale" cada uno de los campos con el mouse, desde la lista de
campos "Form1.qryClientes", hasta la forma, en el orden que desee que el usuario los escriba, y
en la posición deseada en la forma. Cuando "suelte" cada campo, Delphi creará un componente
TLabel y un DbEdit por usted, listos para recibir los datos adecuados.

Delphi es versatil también. Examine las propiedades de los "DbEdit"s que ha


estado soltando en la forma. Para hacer esto manualmente, usted seleccionaría
un dbEdit de "Data Controls", lo pondría en la forma, y manipularía sus
propiedades "DataSource" y "DataField" para mencionar el DataSource en su
forma y el campo deseado, respectivamente. No hay "gran misterio" en cuanto a
la manera en que Delphi lo está ayudando a programar. Como dicen por ahí los
"Borlanderos": Delphi está escrito en Delphi. A continuación presento un ejemplo
de la manera en que probablemente se ve su forma:

"Dijimos que Delphi nos permitía diseñar visualmente.... ¿Donde están los datos?"
Ah, pues es muy sencillo: Nuestro Query todavía no está abierto. Aunque Delphi lo
ejecutó para averiguar la lista de campos necesarios para el diseño, nuestro
query, para propósitos prácticos, está cerrado. Vamos a abrirlo y veamos que
obtenemos:

Nuestros campos han sido activados. El dbNavigator ya nos dá algunas opciones. Pues sí, esa es la
cuenta que especificamos en los parámetros... Y fijate, la Señorita Davis es una muchacha muy
guapa, de Wellesley, Massachusets. Y es programadora, además... Con esa sonrisa, seguro
programa en Delphi.
Si usted quiere, puede correr ahora mismo su programa y hacer cambios, pero solo a ese registro
(porque nuestro query especifica un registro únicamente). Si Delphi no le permite editar mientras
ejecuta, asegúrese de que su Query tiene el RequestLive en "True".

Ahora que sabemos como se hacen las cosas, para experimentar un rato vaya al SQL en su Query
y elimine la sección "WHERE" de la sentencia SELECT. Su SQL quedará como SELECT * FROM
"CLIENTS.DBF" CLIENTES

Recordando todas las precauciones que vimos al principio de nuestro capítulo, sabemos que esta
tabla en particular sólo tiene cinco registros, así que el tiempo de espera del select no será
catastrófico (pero recuerde lo que dije antes; más tarde veremos varias técnicas para manejar
esto). Después, abra su query de nuevo (cambie la propiedad "Active" del Query a "True", y
ejecute el programa.

Felicidades! Tiene su primer programa de acceso de datos de Delphi. Todavía no


hemos escrito una palabra en Pascal, pero funciona muy bien! El Navegador (La
barra de botones de la parte superior) le permite editar, grabar, cancelar,
refrescar los datos y moverse entre los registros. Todos sus registros funcionan, y
usted puede comenzar a editar y añadir registros al archivo de Clientes de
inmediato.

Finalmente, grabe su ejemplo; lo utilizaremos en otros capítulos para no tener que comenzar de
nuevo cada vez. Cuando le pregunte el nombre de "unit1", teclee forma_clientes. Cuando le
pregunte el nombre para el proyecto, teclee "ManejodeClientes".

En los siguientes subcapítulos de la sección "base de datos", aprenderemos mucho acerca de las
muy diversas maneras en que podemos desarrollar aplicaciones de manejo de datos usando
Delphi. Además nos quitaremos de algunos de los "vicios" que tuve a bien introducir en este
capítulo para hacerlo más sencillo y obtener resultados más rápido, como el mantener las tablas
abiertas en modo de diseño, usar SQL sin sentencias WHERE, etcétera. Siendo Delphi tan
poderoso como lo es para el manejo de bases de datos, es dificil abarcar todo. Pero al menos les
daré una "probadita" de varias de las capacidades de Delphi en cuanto al manejo de información,
que son muchas. A partir de ese punto, usted tendrá las herramientas suficientes para
experimentar y extender sus conocimientos.
Por ahora, dése unas palmaditas en la espalda, porque ya terminó una de las secciones más
largas de el curso! Ha usted hecho bastante, y todavía ni siquiera hablamos del lenguaje en sí, un
área fascinante que veremos más a fondo mientras viajamos por los ejemplos...

Capítulo 6.1. Cómo funciona Cliente/Servidor en 20 minutos


En este capitulo teórico explicaremos algunos de los comandos básicos necesarios para trabajar
en Cliente/Servidor. Donde sea posible, utilizaré únicamente lenguaje SQL acorde con el estándar
SQL-92. La base de datos que utilizo para probar es InterBase 4. Mi base de datos alternativa es
MS-SQL. Es muy importante que estudie los conceptos básicos el Capítulo 5 antes de comenzar
este capítulo.

Comandos SQL más comunes

SQL es una especie de mezcla entre un lenguaje de tercera generacion


como dBase y un lenguaje de línea de comando como unix shell o
archivos .BAT en DOS. Los comandos en SQL son ejecutados uno por uno
por el sistema de base de datos. Cada comando puede devolver un set de
resultado (cursor), un mensaje de error que delphi mostrará como una
excepción, o ningún resultado. Los sets de resultados, a su vez, pueden
ser o no modificables "en vivo". SQL también permite ejecutar comandos
de modificación directa sin utilizar un set de resultado de por medio.

Como éste curso es de Delphi y no de SQL, explicaré muy rápido los comandos básicos que se
utilizan en este lenguaje de programación, que en realidad merece un curso propio. Para mayor
velocidad y entendimiento de conceptos que Delphi utiliza para enmascarar los comandos SQL en
sets de datos (dataset), he decidido dividir la sección de comandos entre devuelven un set de
resultado, comandos que no devuelven un set de resultado (recuerden que un set de resultado sin
registros sigue siendo un set de resultado), y comandos para manipular metadatos. Por cierto, un
comando SQL puede estar escrito en varias líneas.

Junto con cada comando incluyo un poquito de su sintaxis básica (varios comandos son muy
complejos) y unos ejemplos para que usted vea en qué clase de situaciones se utilizan los
comandos.

Comandos que devuelven un set de resultado

Todos los comandos mencionados en esta sección pueden devolver un set de resultado. Estos
comandos son:

 SELECT
 Procedimientos ( CREATE PROCEDURE )
 Vistas ( CREATE VIEW )

SELECT

SELECT es el comando que siempre va a devolver un resultado o un mensaje de error. El comando


SELECT tiene la siguiente sintaxis:

SELECT {Campo1 AS NombreCampo1, Campo2, ...CampoN }


FROM {Tabla/Vista}
[ WHERE {Condición} ]
[ LEFT JOIN OtraTabla ]

Ejemplos

Por ejemplo, para hacer un Select que nos devuelva toda la información en la tabla de clientes
donde el cliente tiene como domicilio la ciudad de México, DF, puede usted escribir:

SELECT * FROM CLIENTES

WHERE CIUDAD = "MEXICO" AND ESTADO =


"DF"

El resultado de este SELECT será:

NUM NOMBRE DIRECCION CIUDAD ESTADO SALDO


1234 DAVID MARTINEZ AVENIDA DEL PROGRAMADOR #45 MEXICO DF $1,332.00
2374 ELVIS PRESLEY COUNTRY MUSIC RD #485 MEXICO DF $503.00
5586 MARIO MORENO LOS HUMORISTAS #24 MEXICO DF $45.05
1048 PEDRO INFANTE CALLE DEL MARIACHI #4853 MEXICO DF $5,340.00
2894 LUIS MIGUEL BOLEROS #5886 MEXICO DF $1,255.00

El comando JOIN sirve para juntar campos de dos entidades. Un uso común en SQL para el
comando JOIN es la llamada "denormalización" de los resultados. Esta denormalización es solo de
los resultados, para que el SQL devuelva un set consistente de resultados (siempre el mismo
número de columnas). por ejemplo, supongamos que usted tiene información de una factura.
Tiene usted el encabezado de la factura y además una serie de renglones con los precios y
descripciones de los artículos comprados. Para devolver información que usted pueda desplegar,
puede usted escribir su SELECT con un JOIN de la siguiente manera:

SELECT
ENC.FACNO,
ENC.NOMBRECLIENTE,
ENC.CIUDAD++ENC.ESTADO AS CIUDADEDO
REN.ITEMNO,
REN.DESCRIPTION,
REN.PRECIO_USD,
FROM FACTURAS ENC
LEFT JOIN FACTURARENGLON REN ON ENC.FACNO = REN.FACNO
WHERE ENC.FACNO = 1

Examine el SQL escrito aquí. En este comando de SQL tenemos dos tablas: Una llamada
FACTURAS que estoy "abreviando" a ENC (por encabezado), y la otra llamada FACTURARENGLON,
que he abreviado a REN (por renglón). De este modo me puedo referir a ellas más fácilmente.
También he mezclado la ciudad y estado en un solo campo, al cual he llamado CIUDADEDO (para
eso sirve el AS). De este modo puedo desplegarlo en un solo lugar para efectos de la factura. El
JOIN junta las tablas a través del campo indice (FacturaNo), que existe en las dos tablas, y en este
caso tiene el mismo nombre (ENC.FACNO = REN.FACNO). Finalmente, especificamos la
factura #1 únicamente para aventar eso a un reporte.
FACNO NOMBRECLIENTE CIUDADEDO ITEMNO DESCRIPCION PRECIO_USD
1 DAVID MARTINEZ MEXICO, DF 112232 COMPUTADORA COMPAQ PRESARIO $2,340
1 DAVID MARTINEZ MEXICO, DF 112522 MONITOR COMPAQ 21" $1,340
1 DAVID MARTINEZ MEXICO, DF 513213 3COM PALMIII $400.00
1 DAVID MARTINEZ MEXICO, DF 445653 LIBRO "MASTERING DELPHI 3" $39.99
1 DAVID MARTINEZ MEXICO, DF 445657 LIBRO "COLLAB COMP W/DELPHI 3" $69.99

La denormalización de los resultados es algo común en SQL. Recordemos que, para el servidor, no
es problema repetir los datos porque el cursor interno no se mueve de lugar. Y para nosotros, nos
ahorra tráfico en la red porque, aunque el set de resultados es más grande, no tenemos que pedir
más de uno. Los datos siguen normalizados en las tablas correspondientes.

Procedimientos

Un procedimiento (stored procedure) es básicamente el mismo concepto que un procedimiento en


Delphi. Un procedimiento tiene un nombre y parámetros, y dentro de este procedimiento usted
puede definir variables y opcionalmente devolver uno o más sets de resultado.

CREATE PROCEDURE MiProcedimiento


VARIABLE1 CHAR(10),
VARIABLE2 INT
AS
{ Comandos SQL. Cualquier Select se convierte en parte
del set de resultados }

TODO: TERMINAR PROCEDIMIENTOS

Nota: Los componentes de Delphi, por decisión de arquitectura básica,


pueden manejar únicamente un set de resultado por cada llamada al SQL.
Si usted necesita recuperar la información de un procedimiento que
devuelva más de un set de resultado, deberá utilizar acceso directo al
BDE, o si tiene acceso al servidor, dividir el procedimiento en partes que
devuelvan un set de resultado diferente en cada caso.

Vistas

Una vista (view) es uno o más comandos que devuelven un set de resultado y llevan consigo un
nombre. Para los programas que ejecutan comandos, la vista es identica a una tabla. De esta
manera el programador SQL puede juntar tablas y condiciones en una vista y cambiar los
parámetros de la misma. Por ejemplo, la siguiente vista repite el ejemplo de visualización de
facturas que vimos en la sección de SELECT y lo encapsula en una vista mucho más facil de usar.

CREATE
VIEW DESPLEGARFACTURA

AS
SELECT
ENC.FACNO,
ENC.NOMBRECLIENTE,
ENC.CIUDAD+ " , " +ENC.ESTADO AS CIUDADEDO
REN.ITEMNO,
REN.DESCRIPTION,
REN.PRECIO_USD,
FROM FACTURAS ENC
LEFT JOIN FACTURARENGLON REN ON ENC.FACNO = REN.FACNO

Note que en esta "vista" no tenemos el número de factura. Esto es intencional, para que podamos
escribir comandos como:

SELECT
* FROM DESPLEGARFACTURA WHERE FACNO = 1

En este comando, el set de resultado es el mismo que en la sección de


SELECT/JOIN, que es lo que esperaríamos:

FACNO NOMBRECLIENTE CIUDADEDO ITEMNO DESCRIPCION PRECIO_USD


1 DAVID MARTINEZ MEXICO, DF 112232 COMPUTADORA COMPAQ PRESARIO $2,340
1 DAVID MARTINEZ MEXICO, DF 112522 MONITOR COMPAQ 21" $1,340
1 DAVID MARTINEZ MEXICO, DF 513213 3COM PALMIII $400.00
1 DAVID MARTINEZ MEXICO, DF 445653 LIBRO "MASTERING DELPHI 3" $39.99
1 DAVID MARTINEZ MEXICO, DF 445657 LIBRO "COLLAB COMP W/DELPHI 3" $69.99

Comandos que no devuelven un set de resultado

Hay otros comandos de SQL que no devuelven un set de resultado. Estos comandos son
generalmente para preparar diferentes partes del servidor, o para modificar y borrar datos.

UPDATE

El comando UPDATE actualiza la tabla especificada con los valores que usted necesite. En el
ejemplo que estamos manejando, el siguiente comando modificará todos. El siguiente comando
cambia la abreviatura DF a su forma completa Distrito Federal:

UPDATE FACTURAS
SET ESTADO = "DISTRITO FEDERAL"
WHERE ESTADO = "DF"

Es muy importante poner la clásula WHERE, ya que SQL no pregunta, y si


usted no la pone, el SQL cambiará TODOS los " ESTADOs" en las facturas
a "DISTRITO FEDERAL" sin importar su estado actual (y estaría raro ver
Acapulco, Distrito Federal en una factura)... Asegúrese de siempre poner
una clausula WHERE en todas sus tablas a menos que esté seguro que
quiere cambiar absolutamente todo. El mismo caso aplica al
comandoDELETE.

DELETE

El comando DELETE borra los registros de la tabla especificada. Tal como Update, Delete acepta
una cláusula WHERE.
DELETE FACTURAS WHERE FACNO = 10

Este comando borrará la factura numero 10. Tal como en UPDATE, si no incluye una cláusula
WHERE en su comando, todos los registros de la tabla serán eliminados.

INSERT

El comando INSERT añade un registro a la tabla especificada. INSERT nunca acepta una clausula
where, pero INSERT puede añadir más de un registro basado en un SELECT.

INSERT INTO FACTURAS


( FACNO, NOMBRECLIENTE, CIUDAD, ESTADO )
VALUES ( 99, 'Winston Churchill', 'Londres', 'La Mera Capital' )

Este INSERT añade una factura a la tabla de facturas.

INSERT INTO FACTURARENGLON


( FACNO, NOMBRECLIENTE, CIUDAD, ESTADO )
SELECT 99, ITEMNO, DESCRIPTION, PRECIO_USD FROM
FACTURARENGLON WHERE FACNO = 2

Y este INSERT se combina con otro SELECT para copiar los renglones de la factura número dos y
ponerlos en la factura número 99.

Sets de resultado "vivos"

Los sets de resultado de SQL pueden ser "vivos", es decir, Delphi (u otras aplicaciones) puede
modificar los registros sin necesidad de comandos UPDATE, INSERT o DELETE.

Capitulo 6.2. Continuando con nuestro Catálogo - Manejando


Parámetros
En éste capítulo agregaremos parametros a nuestra aplicacion utilizando el IDE de Delphi.
También veremos como Delphi interpreta los parámetros que agregamos para enviar comandos al
servidor SQL.

Creando parámetros con el IDE

En el Capítulo 6, ya utilizamos el IDE para crear un parámetro (cuando estábamos diseñando la


forma). Ahora veremos como podemos realizar consultas programáticamente para hacer el uso
del programa más sencillo para el usuario.

Lo primero que debemos hacer es crear una forma para que el usuario pueda hacer consultas. Así
que seleccione File-New en el menú de Delphi para crear una nueva forma.

Dentro de la página de "Dialogs", seleccione "Standard Dialog", ya sea el de los botones abajo o a
la derecha (según su preferencia).

Utilizando las ayudas de diseño que se encuentran en la página "Standard" de la barra de


herramientas de Delphi, diseñe una forma que contenga un componente TEdit (con su respectivo
TLabel) llamado edtCampo. Este componente será utilizado para que el usuario teclee el apellido
de la persona.
TODO: Añadir grafico

En nuestra forma principal, añada un botón llamado "Consultar..." para que pueda mostrar el
diálogo. Seleccione "File-Use Unit" del menú para decirle a Delphi que la forma de consulta utiliza
el diálogo. Esto añade el diálogo a la clausula de USES en la sección implementation. Después
haga doble click en el botón para que Delphi escriba un evento, y escriba lo siguiente:

procedure TfrmClientes.btnConsultarClick(Sender: TObject);


begin

// Muestra el diálogo de consultas


dlgConsulta.ShowModal;
if dlgConsulta.ModalResult = mrOK then begin
qryClientes.Close;
qryClientes.ParamByName('Apellido').AsString :=
dlgConsulta.edtApellido.Text+'%';
qryClientes.Open;
if qryClientes.EOF then
ShowMessage('No encontré ningún Cliente!');
end;

end;

Como podrá ver, esta seccion le dice a Delphi lo siguiente:

 Muestra la forma de consultas de manera Modal


 Si el resultado de la forma de consultas fue mrOk (hicieron click en el botón "Ok"):
o Cierra el Query de Consultas (en caso de que esté abierto)
o Asigna el valor del campo de Apellido al diálogo de Consultas
o Abre el Query de Consultas
o Si no hay registros (EOF significa End of File, o fin de archivo), muestra un mensaje
que dice que no encontró clientes.

Ya tenemos el código que reemplazará el parámetro apellido para buscar un apellido en


específico. Ahora lo que necesitamos hacer es modificar la propiedad SQL del TQuery para que
diga lo siguiente:

SELECT * FROM "CLIENTS.DBF" CLIENTES


WHERE Last_Name LIKE :Apellido

En Delphi, cuando usted añade una palabra precedida por un signo de dos puntos (:), la palabra
es automáticamente convertida en un parámetro, el cual es agregado a la propiedad Params, la
cual es una lista de objetos que serán reemplazados por lo que usted especifique antes de
ejecutar el comando. Una vez que usted haya añadido el texto, Vaya a la propiedad "Params"
dentro del inspector de objetos y haga doble click. A continuación podrá ver una lista de
parametros que usted puede examinar (que por ahora solo contiene el apellido). Seleccione el
parámetro y modifique la propiedad "DataType" para que diga ftString. Es importante decirle a
Delphi que clase de parametro vamos a enviar para que Delphi sepa si le debe añadir comillas
(para especificar texto) o dejarlo como número.

Recordemos que el código SQL no es interpretado por Delphi, sino que es convertido a comandos
SQL para un servidor como Oracle o MS-SQL (vea el capítulo 6.1 para mayor información.
Ejecutemos el programa para probarlo. Ahora presione el botón consulta y escriba el nombre
"Davis" como apellido, y seleccione "Ok". A continuación verá a la Srita. Davis aparecer en la
pantalla. Experimente con distintos apellidos.

Si experimenta suficiente notará algo especial: Si usted sólo teclea una "D" en el campo de
apellido, también recuperará el registro! Hicimos esto aprovechando que el lenguage SQL soporta
la comparación LIKE, que devuelve todos los registros que se parezcan a la cadena que enviamos.
Cuando escribimos nuestro código en el OnClick, habrá notado que la línea que asigna el
parámetro añade un signo de porcentaje al final:

qryClientes.ParamByName('Apellido').AsString :=
dlgConsulta.edtApellido.Text+'%';

Esto quiere decir que queremos que el query nos devuelva todo lo que comienza con el texto
que tecleamos. Tenga en cuenta que el servidor SQL es el que interpreta este signo, así que como
se interpreta el signo de porcentaje depende del servidor que este proporcionándonos los datos.

Código de Ejemplo

Comenzando en esta sección estoy añadiendo archivos zip de ejemplo (ya que comenzamos a
escribir código). En el Zip de esta sección he avanzado de tal forma que el diálogo soporta
consultas a varios registros importantes.

Hay varias maneras en las cuales pude haber hecho esto, pero lo que decidí hacer para este
ejemplo fué crear varios componentes TQuery diferentes, uno con cada tipo de consulta. Despues
añadí un RadioButton al diálogo de consulta para que el usuario decida qué tipo de consulta voy a
hacer. El radioButton cambia la etiqueta del campo para reflejar la consulta adecuada.

Notará que, aunque hay varios Queries, solo hay un DataSource. Este es otro ejemplo de la
versatilidad de Delphi. Para hacer que todos los campos de la forma apunten a otro query, todo lo
que tengo que hacer es modificar la propiedad DataSet del componente DataSource para apuntar
a esta nueva consulta, y todos los componentes visuales que apuntan al DataSource
automáticamente cambiarán a la consulta adecuada. Estoy tomando esta decisión aprovechando
la selección en el RadioButton. El código que realiza la consulta ahora tiene la siguiente
apariencia:

procedure TfrmClientes.btnConsultarClick(Sender: TObject);


var
QueryAUsar : TQuery;
begin

// Muestra el diálogo de consultas


dlgConsulta.ShowModal;
QueryAUsar := Nil;
if dlgConsulta.ModalResult = mrOK then begin

// Primero decide que query vamos a usar.


case dlgConsulta.rgConsulta.ItemIndex of
0: QueryAUsar := qryClientesporApellido;
1: QueryAUsar := qryClientesPorCuenta;
2: QueryAUsar := qryClientesPorRiesgo;
end; //case
if QueryAUsar = Nil then Exit;
QueryAUsar.Close;
// Nota: El Número de cuenta es un Integer y no un String. Este IF
// se encarga de eso. Note además que todos los queries que contienen
// parametros tipo string tienen la sentencia LIKE para que podamos añadir
// signo de porcentaje para busqueda parcial.
if QueryAUsar.Params[0].DataType = ftFloat
then
QueryAUsar.Params[0].AsFloat := StrToFloat(dlgConsulta.edtConsultaTexto.Text)
else
QueryAUsar.Params[0].AsString := dlgConsulta.edtConsultaTexto.Text+'%';
QueryAUsar.Open;
dsClientes.DataSet := QueryAUsar;
if QueryAUsar.EOF then ShowMessage('No encontré ningún Registro!');
sbStatus.Panels.Items[0].Text := 'Encontré '+FormatFloat('###,###,##0',
QueryAUsar.RecordCount)+' registros.';

end; // if

end;

Copiar el Código fuente (7K, formato Zip) para esta sección

Capitulo 6.3. Los módulos de datos


Las herramientas de desarrollo visual sufren de un problema común, que es el hecho de que le
permiten al programador ser un tanto desorganizado. Si se pone a pensar en el capítulo anterior,
el programa, aunque funciona muy bien, no cumple con importantes reglas de diseño de
aplicaciones que nos dicen que el manejo de la lógica de los datos debe estar separado de la
aplicación.

Es aquí donde los míodulos de datos nos pueden ayudar. Estrictamente hablando, un módulo de
datos es una "Forma Invisible" que nos permite poner nuestra lógica de acceso de datos separada
de la interfaz del usuario. Usted puede tener uno o varios módulos de datos para su aplicación.

Por ejemplo, supongamos que Ud. tiene que programar un sistema maestro para su pequeña
empresa. Usted ha determinado que necesitará escribir un sistema con las siguientes áreas
functionales:

 Facturación
 Ventas
 Control de Inventarios
 Aplicación al Sistema Contable en Oracle

En este ejemplo, usted puede decidir hacer módulos de datos para cada área funcional. Recuerde
que esto no tiene nada que ver con su interfaz de usuario; sino con la manera en que los datos
están representados, y las reglas del negocio para cada departamento. Incluso, si su organización
es muy grande y los chavos del sistema contable tienen su sistema en Delphi, usted puede
heredar desde el Repositorio de Código el código del sistema contable que fue hecho en Delphi, y
únicamente hacer los cambios apropiados para que su sistema funcione.

// TODO: Insertar Gráfica


A partir del Delphi 5, los módulos de datos le pueden mostrar a usted el diseño de las consultas
(queries) y tablas tal como se verían en un programa de diagramación de datos como erWin, y
también puede preparar relaciones entre las tablas utilizando elementos visuales como flechas y
etiquetas.

// TODO: Insertar grafica de un DataModule en Delphi 5

Los módulos de datos se pueden usar unos a otros (utilizando File-Use desde el menú de Delphi)
para encadenar las funciones. Pero usted deberá tener cuidado de mantener una separación
funcional correcta. Para que una forma vea un módulo de datos, éste debe haber sido creado
previamente a la forma, y el archivo que contiene el módulo de datos debe existir en la cláusula
uses de la forma.

Como cualquier otra forma, los módulos de datos tienen su propio tipo cuando son creados. Un
módulo de facturación que usted ha llamado dmFacturas sería de tipo TdmFacturas. Esto le
permite crear más de un módulo de datos a la vez, todos compartiendo el mismo código (aunque
tal vez con una factura diferente abierta.

Otra ventaja de los módulos de datos es cuando usted comienza a distribuir su aplicación
utilizando tecnologías como MIDAS. En este caso, el servidor crea instancias del módulo de datos
conforme las va necesitando, para que los clientes remotos tengan un módulo de datos donde la
aplicación haga los cálculos de negocios.

Capitulo 6.4. Migrando a Módulos de Datos


Ahora que tenemos motivos claros para crear un módulo de datos, migraremos la pequeña
aplicación que hemos hecho para que los datos estén separados de la implementación.

Desde el menú de Delphi, seleccione File-New. En el diálogo de "New Items" encontrará el Data
Module en la primera página. Selecciónelo y presione OK. Delphi nombra nuestro nuevo módulo de
datos DataModule1.

Grábelo en disco con el nombre "datamoduleclientes" para que tengamos un nombre al cual
referirnos cuando lo comencemos a usar desde otros lugares.

Ahora necesitamos mover los queries que tenemos en la forma principal a nuestro nuevo
datamodule. Esto es tan sencillo como seleccionarlos, y cortar y pegar.

Ahora cambie la propiedad "Name" del datamodule para que sea significativa. En mi ejemplo lo
nombré "dmClientes".
Si usted es perceptivo, habrá notado que los elementos TField que pertenecen a
estos queries también han sido copiados, junto con todas las propiedades
(nombres de campo, formatos, etcétera) que usted ha definido con anterioridad.
Este fragmento del código de nuestro módulo de datos nos muestra que los
TFields han sido copiados:

unit datamoduleclientes;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
Db, DBTables;

type
TdmClientes = class(TDataModule)
qryClientesporApellido: TQuery;
qryClientesporApellidoLAST_NAME: TStringField;
qryClientesporApellidoFIRST_NAME: TStringField;
qryClientesporApellidoACCT_NBR: TFloatField;
qryClientesporApellidoADDRESS_1: TStringField;
qryClientesporApellidoCITY: TStringField;
qryClientesporApellidoSTATE: TStringField;
qryClientesporApellidoZIP: TStringField;

Note que esto sólo ocurre con propiedades, NO con manejadores de


eventos. Los manejadores de eventos están asociados con la forma y no
con objetos dentro de la forma.

Ahora necesitamos decirle a la forma principal que los datos provienen no de los queries en la
forma principal (por ejemplo qryClientesporApellido), sino de los queries en el módulo de datos
(por ejemplo dmClientes.qryClientesporApellido). Seleccione la forma de Clientes y vaya al menú
"File-Use Unit". A continuación podrá ver una lista de las formas que su forma principal no está
usando. Seleccione "datamoduleclientes".

Ahora nuestra sección "implementation" tiene la siguiente apariencia:


implementation

uses consultaclientes, datamoduleclientes;

Seleccione el DataSource de la forma de Clientes. Notará que cuando cortó los TQueries para
pegarlos en otro lugar, la propiedad DataSet se borró. Si usted abre la lista, Delphi encontrará los
TQueries, ahora nombrándolos "dmClientes.(nombre del query)".

Esto nos dá una última pista: En el código del botón de consultas, en cualquier
lugar donde usted mencione uno de los queries, debe ahora añadir el calificador
"dmClientes." antes del nombre, para que el compilador lo encuentre. Una
manera fácil de hacer esto es con la sentencia "with":

// Primero decide que query vamos a usar.


with dmClientes do begin
case dlgConsulta.rgConsulta.ItemIndex of
0: QueryAUsar := qryClientesporApellido;
1: QueryAUsar := qryClientesPorCuenta;
2: QueryAUsar := qryClientesPorRiesgo;
end; //case
end; // with

Esto es todo. Ahora usted puede ejecutar su programa y funcionará correctamente.

Copiar el Código fuente (7K, formato Zip) para esta sección

Capitulo 6.5. MIDAS y Nuevos Paradigmas: Objetos de


Negocios
Objetos de Negocios

Un Problema de Diseño y Arquitectura

Este no es un problema de cómputo, sino humano. Las agilidad de un negocio impide el mantener
un modelo o conocimiento de las "reglas del negocio" en un lugar legible y centralizado. Si usted
centraliza y documenta todos los procedimientos perfectamente, su negocio tiende a volverse
rígido. Cuántas veces hemos oido "lo haría por usted, pero la computadora no me deja". Pero al
mismo tiempo, el hacer sistemas flexibles que al mismo tiempo satisfagan las necesidades del
usuario es mucho muy dificil sin un conocimiento claro de las reglas.

Muchas veces tenemos que hacer tremendos malabares para implementar exactamente lo que el
usuario requiere. Aún con la mejor documentación y requerimientos, siempre acabamos en un ir y
venir con los usuarios relevantes para implementar ciertos cálculos o procedimientos que no son
claros para nadie más que para uno o dos usuarios en específico.

Los Objetos de Negocios como solución del problema

Con el correr de los años, los sistemas de cómputo se volvieron no sólamente la herramienta de
todos los días, sino el único repositorio actualizado de todo el conocimiento acerca de cómo un
negocio funciona. El problema es que este conocimiento está expresado en COBOL, Pascal, Java,
C++, SQL y muchos otros lenguajes que la gente común y corriente no entiende, y algunas reglas
muy importantes se encuentran dentro de ciclos "for-next" y "do-while".

Al darse cuenta de esto, y tomando en cuenta el hecho de que la orientación a objetos puede
reflejar más fielmente la realidad, varios científicos de cómputo y eruditos decidieron que si
pudieramos diseñar sistemas de cómputo utilizando modelos del mundo real (objetos que
representen sus contrapartes en el mundo físico), y aplicaramos a esos modelos procedimientos y
acciones relativas a otros objetos, podríamos lograr:

 Documentos de diseño que reflejan el mundo real y las reglas del negocio, legibles tanto
por los administradores como por los ingenieros
 Sistemas más flexibles, donde añadir la capacidad de hacer algo quiere decir simplemente
añadir un método
 Separación entre la interacción de los objetos "de negocios" y la interfaz del usuario,
permitiendo usar la misma lógica para introducir los datos ya sea desde el teclado, mouse,
navegador de web, realidad virtual o desde otro programa via internet

Un objeto de negocios es una representación virtual (ya sea en papel o en


código) de un objeto en el mundo real, con especificaciones de todas sus
interacciones con otros objetos.

El hecho de que tanta gente proporciona su conocimiento durante el diseño de un sistema es


altamente significativo. Bajo un paradigma de objetos de negocios el diseño de sistemas es no
sólo para crear una base de datos y un par de ejecutables, sino una oportunidad excelente para
expresar y evaluar la manera en que funciona el mundo a nuestro alrededor (en lo que se refiere a
nuestra actividad diaria dentro de la empresa, claro está).

Los objetos de negocios se describen en papel utilizando una notación de


modelaje llamada UML (Unified Modeling Language) (TODO: Add Link).

Es muy importante tomar en cuenta de que la primera vez que realizamos un sistema de esta
forma el diseño del sistema tomará mucho tiempo y muchas iteraciones y diagramación antes de
escribir una sola línea de código o diseñar una sola pantalla o tabla.

Para tomar prestada una analogía de la notación UML, diseñar sistemas de objetos de negocios es
un poco como escribir una obra de teatro. El escritor comienza por definir Actores (objetos),
especificando su naturaleza, historia (razon de ser) y sus interacciones con otros Actores. Al hablar
con los expertos que utilizan estos "actores" una y otra vez descubrimos más interacciones que
reflejan más actores que a su vez interactúan con otros actores, nuevos o existentes.

Al final lo que tenemos es un modelo muy exacto de como funciona el negocio, pero en papel. Una
vez hecho esto, podemos comenzar a definir bases de datos para guardar las características de
los diferentes actores, código que representa los actores y todas sus interacciones, y pantallas
(vestuario y coreografía) para llenar las características de los actores, con botones y eventos para
activar sus acciones.
Programación Multi-Capas

El Problema: Cambios en las Reglas del Negocio

Cuando crece su empresa, o la cantidad de computadoras que usted maneja, el mantener todos
los clientes configurados correctamente y con la más nueva versión de su programa instalado
puede resultar complicado.

Supongamos que su programa mantiene e imprime facturas para sus clientes. El aparato fiscal de
su país acaba de bajar los impuestos de ventas (jajajaja), y además ahora se calculan de manera
diferente dependiendo del tipo de producto. Si usted tiene que reinstalar el programa en 50
tiendas simplemente porque el impuesto ha bajado, tendrá el riesgo de que algunas de las tiendas
calcularán los impuestos de manera incorrecta hasta que usted instale el programa en todas las
tiendas.

Tal vez usted dirá: "Bueno, incluso si esto es cierto, puedo poner una tabla centralizada con el
porcentaje de impuestos". Si bien esto es cierto, ¿qué hará cuando lo que cambia es la manera de
calcular? Esto ocurre muy seguido en el cálculo de impuestos en general en todos los países. Es
muy dificil escribir un programa para interpretar fórmulas en una base de datos, especialmente
cuando estas fórmulas pueden ser muy complicadas, con procedimientos, diferentes casos y
repeticiones.

La Solución de Inprise - MIDAS

El paradigma de objeto de negocios es muy útil, pero nos ocasiona muchos problemas que Delphi
ya había solucionado en cuanto a la programación de base de datos. El diseño de los objetos de
negocios en sí totalmente ignora el concepto del DataSet, y con ello, los controles data-aware.
Esto quiere decir que, en una implementación "pura" de un objeto de negocios, usted deberá de 1)
utilizar controles normales y escribir una gran cantidad de código de infraestructura, o 2) crear su
propio descendiente de TDataSet que funcione con cada uno de sus objetos de negocios.

Esto es un problema, especialmente cuando nos ponemos a pensar que tanto COM como CORBA
son traducidos a llamadas locales en tiempo de compilación; lo cual quiere decir que es imposible
convertir una interfase de objetos de negocio a un TDataSet sin tomar en cuenta la interfase de
objeto de negocio en específico.

La tecnología MIDAS le permite exportar e importar DataSets a través de COM o CORBA


(incluyendo constraints, reglas del negocio y otras ventajas), lo cual le dá casi todas las
ventajas de los objetos de negocios sin tener que sufrir sus desventajas. Por supuesto, esto sólo
funciona si tanto sus clientes como sus servidores utilizan tecnología MIDAS (que se encuentra
disponible para Java, C++ Builder y Delphi).

Nota: Esta tecnología definitivamente no es para los puristas. El no


exportar una interfase con Getters y Setters es casi un Tabú en UML, y le
será dificil reconciliar un modelo UML con IDL generado con MIDAS. Uste
deberá tomar una decisión basada en sus necesidades de purismo vs.
tiempo de desarrollo. Tal como algunas personas utilizan herramientas
RAD únicamente para hacer prototipos, tal vez usted querrá sólamente
hacer prototipos con MIDAS y exportar interfases "reales" una vez que
tiene un prototipo que los usuarios acepten.

He puesto la sección de MIDAS antes que las secciones de DCOM y CORBA intencionalmente
porque usted no necesariamente debe saber de interfases para comenzar a utilizar MIDAS.
Esto no quiere decir que el aprender interfases no le sea útil, sino que usted puede hacer
programas pequeños y medianos con MIDAS y exportarlos como objetos CORBA o DCOM sin
aprender nada de estas tecnologías, gracias a los Wizards de Delphi.

Capítulo 6.6. Migrando Nuestra Aplicación a MIDAS


En esta sección migraremos nuestra aplicación a módulos de datos, que pueden vivir en la misma
computadora como dos procesos diferentes o en dos computadoras distintas.

En este caso, nuestra aplicación anterior se convertirá en un "cliente" de la aplicación que realiza
el acceso a bases de datos.

Creando la Capa Media

Primero necesitamos crear un proyecto nuevo para nuestra "capa intermedia". Seleccione "File-
New" y después "Application". Esto creará un proyecto básico con una forma.

A continuación necesitamos crear nuestra interfase para que nuestros clientes la encuentren.
Utilice "File-New" y Seleccione "Remote Data Module" desde la página "Multitier".

A continuación, el wizard le pedirá los datos necesarios para generar el nuevo módulo de datos.
 Class Name: Este es el nombre de la clase con la cual usted publicará el módulo de datos.
Cuando un programa cliente pida una interfase por nombre, éste es el nombre que deberá
pedir para que el servidor responda.
 Instancing: Este es el modelo de instanciación que el módulo de datos utilizará.
 Threading Model: Este es el modelo de hilos de ejecución que utilizará su programa.

Para mayor información de estos modelos, vea la sección de


programación en COM de este curso.

Ahora grabe su nuevo módulo de datos (el nombre del mío fué "dmTutorClientes.pas".

El módulo de datos que usted acaba de crear es además una interfase. Esta interfase es pública
una vez que se haya registrado con la computadora, y otros procesos la pueden accesar. Así que
ahora todo lo que debe usted hacer es crear queries y exportarlos. Para ahorrar tiempo, copie y
pegue los queries del proyecto de Clientes a este. Una vez que haya copiado y pegado, terminará
con un módulo de datos público con tres queries que aún son privados. Para exportarlos, haga
click con el botón derecho del mouse y seleccione "Export Query from DataModule" del menú
de opciones. Haga lo mismo con los tres queries. Una vez hecho esto, compile y ejecute el
programa una vez para que el sistema registre la existencia de estas nuevas interfases.

Si usted no ejecuta una vez el programa antes de comenzar a programar


el cliente, la interfase nunca será registrada en Windows y no podrá
seleccionar el servidor cuando programe el cliente.
Ahora su proyecto tiene tres módulos de datos exportados (uno por cada query). Veamos cómo
fueron generados en su aplicación.

MIDAS e Interfases

Delphi exporta interfases utilizando una librería de tipos. Una librería de tipos es un archivo que
mantiene la especificación de las interfases. Como MIDAS necesita exportar su módulo de datos
como una interfase, utiliza el editor de tipos para generar interfases de manera estándar.

Nuestro proyecto ha exportado una interfase con tres propiedades. Para verlas, seleccione "View-
Type Library". A continuación podrá ver la interfase TutorClientes ("ITutorClientes"), contenida en
una CoClass llamada "TutorClientes". Esta interfase tiene tres propiedades, con los nombres de los
queries que usted ha exportado.

Estas propiedades son de tipo IProvider. IProvider es una interfase específica de MIDAS, que se
utiliza para comunicar un DataSet con sus clientes.

Modificando el Cliente para Comunicarse con el Servidor

Ahora modificaremos el cliente para que se comunique con el servidor. Abra el proyecto de
Clientes.dpr y elimine todos los queries del Módulo de datos. También deberá eliminar las
menciones a dbtables y bde (si la tiene) de su módulo de "uses", tanto en el módulo de datos
como en las formas del programa. Esto no sería necesario si usted nunca hubiera tenido
TQueries en su programa.

Esto sólo es necesario porque el TQuery depende del BDE, y si usted no


elimina las unidades que necesitan el BDE de su cláusula de uses, el
programa cliente requerirá el BDE para operar correctamente!

A continuación, vaya a la página de componentes "Midas" y añada un componente


TDCOMConnection al módulo de datos. En el combobox de la propiedad "ServerName" usted verá
los nombres de los programas que están registrados como módulos de datos. Seleccione
servicioclientes.TutorClientes, que es la capa media que creamos con anterioridad.

Note que el TDComConnection también permite la propiedad


"ComputerName", que usted puede utilizar para ejecutar la capa en otra
computadora.
A continuación agregue tres componentes "TClientDataSet". El ClientDataSet nos permite
representar la interfase IProvider en el Cliente, y se comporta de manera muy parecida a los
componentes TQuery y TTable (porque descienden del mismo componente, TDataSet). Para cada
uno de estos ClientDatasets, asigne la propiedad "RemoteServer" al objeto TDCOMConnection que
creó.

Una vez que ha hecho eso, necesitará seleccionar el IProvider correcto para cada ClientDataSet.
Asigne la propiedad ProviderName de cada uno de los TClientDatasets dependiendo del nombre.

Cuando haga click en el combobox para seleccionar el nombre, la


propiedad "Connected" de TDComConnection se activará
automáticamente para que Delphi "averigüe" qué IProviders están
registrados en el servidor (esto se hace llamando un procedimiento
llamado "GetProviderNames").

Como eliminamos los queries, usted necesitará cambiar el DataSource de la forma principal para
especificar el nuevo ClientDataSet, y cambiar un poco de código en el botón "Consultar" para que
utilice el ClientDataSet en vez del TQuery (esto requerirá que usted añada "dbClient" a la clausula
de uses del programa principal, para poder declarar la variable local como TClientDataSet
(recuerde eliminar dbTables porque ya no estamos usando TQueries).

El código del botón ha cambiado de la siguiente manera:

procedure TfrmClientes.btnConsultarClick(Sender: TObject);


var
QueryAUsar : TClientDataSet;
begin

// Muestra el diálogo de consultas


dlgConsulta.ShowModal;
QueryAUsar := Nil;
if dlgConsulta.ModalResult = mrOK then begin

// Primero decide que query vamos a usar.


with dmClientes do begin
case dlgConsulta.rgConsulta.ItemIndex of
0: QueryAUsar := cdsClientesporApellido;
1: QueryAUsar := cdsClientesPorCuenta;
2: QueryAUsar := cdsClientesPorRiesgo;
end; //case
end; // with
if QueryAUsar = Nil then Exit;
QueryAUsar.Close;
QueryAUsar.FetchParams;

Note que al final he añadido el comando "FetchParams" para que el cliente pida la lista de
parámetros del servidor (esto no ocurre automáticamente).

Por ahora, mantenga la propiedad Connected del TDComConnection encendida (True) para que no
tenga que conectarse. Usted podrá hacer esto más tarde con un botón de "Conectar" o algo así.

Ahora puede usted ejecutar el programa. Notará que funciona de la misma manera que los
programas anteriores, sólo que éste no requiere el BDE y funciona de manera distribuida.
Cualquier regla que usted aplique a los TQueries y a los TFields dentro de los queries será copiada
al cliente.

Le recomiendo mucho que estudie TClientDataset y lo aplique. Es muy útil aún sin necesidad de
un servidor de aplicaciones.

Copiar el Código fuente (7K, formato Zip) para esta sección

Capítulo 7. Componentes y Paquetes


Hay muchos objetos en la barra de componentes de Delphi. Todos estos objetos están escritos en
Object Pascal, y en conjunto forman la librería VCL.

Un componente es un objeto que "sabe" como comportarse en modo de diseño, y puede ser
añadido a una forma. Todos los objetos de la barra de componentes de Delphi heredan directa o
indirectamente de TComponent, que es de donde heredan su comportamiento en tiempo de
diseño, y sus capacidades de añadirse a y grabar su estado en el archivo de Forma (dfm).

Como Delphi es completamente orientado a objetos, usted puede heredar un objeto que se
comporta exactamente como el objeto del cual heredó. Este concepto es lo que hace tan sencillo
el extender la barra de herramientas de Delphi para nuestros requerimientos.

El Punto de Vista del Autor de Componentes

La programación de componentes es muy distinta a la programación de aplicaciones. Cuando


usted programa aplicaciones, usted sólo se debe de preocupar por la manera en que su objeto se
debe de comportar durante la aplicación. Pero cuando usted programa un componente, usted
debe de tomar en cuenta la manera en que su componente se comportará en tiempo de diseño
también.

Delphi no es tramposo, y utiliza una versión compilada de su componente para mostrar el


componente en tiempo de diseño. Esto quiere decir que cada vez que usted añada una propiedad
publica al componente, debe usted asegurarse de que esta propiedad también funcione en tiempo
de diseño, o que al menos su componente pueda distinguir si está en tiempo de diseño para que el
desarrollador que está añadiendo el componente no obtenga errores extraños al tratar de usar su
creación.
Como Delphi está corriendo su código cuando usted crea un componente, usted puede añadir
menús, editores especiales y muchas cosas más como ayudas de diseño para el usuario (que en
este caso es el desarrollador que tiene Delphi y está creando un programa haciendo su
componente.

Paquetes

La tecnología de paquetes es parte integral de la habilidad que tiene Delphi para extender sus
capacidades usando componentes y ayudas de desarrollo. Usted también puede utilizar la misma
tecnología para extender sus propios programas.

Todos los componentes viven en un paquete. Un paquete es una clase de DLL especial que tiene
funciones para pasar tipos de datos especiales (los DLLs, en su forma nativa, sólo pueden pasar
cadenas de texto, números y punteros). Los paquetes de Delphi son integrales para el diseño de
componentes, porque cuando un componente está en modo de diseño Delphi utiliza la librería de
paquetes para cargarlo en memoria.

Usted puede Activar y Desactivar paquetes con el menú de "Project-Install Packages" en Delphi.
Además, cuando usted abre un proyecto, el proyecto recuerda los paquetes que usted estaba
utilizando y los activa, para asegurarse de que todos los componentes estén funcionando cuando
usted despliegue la forma.

Usted puede crear sus propios paquetes en Delphi. Un archivo fuente de cabecera de un paquete
tiene la extension .dpk. Un paquete compilado tiene la extension .dpl.

La extensión .DPL de los paquetes es únicamente para que Delphi los


diferencíe de un DLL. Si usted cambia la extensión a DLL podrá abrirlo con
quick view o cualquier programa de desarrollo que pueda mostrar las
funciones exportadas de un DLL (aquí nomás curioseando). Cambie la
extensión de nuevo a .DPL para utilizarlo en Delphi.

Tipos de Componentes

Por sí solo, un TComponent no puede hacer nada más que exportar las propiedades de su sección
"published" en formato DFM, y mostrar una cajita en la forma que no se muestra en modo de
ejecución (esto es, un componente no visual). Así que rara vez querrá usted crear un
componente "desde cero". Lo que usted probablemente hará es extender un componente
existente, o al menos utilizar algunos de los descendientes abstractos directos de TComponent
para crear su propio componente.

Para escribir componentes, dos cosas le serán de extrema utilidad:

 La jerarquía de la librería de Clases, para saber de donde es correcto heredar dependiendo


el caso.
 El Código fuente del control del cual usted está heredando.

Es por esto que todas las versiones de Delphi en vez de la estándar vienen con el código fuente de
la librería de componentes. A veces, cuando heredamos componentes, es importante asomarnos a
ver cómo los programadores de Borland escribieron métodos específicos, para saber si podemos
reutilizar este código o si necesitamos hacer override al código existente (o en la mayoría de los
casos, alguna combinación de ambos).
Reglas para Crear un Componente

Un componente es muy, muy parecido a una clase, pero escribir un componente debe tomar en
cuenta las siguientes reglas:

Regla #1. Las propiedades para el Inspector de Objetos van en la sección published

Cuando usted crea un componente y desea que su propiedad sea parte del inspector de objetos,
usted deberá declararlas en la sección published de su componente. Las propiedades de la
sección published son mostradas en el inspector de objetos y son grabadas en el archivo DFM.

Regla #2. Crear métodos para cambiar propiedades

Para crear un componente, es obligatorio hacer métodos GetXXX y SetXXX para cambiar un
miembro.

Por ejemplo, considere el código siguiente:

private
procedure SetVariable( Value : String );
function GetVariable: String;
protected
FVariable : String;
published
property Variable : String read GetVariable write SetVariable;

Esta es la manera correcta de cambiar una propiedad en un componente. Su variable FVariable


está "protegida", esto es, sólo la clase y sus descendientes pueden accesarla. La propiedad
Variable es de tipo String y se puede leer y modificar con los métodos GetVariable y SetVariable,
respectivamente. La versión protegida de su variable puede tener cualquier nombre, pero el estilo
típico en Delphi es añadir una letra "F" antes de la variable.

Esto se hace así para permitirle a usted hacer tareas automáticas, como inabilitar el control
cuando la variable tiene un valor específico, o cambiar el color de un control automáticamente
cuando el valor de una propiedad cambia. En este ejemplo, el color del control cambia a verde
cuando la propiedad Variable tiene la cadena "Hola Chavos".

Regla #3. Su componente debe estar registrado

Para que se muestre en la paleta de objetos, su componente debe haber sido


registrado con anterioridad. Cuando usamos el Wizard de creación de
componente, Delphi registra el componente automáticamente añadiendo el
siguiente procedimiento a su código:

procedure Register;
begin
RegisterComponents('Samples', [TSuComponente]);
end;
El crear un componente es una disciplina con preceptos muy sencillos, pero es un arte. Usted
puede hacer desde cambios pequeños como el hacer un TLabel que imprima "al revés", hasta la
creación del widget para realidad virtual más picudo del planeta.

Capítulo 7.1. Dos modos fáciles de escribir un componente


Ahora veamos cómo podemos escribir un componente para que otros desarrolladores puedan
utilizarlo. En este ejemplo, usted creará un paquete con dos componentes sencillos, uno visual y
otro no visual.

La creación de componentes bajo Delphi es totalmente independiente de la creación de una


aplicación, pero yo siempre creo una aplicación vacía de prueba para poder poner mi componente
en la forma y probarlo en tiempo de diseño al mismo tiempo que lo modifico. Así que simplemente
comience Delphi con un proyecto nuevo.

Nuestro primer componente es un Label que dice "Buenos Días" en varios idiomas.

Cuando hagamos nuestro componente, necesitaremos crear un paquete. Muchos programadores


mantienen dos paquetes de componentes; el de "prueba", donde preparan sus componentes
prototipo y los mejoran, y el "real", que es el que utilizan para integrar sus aplicaciones. Pero
como mínimo, usted necesitará al menos un paquete para sus componentes, así que crearemos
uno primero.

Desde el menú de Delphi, seleccione "File-New" y haga click en el ícono de "Package". A


continuación podrá ver el Editor de paquetes.

Grabe este paquete como "Tutor". A continuación, seleccione "Component-New Component"


(también puede usar "File-New" y seleccionar "Component"). A continuación podrá ver el wizard
de creación de Componentes.
Cuando usted crea componentes, el tipo de ancestro es una de las cosas más importantes y más
difíciles de determinar, especialmente si usted quiere hacer un componente totalmente nuevo. Es
muy importante conocer la jerarquía del VCL y qué componentes proveen qué servicios para saber
de qué componente es más conveniente heredar.

Por ejemplo, usted puede hacer su propio ComboBox, pero si el componente que usted quiere
hacer difiere mucho de TComboBox, podría ser más recomendable heredar de
TCustomComboBox, que provee los primitivos de un ComboBox pero mantiene muchas
propiedades privadas.

Ahora presione el botón "Install..." para decirle a Delphi que queremos añadirlo a un paquete.
Seleccione "existing package" (pudo haber creado un paquete nuevo desde aquí tambien
utilizando "Into New Package"), y seleccione nuestro Tutor.dpk.

A continuación verá un mensaje diciendole que el paquete va a ser construido y después


instalado. Seleccione "Yes" y el compilador de Delphi se pondrá a trabajar. Una vez hecho esto,
Delphi nos dice que el paquete "Tutor.dpk" ha sido instalado y usted tiene un nuevo componente
llamado THolaLabel.

Note que ahora hay una página "Tutor Delphi" en su paleta de componentes, con un componente
THolaLabel en ella.
Ahora podemos comenzar a escribir código. Nuestro "proyecto" es ahora el archivo DPK, así que
para compilar simplemente utilizamos el Botón Compile de la ventana del Paquete.

Nuestro componente va a saludar en varios idiomas, así que comencemos por


definir los idiomas en que va a saludar. La mejor manera de hacer esto es el
definir un tipo. Lo llamaré idiomas, y va a contener todos los idiomas posibles
para mi componente. Como habrá una propiedad de este tipo, lo debemos definir
antes que el componente:

type
TIdioma = ( idEspanol, idIngles, idFrances,
idItaliano, idAleman );
THolaLabel = class(TLabel)

Ahora que tenemos un tipo que nos será útil para definir los idiomas, necesitamos
una variable y funciones set y get para guardar qué idioma vamos a usar.

private
{ Private declarations }
FIdioma : TIdioma;
procedure SetIdioma( Valor : TIdioma );
function GetIdioma : TIdioma;

Por supuesto, no basta con definir las funciones; también debemos escribirlas:

function THolaLabel.GetIdioma : TIdioma;


begin
Result := FIdioma;
end;

procedure THolaLabel.SetIdioma( Valor : TIdioma );


var
sMensaje : String;
begin

FIdioma := Valor;
case FIdioma of // Dependiendo del idioma es el mensaje.
idEspanol : sMensaje := 'Buenos Días!';
idIngles : sMensaje := 'Good Morning!';
idFrances : sMensaje := 'Bonjour!';
idItaliano : sMensaje := 'Bonjorno';
idAleman : sMensaje := 'Gutten Mörgen!';
end;
Self.Text := sMensaje; // Reemplaza nuestro texto con el mensaje

end;
Note que la funcion SetIdioma no sólo guarda el idioma, sino cambia el texto del Label (self) de
acuerdo al idioma que el usuario seleccionó. Esto nos permite que el Label muestre el cambio de
inmediato al cambiar mi propiedad, incluso en modo de diseño!

Por último mi propiedad, curiosamente, se llamará "Idioma". Quiero que sea


publicada en el inspector de objetos, así que la pongo en la sección de
"published", para que se anuncie y se grabe con la forma en tiempo de diseño.

published
{ Published declarations }
property Idioma : TIdioma read GetIdioma write SetIdioma;

Felicidades! Acaba usted de hacer su propio componente. No fué difícil, verdad? Por cierto, el
concepto de JavaBeans en Java es casi idéntico a la creacion de componentes en Delphi (y no por
casualidad; Borland está en la mesa directiva del consorcio de estándares de Java).

Ahora necesitamos probarlo, por supuesto. Como ya está instalado, sólo tenemos que recompilar
el paquete. Vaya a la ventana de "Tutor.dpk" y presione el botón "Compile".

En el caso especial de los paquetes, los controles normales de


compilación (Control-F9, etc) no funcionan, porque compilan el proyecto,
no el paquete. Usted debe usar el botón de compilar dentro de la
ventana del paquete.

A continuación, vaya a la página "Tutor Delphi" en la paleta, muestre la forma principal de su


proyecto y ponga un THolaLabel en el mismo. En el inspector de objetos, busque la propiedad
Idioma:

Note que al compilar para modo de Diseño, Delphi analizó su código y su propiedad Idioma es
perfectamente legible, utilizando los mismos valores que usted escribió en su nuevo tipo TIdioma.
Aún con esta ayuda en modo de diseño, el optimizador compilará un valor entero para mayor
velocidad. Pero por ahora, usted puede cambiar la propiedad. Cambiemos nuestro HolaLabel a
italiano:
He cambiado mi Font a algo más grande para que sea legible. Cuando usted cambia la propiedad,
Delphi ejecuta la función SetIdioma que usted ha escrito, y cambia el texto a italiano.

Aunque esto es muy útil, recuerde que Delphi esta ejecutando su código, lo cual quiere decir que
cualquier loop infinito o error en el código que Delphi ejecuta en modo de diseño puede trabar a
Delphi. Asegúrese de grabar antes de compilar sus paquetes.

Platicando con Otros Lenguajes de Windows - Controles OCX

Hacer un Control para su uso en Visual Basic y otros lenguajes es tan sencillo que ni siquiera
amerita un capítulo propio. En esta pequeña sección (que no es necesaria si usted no quiere
utilizar su componente en otros lenguajes) crearemos un control OCX.

Nota: Windows no puede crear un Control ActiveX que no tenga un Handle


de Windows (esta es una limitación de la tecnología ActiveX y no de
Delphi). En Delphi, esto quiere decir que el control debe heredar de
TWinControl. Desafortunadamente, nuestro THolaLabel hereda de
TGraphicControl (para ahorrar recursos de Windows).

Desde el menú de Delphi, Seleccione "File-New". Vaya a la página de ActiveX y seleccione


"ActiveX Library". Grabe el proyecto.

Ahora seleccione "File-New" y "ActiveX Control" (también desde la página de ActiveX).


Delphi le preguntará el nombre del control existente (haremos un TDateTimePicker), el nombre del
nuevo componente ActiveX, el nombre de archivo para el .pas y el modelo de hilos de ejecucion.
También le dará opciones para crear una caja de "About", versión y licencia.

Automáticamente, Delphi creará los archivos necesarios. Ahora sólo compile e instale el .OCX
resultante en VB. Felicidades! Acaba de hacer usted un control OCX!

Nota: Si usted selecciona "Run Parameters", y pone el ejecutable de Visual


Basic (o el lenguaje donde haya instalado el nuevo OCX) como "Host
Application", podrá utilizar el debugger de Delphi en su control OCX.

Copiar el Código fuente (7K, formato Zip) para esta sección (Componente/Paquete)

Copiar el Código fuente (29K, formato Zip) para esta sección (ActiveX)

Capitulo 9. Teoría de Interfases


Introducción

Si usted ha viajado a otro continente, seguramente estará consciente de que algunos países
tienen diferentes enchufes eléctricos. Argentina, por ejemplo, tiene enchufes redondos; Los
estados unidos tienen enchufes de tres picos, donde dos de los picos son planos y el otro (el de
"tierra") es redondo. Pero también funcionan los aparatos viejos porque solo tienen los dos picos
planos y los dos picos planos dan la misma corriente eléctrica que requieren estos
aparatos. Los enchufes eléctricos no son exactamente alta tecnología, pero es el ejemplo más
sencillo de una interfase.

Definición de Interfase

Otro ejemplo de una interfase es el siguiente. Seguramente usted habrá oido en las noticias que el
taxi espacial Estadounidense ha estado viajando y conectándose con la estación espacial Rusa
MIR. La tecnología rusa y la estadounidense son muy diferentes. ¿Cómo es esto posible? Bueno,
cuando construyeron MIR hicieron una definición de como se debía fabricar la interfase para
acoplamiento con el MIR. Por ejemplo, seguramente definieron la forma (redonda), dónde iban los
enchufes de los tubos para pasar oxígeno, electricidad, combustible, etc. Si usted quisiera acoplar
su casa con MIR, tendría que construir una interfase redonda con los enchufes de la misma
manera, y entonces su casa podría conectarse a MIR.

Basado en estos ejemplos, mi definición sencilla de interfase para usted es: Una interfase es una
especificación fija para que dos objetos hablen entre sí.

Como en todos los conceptos abstractos, es muy importante también


saber lo que una interfase NO es: Una interfase no es un objeto, tal como
un rectángulo NO ES una caja de chocolates. El objeto (la caja de
chocolates) soporta una implementación de la interfase (rectángulo). De
esta manera, cualquier robot entrenado para manipular rectángulos
puede manipular la caja de chocolates. De la misma manera, el módulo de
acoplamiento del MIR no es una interfase, sino una implementación de la
interfase. La interfase es la definición de como acoplarse al MIR (redondo,
2m diámetro, con tubos aquí y allá).
Todos los lenguajes modernos soportan el concepto de interfases. Hoy día en computación hay
dos "lenguajes de transporte" para interfases: (COM y CORBA). Hablaremos de maneras
específicas de crear una interfase con ambas tecnologías y de sus diferencias en los capítulos
siguientes, pero por ahora sólo hablaremos de interfases de manera abstracta, con ejemplos
prácticos.

Un uso Común para Interfases

Supongamos que su organización ha estado creciendo mucho últimamente. Todos los


departamentos necesitan información de clientes y hay muchos desarrollos diferentes en su
oficina. Todos los desarrollos requieren un catálogo de clientes, y usted hasta ahora ha resuelto el
problema mediante un archivo de texto ASCII con la información de los clientes que su sistema de
clientes pone en la noche del día 30 de cada mes y los otros programas lo importan.

Esto ha funcionado muy bien hasta ahora, pero tiene dos problemas: El primero es que los otros
sistemas siempre tienen información que está atrasada por un mes. Esto es, si el sistema de
ventas no sabe que el cliente se mudó a otra dirección la semana pasada, el producto le llegará a
la dirección anterior aún si el cliente cambió su dirección con los muchachos de servicio al público,
porque la información del cliente no ha sido copiada al sistema de ventas.

El otro problema es que los programadores tienen que "reinventar el hilo negro" quince veces
para hacer consultas de clientes funcionar en todos los sistemas, y como los datos de todos los
clientes ocupan 2Gb, usted está gastando 2Gbx15 departamentos diferentes en datos
redundantes.

Lo que usted necesita es una manera de hacer que los diferentes subsistemas (ventas, cobros,
envíos, garantías) le hablen al mismo sistema de clientes cada vez que necesiten información
acerca del cliente. De esta manera usted ahorra 28Gb de espacio en disco y elimina trabajos
nocturnos, permitiendo el uso del sistema en la noche para la gente que trabaja horas extras.
Como verá esto tendría muchas ventajas.

Esta es la clase de problema para el cual las interfases fueron diseñadas. Para solucionar éste
problema lo primero que usted debe hacer es especificar una Interfase para que los diferentes
subsistemas puedan platicar con su sistema de clientes. Comencemos a definir una interfase de
manera teórica.

Nota: Es muy importante pedir ayuda de la gente que trabaja en todos los
departamentos para que la interfase mantenga a todos satisfechos.
Recuerde que no importa cuanto sepa usted, son los usuarios los que
saben la clase de datos que necesitan.

Supongamos que usted organizó una junta. Para invitar a la gente en esta junta usted necesitó los
jefes o supervisores de todos los departamentos que requieren datos del cliente, porque ellos son
los que saben todo acerca de los datos que deben ser transportados por las interfases) y también
a los líderes de proyecto de todos los sistemas que utilizan datos del cliente (porque ellos
necesitan saber y opinar acerca del diseño de la interfase). Entre todos han llegado a un diseño
general que contiene lo siguiente:

 Nombre (Nombre y Apellido)


 Dirección (Calle, Colonia, Ciudad, Estado, País)
 Teléfono (Código de País) (Area) (Número)
 Fecha de Ultima Compra
 Fecha de Ultimo Pago
 Estatus de Cobro (Pueden Ser: Al corriente, Nuevo Cliente, Atrasado, En Conflicto)
 Debe ($)
 Credito Disponible ($)

El diseño puede ser a discreción de las necesidades de cada compañía, pero uno de los diseños de
la interfase de clientes (pseudocódigo) es como sigue:

 NEstatus : Enum ( AlCorriente, NuevoCliente, Atrasado, EnConflicto )


 IPersona
o NombredePila : String
o ApellidoPaterno : String
o ApellidoMaterno : String
o FechadeNacimiento : Float
 ICliente
o ClienteNo: LongInt
o Cliente: IPersona
o Dirección: IDirección
o Teléfono: ITeléfono
o ÚltimaCompra: Double
o ÚltimoPago: Double
o Estátus: NEstatus
o Debe: Float
o CreditoDisponible: Float
 IClientes
o Función DameCliente(ClienteNo: LongInt) : ICliente
o Procedimiento GuardaCliente( Cliente : ICliente )
Si utilizaramos el diseñador de Delphi para generar esta interfase gráficamente, veríamos lo
siguiente:

El Lenguaje IDL

El lenguaje IDL es un lenguaje común para definir interfases tanto en COM como en CORBA. IDL se
parece a C, pero carece de sentencias de control (do while, for next, etc). Esto es porque en IDL
usted unicamente define las funciones que usted va a implementar en Pascal, C, Java, COBOL,
etcétera.

IDL es un estándar, y cada lenguaje (Delphi, Java, C, etc.) cuenta con un traductor de IDL, que
traduce las sentencias de la definición de la interfase al lenguaje adecuado.

Delphi es facil de usar y le permite diseñar las interfases visualmente. Usted puede obtener el
código IDL utilizando el botón "Export to IDL" de la barra de botones del editor de tipos y
seleccionando "Export to CORBA IDL". Como de costumbre, el IDL estándar es diferente al IDL de
Microsoft. La función "Export to IDL" puede exportar a ambos tipos. He aquí el resultado de
seleccionar CORBA IDL y MIDL (Microsoft IDL), basandonos en el ejemplo anterior:

 CORBA IDL
 Microsoft IDL
De esta manera, cuando usted necesite exponer interfases a usuarios de otros lenguajes (Java, C+
+, Visual Basic), usted puede utilizar estas funciones para generar un archivo IDL que ellos puedan
usar.

Punteros de Interfase

Ahora supongamos que todos los sistemas deben comenzar recuperando un Cliente. Los sistemas
piden una interface a IClientes en la computadora y piden a la computadora XYZ (utilizando
tecnología COM, CORBA, etc) que genera una "instancia" (instance) de la interface IClientes. El
sistema nos va a devolver lo que se llama un puntero de interfase (interface pointer). Este
puntero de interfase es como la conexión al sistema de clientes. Representa la interfase de
clientes que la computadora XYZ soporta (obviamente, si pedimos una interfase IClientes a una
computadora donde el sistema de clientes no existe, recibiremos un error tipo "Interface not
supported"). Nunca trate de guardar este puntero en un archivo de texto o algo así porque solo es
un número de una posición de memoria.

Imagine que tiene usted un sistema de TV por cable. Cuando usted


enciende la televisión y pide el canal (HBO, por ejemplo), su caja de cable
comienza a recibir el canal HBO mediante el pequeño cable que está
enchufado a su pared. El punto en su caja de cable donde se enchufa el
cable es el puntero de interfase mediante el cual viene HBO, pero no es
HBO en sí. Sigo insistiendo en esto porque es muy importante que
entienda que cuando usted pide una interfase esta recibiendo un puntero
a la interfase que debe ser traducido por la máquina, y no el programa en
sí.

Una vez que usted obtenga esa interfase, usted llamaría al cliente #1 utilizando la función
DameCliente(1). El resultado de esta función debe ser guardado en otro puntero de interfase.
Ahora nuestra segunda interfase es ICliente.

El miembro de la interfase es aún otra interfase, ésta vez llamada IPersona. Y así sucesivamente
hasta que usted encuentra finalmente un tipo de datos primitivo que pueda desplegar en la
pantalla (String, LongInt, etc). Obviamente, como estas son interfases y son soportadas en varios
lenguajes, no mencioné un lenguaje en específico, sino solamente los conceptos.

Si usted cree que esto se parece mucho a nuestra discusión de objetos en


el Capitulo 3, tiene razón - Los conceptos son casi los mismos. Pero
recuerde una vez mas que esta vez estamos hablando de la
representación de los objetos, no de los objetos en sí mismo (como una
analogía, piense que aquí estamos hablando de rectángulos como un
concepto geométrico abstracto y anteriormente hablamos de objetos de
forma rectangular - edificios, cajas de chocolates, étc).

Así que ya hemos visto cómo los clientes van a utilizar nuestra interfase. Pero nosotros, cómo la
implementamos?

La interfase es una representación uniforme de un cliente para la organización. El programa que


nosotros vamos a escribir debe "implementar" todas las funciones de la representación de un
cliente. Usted puede escribir varios programas que representen al mismo cliente (i.e. varias
"implementaciones" de la misma interfase, tal como una caja de chocolates y una caja de
malvaviscos tienen todas cuatro lados y cuatro ángulos). Esto es cierto en cualquier lenguaje y en
cualquier transporte.
Ahora vayamos a algo específico (al fin, algo de código, dirán algunos): ¿Cómo implementamos
una interfase en el lenguaje Object Pascal?

Object pascal, como hemos visto anteriormente, es orientado a objetos. Cuando queremos que un
objeto (cualquier objeto) represente una interfase, el primer paso es decirle al compilador que
esto es lo que necesitamos hacer, agregando una coma y el nombre de la interfase a la definición
de tipo de la unidad. Por ejemplo:

TODO: usar Pas2HTML en esta sección


TXYZClientes = class(TInterfacedObject, IClientes)
protected
public
private
end;

En esta declaración, usted tiene un objeto TXYZClientes que hereda de un TInterfacedObject e


implementa la interfase IClientes. Heredamos de TInterfacedObject porque todas las interfases
necesitan saber hacer tres cosas: Añadirse al puntero de interfase, borrarse del puntero de
interfase, y averiguar si hay alguna función o un procedimiento con un nombre específico en la
interfase. Estas tres funciones también forman parte de una interfase, que se llama IUnknown.
Veremos más información de IUnknown y de su pariente, IDispatch en la sección teórica de
COM.

En otros lenguajes usted debe programar los métodos de IUnknown por sí mismo, pero Delphi
hace todo esto por usted mientras herede de el objeto TInterfacedObject o de TComObject.

Una vez que hemos declarado los objetos que van a representar nuestras interfases (usted deberá
declarar también objetos para representar IPersona e ICliente), su programa no compilará hasta
que declare funciones para satisfacer todos los procedimientos y funciones de la interface. Estas
funciones normalmente se declaran en la sección protected del objeto. Por ejemplo:

TXYZClientes = class(TInterfacedObject, IClientes)


protected
function Get_ClienteNo: LongInt;
procedure Set_ClienteNo( Value: LongInt );
function Get_Cliente : IPersona;
procedure Set_Cliente( Value: IPersona );
function Get_Direccion : IDirección;
procedure Set_Direccion( Value: IDirección );
function GetTeléfono: ITeléfono;
procedure Set_Telefono( Value: ITeléfono );
function Get_ÚltimaCompra : Double;
procedure Set_ÚltimaCompra( Value: Double );
function Get_ÚltimoPago : Double;
procedure Set_ÚltimoPago( Value: Double );
{ ... etcétera... }
public
private
end;

Como algunos lenguajes no son orientados a objetos, el lenguaje IDL nos obliga a utilizar métodos
llamados Get_XXX y Set_XXX cada vez que creamos una propiedad de lectura y escritura (si la
propiedad es de Lectura solamente, solo debemos satisfacer la función Get_XXX). Es mucho
trabajo, pero como veremos en la práctica, si usted utiliza Delphi la mayor parte de este código es
escrito por usted mientras diseña. Pero es importante que Ud. lo entienda por si algo sale mal o
expertos en otros lenguajes necesitan entender algo acerca de su interface.

Así funciona la teoría de las interfases, y así es como se programan en Delphi. Dependiendo del
tipo de interfase que usted vaya a programar, usted deberá utilizar un servicio o registro para
decirle a la computadora que la implementación de su interfase de IClientes existe en la
computadora XYZ y el programa se llama ServicioClientes.EXE (o algo así). Veremos estos
conceptos y un programa de ejemplo en los subcapítulos que siguen.

Capitulo 9.1. Interfases COM en Delphi

Ahora que sabemos cómo funciona una interfase y como se implementa en Object Pascal, veamos
cómo funcionan las interfases COM (y DCOM) en específico.

COM es un transporte para interfases. La conveniencia de COM es que viene con todas las copias
de Windows en el planeta, así que no hay que preocuparse de instalar librerías con su sistema. La
parte inconveniente es que si usted utiliza COM, su programa solo puede hablar con máquinas que
corran Windows (hay un esfuerzo para implementar la librería COM en Unix, pero no ha tenido
éxito técnico o político).

ActiveX es simplemente un conjunto de interfases COM y utilerías relacionadas que, cuando


usted implementa, permiten que su producto sea utilizado en lenguajes de programación como
componente visual. Todos los componentes de Visual Basic son ActiveX, y cualquier componente
de Delphi puede implementar un ActiveX también. Esto quiere decir que cualquier componente
visual que usted haga en Delphi puede ser utilizado en programas de Visual Basic. A su vez,
Delphi puede utilizar cualquier componente ActiveX.

La diferencia entre un Componente de ActiveX y un componente de Delphi normal (.pas) es que


ActiveX es independiente del lenguaje, pero los componentes de Delphi son mucho más
compactos y no le requiere redistribuir binarios ajenos a su programa.

Ejecutables en Windows

La implementación de una interfase COM en Delphi puede vivir en cualquier archivo de 32 bits que
Windows pueda ejecutar. Estos archivos pueden ser ejecutables, Librerías DLL o Librerías OCX.
Hay ciertos detalles en cuanto a lo que es soportado en cada uno de estos tipos de
implementación, como hilos de ejecución o capacidad de funcionar como un control de ActiveX. Un
solo ejecutable puede implementar todas sus interfases, o puede usted granularizar en diferentes
servicios como más convenga a su caso en particular.

Como Windows Maneja COM

Para poder instanciar una interfase, la computadora necesita saber en qué ejecutable vive esta
interfase, y además necesita saber algunos otros detalles acerca de su ejecución, como puntero
de entrada a cada una de las interfases (dentro del ejecutable), permiso de usuario con los cuales
el ejecutable va a funcionar, etcétera. Toda esta información es guardada por el registro de
Windows.

Lo primero que necesitamos para una interfase es no confundirla con otra. Para esto se utilizan los
llamados GUIDs, o Globally Unique IDentifiers. Estos identificadores son una especie de número de
serie aleatorio de 128 bits generado utilizando una función llamada CoCreateGUID. La función está
escrita de manera tal que se le garantiza que éste numero nunca será repetido. Esto es
importante porque el GUID es el identificador que la computadora utilizará para nuestra interfase
en todas las computadoras de todo el mundo, y no queremos que nuestras interfases se
confundan con las de otra persona. Por ejemplo, en todo el planeta, el siguiente GUID identifica al
Active Desktop de Internet Explorer:

{FBF23B40-E3F0-101B-8488-00AA003E56F8}

Las interfases en Windows vienen en "paquetes de interfaces" llamados


CoClasses. Un CoClass es una clase que implementa una o más
interfaces. En COM, todas las funciones que manejan interfases de
manera abstracta comienzan con el preidentificador "Co". De esta manera
sabemos que esta función es una función que puede ser aplicada a
cualquier CoClass, no obstante los particulares de la misma.

Tómese unos cuantos minutos para examinar el registro de Windows con el programa REGEDIT.
Usted podrá observar que uno de los folders de "raíz" se llama HKEY_CLASSES_ROOT. Este folder
contiene toda la información de todas las interfases. Su nombre, su identificador único, sus
permisos, etcétera. Windows utiliza COM durante su operación diaria, así que usted encontrará los
GUIDs de interfases de Windows, Borland, y todas sus aplicaciones junto con sus propias
interfases.

Utilizar regedit para ver sus interfases puede resultar complicado. Microsoft tiene funciones para
averiguar información acerca de las interfases sin tener que accesar el registro, y se reservan el
derecho de cambiar el formato del registro. Así que dentro de lo posible, procure que su programa
utilice las funciones del Windows API para averiguar información acerca de las interfases en vez de
usar el registro.

Hay un programa muy útil llamado OleView en el sitio de Microsoft que


nos proporciona toda la información pertinente a las interfases COM
instaladas en la computadora.

TODO: Find link to OleView.exe

Instanciando Interfases

Los programas en Windows pueden ser muy diferentes. ¿Cómo sabe Windows cómo instanciar una
interfase? Cuando el programa inicializa (antes de comenzar a ejecutar), Delphi crea por nosotros
una "Fabrica de Objetos" (Class Factory). Una fábrica de objetos es un objeto concreto que genera
objetos de la clase cada vez que Windows decide que un programa cliente ha solicitado un
puntero de interfase. Si usted utiliza las capacidades de RAD de Delphi, rara vez se tendrá que
preocupar acerca de esto, pero es importante que tenga en mente como funciona para resolver
algunos problemas que no son obvios. Por ejemplo, si por algún motivo su objeto nunca inicializa y
usted nota que el procedimiento create nunca ejecuta (y el objeto está registrado), el problema
puede ser que la fábrica de objetos nunca está siendo creada. Si no hay fábrica de Objetos,
Windows no puede crear una CoClass.

En Object Pascal, una fábrica de objetos se instancía en la sección initialization de la unidad


donde vive el objeto. Por ejemplo, un objeto recién creado utilizando los Wizards de Delphi tiene la
siguiente sección de implementación en la unidad donde usted implementará el objeto:

implementation

uses ComServ;
initialization
TAutoObjectFactory.Create(ComServer, TClientes, Class_Clientes,
ciMultiInstance, tmApartment);
end.

TAutoObjectFactory es una fábrica de clases que genera objetos COM. El Create crea una nueva
fábrica de clases y la añade al ComServer (un objeto global dentro de la unidad ComServ que
mantiene una lista de todas las fábricas de clases en este ejecutable). También registra el hecho
de que va a instanciar objetos de Delphi TClientes cada vez que Windows necesite una CoClass
llamada Class_Clientes (esta CoClass fué generada por la biblioteca de tipos del proyecto
automáticamente, y tiene asociado un GUID para ponerlo en el registro de Windows. Vea el
capítulo práctico para entender como funciona con un ejemplo).

También notará que el Create le notifica a la fábrica de clases que este objeto es de instancia
múltiple y su modelo de hilos de ejecución es "Apartamento".

Por ejemplo, las siguientes gráficas ilustran cómo hace COM para instanciar un objeto a partir de
una fábrica de Clases. Cuando un cliente pide la interfase IClientes (1), COM busca en el registro
de Windows el GUID que corresponde a IClientes (a menos que usted haya especificado el GUID en
vez del nombre), y después busca el ejecutable que corresponde al GUID. Si el archivo no está en
memoria, lo ejecuta (2). Una vez hecho esto, COM busca en la lista de la librería de clases (que
Delphi guarda en el objeto global ComServer) la fábrica de clases (en rojo) que puede crear
IClientes (representado por Class_Clientes en el código fuente arriba) (3).

Después, COM llama al método de la fábrica de clases para crear un objeto, y la fábrica de clases
crea un objeto TClientes (4) (usando el método TComObject.CreateFromFactory) y asigna un
puntero de interfase, el cual es devuelto a COM (5).
COM a su vez crea un puntero de interfase interno para devolver al cliente (6).

¿Porqué el paso 6? Recuerde que en un ambiente de memoria protegida como es Win32, usted no
puede accesar memoria que no le pertenece a su aplicación, así que COM necesita crear un
puntero para usted. Esto quiere decir que usted no puede comparar los numeros de puntero en el
lado del servidor y del cliente y esperar que sean el mismo. Esto también es util cuando
instanciamos un objeto usando DCOM en otra computadora (donde la posición de memoria no
tiene sentido en nuestra máquina).

Usted notará que lo complicado en COM ocurre en el servidor, no en el cliente. Lo único que el
cliente tiene que hacer es llamar CreateComObject para obtener un puntero de interfase y usarlo.
Toda la traducción y lo "Feo" se encuentra en el lado del servidor.

Modelos de Creación de Interfaces COM

El modelo de creación de una interfase se compone de dos secciónes. El modelo de instanciación


(instancing model), y el modelo de hilos de ejecución (threading model)

Los modelos de instanciación son como sigue:

 Single Instance

En este modelo, la primera vez que un cliente pide un puntero de interfase, la fábrica de
objetos crea nuestro objeto. Pero la segunda vez, la fábrica de objetos simplemente
encuentra la dirección de nuestro primer objeto y da esta dirección al cliente en vez de
crear un nuevo objeto. De esta manera usted tiene la garantía de que sólo un TCliente
estará en memoria dando servicio a todos los programas clientes.

 Multiple Instance

Bajo este modelo, cada vez que un cliente pide un nuevo puntero de interfase, la fábrica de
objetos crea un nuevo objeto. Bajo este modelo usted debe tener cuidado con los nombres
de sus objetos para no confundirse, porque usted literalmente tendrá varios objetos
TCliente rondando por ahí (uno por cada cliente).

Los modelos de hilos de ejecución (threading) son los siguientes:


 Single

Bajo este modelo, hay solo un hilo de ejecución. Todos los programas esperan a que la
llamada X a Objeto uno termine antes de pedir la llamada Y a objeto dos. Esto es muy
lento, pero no requiere ninguna programación en especial en el servidor, porque nos
garantiza que solo una llamada va a llegar desde COM a la vez.

 Apartment Threaded

Bajo este modelo, COM crea un hilo de ejecución por cada objeto, y solo ejecuta una
llamada a la vez por objeto (por ejemplo, si dos hilos de ejecución tratan de llamar métodos
del mismo puntero de interfase a la vez, COM los llama uno por uno). Obviamente esto sólo
tiene sentido en Multiple Instance. Como hay un hilo por cada objeto, debemos tener
cuidado cuando utilizamos variables globales (Printers, Screen.DataModules,
Screen.Forms), para evitar accesar memoria que otro de los hilos ha liberado y cosas así.

 Free Threaded

Bajo este modelo, los clientes pueden llamar a cualquier método de un objeto desde
cualquier hilo de ejecución a cualquier momento. Los servidores con modelo de Free
Threaded son los más difíciles de desarrollar porque deben de proteger no solo las
variables globales al ejecutable, sino también las variables locales al objeto (porque otro
hilo podría llamar a otra función del objeto que cambia la misma variable). Esto permite
mucha facilidad a los clientes, porque los clientes pueden compartir un sólo puntero de
interfase para todas sus operaciones y no preocuparse de nada.

 Both

Este modelo es un modelo que permite a clientes utilizar Apartment y Free a la vez.

Recuerde que cuando usted registra un modelo de ejecución con


TAutoObjectFactory, está efectivamente entrando en un "contrato"
con Windows, donde usted se compromete a escribir sus
servidores poniendo ciudado a la manera en que COM le enviará
las peticiones para métodos. El que usted haya dicho "Free
Threaded" no quiere decir que el programa automáticamente va
a tomarse cargo de la protección de memoria y diferentes
consideraciones de ejecución.

El mundo de COM es muy grande, y apenas hemos visto suficiente para poder comenzar a hacer
un ejemplo y entenderlo. Si este tema le interesa, le recomiendo que compre un buen libro acerca
de COM/DCOM y se asome al código fuente de los objetos de Delphi en comobj.pas, ComServ.pas
y ActiveX.pas. Espero que esta explicación le haya dado suficientes bases para entender
conceptos más avanzados.

Capitulo 9.1. Interfases COM en Delphi

Ahora que sabemos cómo funciona una interfase y como se implementa en Object Pascal, veamos
cómo funcionan las interfases COM (y DCOM) en específico.

COM es un transporte para interfases. La conveniencia de COM es que viene con todas las copias
de Windows en el planeta, así que no hay que preocuparse de instalar librerías con su sistema. La
parte inconveniente es que si usted utiliza COM, su programa solo puede hablar con máquinas que
corran Windows (hay un esfuerzo para implementar la librería COM en Unix, pero no ha tenido
éxito técnico o político).

ActiveX es simplemente un conjunto de interfases COM y utilerías relacionadas que, cuando


usted implementa, permiten que su producto sea utilizado en lenguajes de programación como
componente visual. Todos los componentes de Visual Basic son ActiveX, y cualquier componente
de Delphi puede implementar un ActiveX también. Esto quiere decir que cualquier componente
visual que usted haga en Delphi puede ser utilizado en programas de Visual Basic. A su vez,
Delphi puede utilizar cualquier componente ActiveX.

La diferencia entre un Componente de ActiveX y un componente de Delphi normal (.pas) es que


ActiveX es independiente del lenguaje, pero los componentes de Delphi son mucho más
compactos y no le requiere redistribuir binarios ajenos a su programa.

Ejecutables en Windows

La implementación de una interfase COM en Delphi puede vivir en cualquier archivo de 32 bits que
Windows pueda ejecutar. Estos archivos pueden ser ejecutables, Librerías DLL o Librerías OCX.
Hay ciertos detalles en cuanto a lo que es soportado en cada uno de estos tipos de
implementación, como hilos de ejecución o capacidad de funcionar como un control de ActiveX. Un
solo ejecutable puede implementar todas sus interfases, o puede usted granularizar en diferentes
servicios como más convenga a su caso en particular.

Como Windows Maneja COM

Para poder instanciar una interfase, la computadora necesita saber en qué ejecutable vive esta
interfase, y además necesita saber algunos otros detalles acerca de su ejecución, como puntero
de entrada a cada una de las interfases (dentro del ejecutable), permiso de usuario con los cuales
el ejecutable va a funcionar, etcétera. Toda esta información es guardada por el registro de
Windows.

Lo primero que necesitamos para una interfase es no confundirla con otra. Para esto se utilizan los
llamados GUIDs, o Globally Unique IDentifiers. Estos identificadores son una especie de número de
serie aleatorio de 128 bits generado utilizando una función llamada CoCreateGUID. La función está
escrita de manera tal que se le garantiza que éste numero nunca será repetido. Esto es
importante porque el GUID es el identificador que la computadora utilizará para nuestra interfase
en todas las computadoras de todo el mundo, y no queremos que nuestras interfases se
confundan con las de otra persona. Por ejemplo, en todo el planeta, el siguiente GUID identifica al
Active Desktop de Internet Explorer:

{FBF23B40-E3F0-101B-8488-00AA003E56F8}

Las interfases en Windows vienen en "paquetes de interfaces" llamados


CoClasses. Un CoClass es una clase que implementa una o más
interfaces. En COM, todas las funciones que manejan interfases de
manera abstracta comienzan con el preidentificador "Co". De esta manera
sabemos que esta función es una función que puede ser aplicada a
cualquier CoClass, no obstante los particulares de la misma.

Tómese unos cuantos minutos para examinar el registro de Windows con el programa REGEDIT.
Usted podrá observar que uno de los folders de "raíz" se llama HKEY_CLASSES_ROOT. Este folder
contiene toda la información de todas las interfases. Su nombre, su identificador único, sus
permisos, etcétera. Windows utiliza COM durante su operación diaria, así que usted encontrará los
GUIDs de interfases de Windows, Borland, y todas sus aplicaciones junto con sus propias
interfases.

Utilizar regedit para ver sus interfases puede resultar complicado. Microsoft tiene funciones para
averiguar información acerca de las interfases sin tener que accesar el registro, y se reservan el
derecho de cambiar el formato del registro. Así que dentro de lo posible, procure que su programa
utilice las funciones del Windows API para averiguar información acerca de las interfases en vez de
usar el registro.

Hay un programa muy útil llamado OleView en el sitio de Microsoft que


nos proporciona toda la información pertinente a las interfases COM
instaladas en la computadora.

TODO: Find link to OleView.exe

Instanciando Interfases

Los programas en Windows pueden ser muy diferentes. ¿Cómo sabe Windows cómo instanciar una
interfase? Cuando el programa inicializa (antes de comenzar a ejecutar), Delphi crea por nosotros
una "Fabrica de Objetos" (Class Factory). Una fábrica de objetos es un objeto concreto que genera
objetos de la clase cada vez que Windows decide que un programa cliente ha solicitado un
puntero de interfase. Si usted utiliza las capacidades de RAD de Delphi, rara vez se tendrá que
preocupar acerca de esto, pero es importante que tenga en mente como funciona para resolver
algunos problemas que no son obvios. Por ejemplo, si por algún motivo su objeto nunca inicializa y
usted nota que el procedimiento create nunca ejecuta (y el objeto está registrado), el problema
puede ser que la fábrica de objetos nunca está siendo creada. Si no hay fábrica de Objetos,
Windows no puede crear una CoClass.

En Object Pascal, una fábrica de objetos se instancía en la sección initialization de la unidad


donde vive el objeto. Por ejemplo, un objeto recién creado utilizando los Wizards de Delphi tiene la
siguiente sección de implementación en la unidad donde usted implementará el objeto:

implementation

uses ComServ;

initialization
TAutoObjectFactory.Create(ComServer, TClientes, Class_Clientes,
ciMultiInstance, tmApartment);
end.

TAutoObjectFactory es una fábrica de clases que genera objetos COM. El Create crea una nueva
fábrica de clases y la añade al ComServer (un objeto global dentro de la unidad ComServ que
mantiene una lista de todas las fábricas de clases en este ejecutable). También registra el hecho
de que va a instanciar objetos de Delphi TClientes cada vez que Windows necesite una CoClass
llamada Class_Clientes (esta CoClass fué generada por la biblioteca de tipos del proyecto
automáticamente, y tiene asociado un GUID para ponerlo en el registro de Windows. Vea el
capítulo práctico para entender como funciona con un ejemplo).

También notará que el Create le notifica a la fábrica de clases que este objeto es de instancia
múltiple y su modelo de hilos de ejecución es "Apartamento".
Por ejemplo, las siguientes gráficas ilustran cómo hace COM para instanciar un objeto a partir de
una fábrica de Clases. Cuando un cliente pide la interfase IClientes (1), COM busca en el registro
de Windows el GUID que corresponde a IClientes (a menos que usted haya especificado el GUID en
vez del nombre), y después busca el ejecutable que corresponde al GUID. Si el archivo no está en
memoria, lo ejecuta (2). Una vez hecho esto, COM busca en la lista de la librería de clases (que
Delphi guarda en el objeto global ComServer) la fábrica de clases (en rojo) que puede crear
IClientes (representado por Class_Clientes en el código fuente arriba) (3).

Después, COM llama al método de la fábrica de clases para crear un objeto, y la fábrica de clases
crea un objeto TClientes (4) (usando el método TComObject.CreateFromFactory) y asigna un
puntero de interfase, el cual es devuelto a COM (5).

COM a su vez crea un puntero de interfase interno para devolver al cliente (6).

¿Porqué el paso 6? Recuerde que en un ambiente de memoria protegida como es Win32, usted no
puede accesar memoria que no le pertenece a su aplicación, así que COM necesita crear un
puntero para usted. Esto quiere decir que usted no puede comparar los numeros de puntero en el
lado del servidor y del cliente y esperar que sean el mismo. Esto también es util cuando
instanciamos un objeto usando DCOM en otra computadora (donde la posición de memoria no
tiene sentido en nuestra máquina).
Usted notará que lo complicado en COM ocurre en el servidor, no en el cliente. Lo único que el
cliente tiene que hacer es llamar CreateComObject para obtener un puntero de interfase y usarlo.
Toda la traducción y lo "Feo" se encuentra en el lado del servidor.

Modelos de Creación de Interfaces COM

El modelo de creación de una interfase se compone de dos secciónes. El modelo de instanciación


(instancing model), y el modelo de hilos de ejecución (threading model)

Los modelos de instanciación son como sigue:

 Single Instance

En este modelo, la primera vez que un cliente pide un puntero de interfase, la fábrica de
objetos crea nuestro objeto. Pero la segunda vez, la fábrica de objetos simplemente
encuentra la dirección de nuestro primer objeto y da esta dirección al cliente en vez de
crear un nuevo objeto. De esta manera usted tiene la garantía de que sólo un TCliente
estará en memoria dando servicio a todos los programas clientes.

 Multiple Instance

Bajo este modelo, cada vez que un cliente pide un nuevo puntero de interfase, la fábrica de
objetos crea un nuevo objeto. Bajo este modelo usted debe tener cuidado con los nombres
de sus objetos para no confundirse, porque usted literalmente tendrá varios objetos
TCliente rondando por ahí (uno por cada cliente).

Los modelos de hilos de ejecución (threading) son los siguientes:

 Single

Bajo este modelo, hay solo un hilo de ejecución. Todos los programas esperan a que la
llamada X a Objeto uno termine antes de pedir la llamada Y a objeto dos. Esto es muy
lento, pero no requiere ninguna programación en especial en el servidor, porque nos
garantiza que solo una llamada va a llegar desde COM a la vez.

 Apartment Threaded

Bajo este modelo, COM crea un hilo de ejecución por cada objeto, y solo ejecuta una
llamada a la vez por objeto (por ejemplo, si dos hilos de ejecución tratan de llamar métodos
del mismo puntero de interfase a la vez, COM los llama uno por uno). Obviamente esto sólo
tiene sentido en Multiple Instance. Como hay un hilo por cada objeto, debemos tener
cuidado cuando utilizamos variables globales (Printers, Screen.DataModules,
Screen.Forms), para evitar accesar memoria que otro de los hilos ha liberado y cosas así.

 Free Threaded

Bajo este modelo, los clientes pueden llamar a cualquier método de un objeto desde
cualquier hilo de ejecución a cualquier momento. Los servidores con modelo de Free
Threaded son los más difíciles de desarrollar porque deben de proteger no solo las
variables globales al ejecutable, sino también las variables locales al objeto (porque otro
hilo podría llamar a otra función del objeto que cambia la misma variable). Esto permite
mucha facilidad a los clientes, porque los clientes pueden compartir un sólo puntero de
interfase para todas sus operaciones y no preocuparse de nada.
 Both

Este modelo es un modelo que permite a clientes utilizar Apartment y Free a la vez.

Recuerde que cuando usted registra un modelo de ejecución con


TAutoObjectFactory, está efectivamente entrando en un "contrato"
con Windows, donde usted se compromete a escribir sus
servidores poniendo ciudado a la manera en que COM le enviará
las peticiones para métodos. El que usted haya dicho "Free
Threaded" no quiere decir que el programa automáticamente va
a tomarse cargo de la protección de memoria y diferentes
consideraciones de ejecución.

El mundo de COM es muy grande, y apenas hemos visto suficiente para poder comenzar a hacer
un ejemplo y entenderlo. Si este tema le interesa, le recomiendo que compre un buen libro acerca
de COM/DCOM y se asome al código fuente de los objetos de Delphi en comobj.pas, ComServ.pas
y ActiveX.pas. Espero que esta explicación le haya dado suficientes bases para entender
conceptos más avanzados.

Capitulo 9.3. Interfases CORBA en Delphi

En el capítulo 9, vimos la teoría de las interfases en general. Ahora que entendemos la idea,
veamos cómo CORBA soluciona el problema. Si usted decidió leer el capítulo 9.1, para ahora
tendrá una muy buena idea de como funcionan las interfases en Microsoft COM y podrá usted
darse cuenta de las diferencias tanto de filosofía como de implementación.

El Open Management Group

En 1989, los altos ejecutivos de varias compañías (desde compañías de Software hasta Bancos) se
reunieron para hablar acerca de interfases, y de la importancia que éstas tendrían en el futuro.
Estas empresas (que forman el llamado "Open Management Group") decidieron que, dada la
enorme importancia que las interfases tendrían, sería muy util especificar un estándar para que
todos los lenguajes de programación pudieran exponer interfases, sin importar el lenguaje, el
sistema operativo o el vendedor de servicios de objetos.

CORBA es el resultado de muchos años de trabajo de varias compañías para definir un estándar
que satisfaga a todos los lenguajes de todos los sistemas operativos. COM fué el primer transporte
de interfases soportado por Delphi, pero CORBA es una tecnología mucho más madura y sólida
para tranporte de interfases, por el simple y sencillo motivo de que CORBA ha estado funcionando
por mucho tiempo en varios sistemas operativos y lenguajes.

Así que la primera diferencia entre COM y CORBA es que COM nos limita a tecnologías Windows,
mientras CORBA nos abre las puertas a la posibilidad de usar e implementar interfases en Unix,
Linux, Mainframes de IBM, Solaris, Sillicon Graphics, Windows, etcétera, en lenguajes tan dispares
como Java, C, Delphi, COBOL, SmallTalk, FORTRAN, LISP y muchos otros.

Independencia de Lenguaje

¿Cómo se logra la independencia entre lenguajes? Tal como vimos en el capítulo 9, Las interfases
CORBA se representan en un Lenguaje unificado llamado IDL (Interface Definition Language). Cada
lenguaje (Delphi, Java, C, etc.) cuenta con un traductor (también llamado "compilador") de IDL,
que traduce las sentencias de la definición de la interfase al lenguaje adecuado.
Cuando usted compra librerías de CORBA (también llamadas ORBs) para su lenguaje, las librerías
normalmente vienen con programas llamados "idl2XXX", donde "XXX" es el nombre de su
lenguaje. De esta manera, un ORB para java viene con un compilador de IDL llamado "idl2java",
mientras que C++ vendría con un compilador llamado "idl2cpp". En delphi tenemos un caso
especial, porque Delphi puede leer IDL directamente en el editor de librerías de tipos y traducirlo a
PAS automáticamente (así que el compilador de IDL viene integrado en las versiones Client/Server
y Enterprise).

Independencia de Sistemas Operativos y Lenguajes

Como ORB no es dominado por una sola compañía sino por un grupo, mientras uste pueda
compilar su programa para un sistema operativo X y pueda comprar unas librerías ORB para el
mismo sistema operativo (y que funcionen con su lenguaje), usted puede hablar con cualquier otro
servicio en la red que exponga un ORB, sin importar qué sistema operativo o qué marca de ORB
está ejecutándose en la máquina que expone el ORB.

CORBA es una Especificación

Tal como lo hicimos en las interfases, hay que ver lo que CORBA no es:

 CORBA NO ES un producto

CORBA es una especificación de como debe funcionar un set de librerías específicas para
llamarse un ORB. Decir "yo sé usar CORBA" no es suficiente; usted normalmente debe decir
cosas como "yo sé CORBA usando Visigenics", o "yo sé CORBA usando IONA". Visigenics e
IONA son dos productos que implementan la tecnología CORBA. Los productos que
implementan CORBA se llaman ORBs.

 CORBA NO ES un lenguaje

De la misma manera, Visigenics (un ORB) está disponible para varios lenguajes bajo varias
plataformas (Visigenics for C++/Linux, Visigenics for C++/Windows, Visigenics for Java).
Pero CORBA en sí mismo no es un lenguaje, sino una serie de librerías y servicios. Así que
recuerde que cuando explique a otra persona que usted puede programar en CORBA,
recuerde que debe decirlo de forma "Yo programo CORBA usando Visibroker para Delphi
bajo Windows", o "Yo programo CORBA usando Visibroker para Java", etcétera.

Componentes de Visibroker

Visibroker es un ORB que cumple con todos los requerimientos de CORBA. Visibroker se compone
de lo siguiente (Los nombres de servicio entre comillas son los nombres de la implementación de
Visibroker en particular):

 Librerías de CORBA.

Las librerías de CORBA le ayudan a los programas a exponer métodos CORBA y a utilizar
los métodos desde los programas Clientes.

Las librerías de CORBA pueden ser de dos tipos:

1. ORB
El ORB es el exportador e importador de interfases. Todos los clientes y servidores
deben inicializar el ORB y utilizarlo para obtener interfases. Básicamente el ORB es
el que interpreta los punteros de interfases y los traduce a mensajes de red, o
recibe llamadas de red y los traduce a punteros locales para su ejecución.

2. Adaptador de Objetos Básico (BOA)

El adaptador de Objetos Básico (Basic Object Adaptor) es la librería que le ayuda a


exportar el puntero de interfase. Se utiliza en el servidor.

Nota: En computación distribuida, los términos "servidor" y


"cliente" pueden resultar intercambiables, ya que el cliente
puede implementar objetos y exportarlos al servidor. En
estos casos, los clientes también necesitan usar el BOA
(pero solo si exportan interfases). Esto será mas claro en los
ejemplos, pero recuerde que "cliente" y "servidor" son
roles que puede jugar un ejecutable en cualquier
momento.

 Servicio de Nombres "SmartAgent"

El servicio SmartAgent le ayuda a exportar un objeto para su utilización en una red local. Si
usted tiene el código de interfase I.O.R. en específico, usted no necesita un servicio de
nombres.

 Servicio de Activación "OAD"

Cuando usted escribe un programa COM que exporta interfases, Windows utiliza uno de sus
servicios internos (TODO:Averiguar Nombre del Servicio) para ejecutar el archivo (.exe, .dll,
etc) donde la interfase "vive". CORBA no es una tecnología que dependa en el sistema
operativo, así que el servicio de activación tiene una lista de las interfases y los nombres
de sus ejecutables para poder iniciar automáticamente el ejecutable. Note que si usted
comienza el ejecutable por sí mismo, no necesita registrarlo en el OAD. De esta manera,
usted puede tener varios servicios en su AUTOEXEC.BAT (o lista de servicios en Windows
NT) que aceptarán peticiones de los clientes.

 Compilador de IDL

IDL es un lenguaje "neutral" para definición de interfases. Como tal, tiene declaraciones
pero no tiene sintaxis de control (for, do while, etc). Bajo CORBA, usted describe su
interfase utilizando IDL y utiliza el compilador de IDL para crear clases de apoyo a su
implementación, y clases auxiliares para que los clientes puedan crear instancias del
objeto.

Visibroker y Delphi

La versión de Visibroker que viene con Delphi 4 es:

prompt> vbver oad.exe

Information for: /Program Files/Borland/vbroker/Bin/oad.exe


Product Name: VisiBroker for C++
Version: 03.02.00.C2.02
Copyright: (C) 1996, 1998
Company: Visigenic Software, Inc.
Build Date: 03/02/1998 11:57:32

Como podrá ver, Delphi 4 utiliza una versión de Visibroker para C++. Como es el caso con
todas las librerías de C++, las llamadas han sido traducidas a archivos .PAS para su uso en
Delphi.

Capitulo 9.4. Mezclando Lenguajes y Plataformas con CORBA: Cómo Platicar con
programas en Java

En éste capítulo veremos cómo podemos hacer que Delphi (Enterprise) y Java platiquen en
CORBA. Además le servirá de práctica acerca de cómo hacer un programa en CORBA en Delphi sin
utilizar MIDAS.

Este projecto utilizará dos programas (cliente y servidor) que estarán implementados en dos
lenguajes (Delphi y Java). Como este es un curso de Delphi nos enfocaremos más a Delphi en
cuanto a los detalles.

Para que los programas en Java en esta sección funcionen, usted


necesitará JBuilder 3 Enterprise, Inprise AppCenter o algún SDK de Java
(Enterprise Edition) que tenga las librerías de Visibroker instaladas
apropiadamente.

La idea de hacer dos clientes y dos servidores tiene por objeto demostrar que podemos llamar al
servidor de Java desde un cliente de Delphi y viceversa. Además, ver dos ejemplos en lenguajes
diferentes le permitirá entender mejor hasta donde termina Delphi y donde comienza CORBA.

Un Servidor CORBA en Delphi

Como esta será una interfase muy simple, utilicemos Delphi para hacer un servidor. Simplemente
creamos una nueva aplicación (le he cambiado el Título a la forma para que diga "Servidor de
CORBA super-básico" y después seleccionamos File-New.

Seleccione la página de Multitier y "CORBA Object" a continuación.


A continuación Delphi le preguntará el nombre de clase de su objeto, de qué manera crearemos
las instancias y el modelo de hilos de ejecución. Mi objeto se llama "ObjetoCurso" Para mantener
las cosas simples, lo he hecho "Single Instance" y "Single-Threaded".

Seleccione OK y a continuación verá código como el que sigue:

TObjetoCurso = class(TCorbaImplementation, IObjetoCurso)


private
{ Private declarations }
public
{ Public declarations }
end;

implementation

uses CorbInit;

initialization
TCorbaObjectFactory.Create('ObjetoCursoFactory',
'ObjetoCurso', 'IDL:Project1/ObjetoCursoFactory:1.0', IObjetoCurso,
TObjetoCurso, iSingleInstance, tmSingleThread);
end.

Esta es la implementación de su Objeto CORBA de acuerdo a Delphi. Todavía no hace nada ni


implementa ninguna función, así que por ahora simplemente define un objeto que hereda de
TCorbaImplementation, e implementa la interface IObjetoCurso. Como la interface todavía no
tiene métodos, no necesitamos implementar nada.
En la inicialización de la unidad, Delphi crea una fábrica de Objetos (TCorbaObjectFactory.Create)
y registra con la fábrica nuestro objeto. Delphi creará una interface CORBA llamada
ObjetoCursoFactory y la "atará" a TCorbaObjectFactory.

En COM todos los objetos deben contar con una fábrica, pero en CORBA
éste no es el caso (en CORBA una fábrica es simplemente una técnica
específica de implementación, que no es requerida). Pero como Delphi
utiliza el mismo código para generar objetos en COM y CORBA, mientras
no implemente su servidor manualmente (con todas la complicaciones
que esto genera), Delphi siempre creará una fábrica (llamada
SuObjetoFactory) por usted. Esto es importante tener en cuenta cuando
utilice otros lenguajes para conectarse a servidores en Delphi, como
veremos más adelante.

Ahora que tenemos listo nuestro código inicial, comencemos por crear algunos métodos. Grabe su
proyecto (yo grabé mi DPR "ORBDelCurso"), y a continuación seleccione "View-Type Library". El
editor de librerías de tipos aparecerá a continuación. Notará que el editor de tipos es el mismo al
mostrado en el Capítulo 6.6.

Utilice el botón con flecha verde para crear un nuevo método, y nómbrelo "DeCabeza". Lo que
queremos hacer es una función que devuelva la cadena que ha recibido pero al revés.

Esta función recibirá un parámetro WideString y devolverá un parámetro WideString también, y


para lograr esto necesitamos especificar dos parámetros, uno como "valor de regreso (retval)".
Obviamente, uno es de entrada y otro es de salida:
También queremos hacer una función WideString llamada TuQuienEres para que nos diga si el
servidor está usando Delphi o Java.

TuQuienEres no tiene parámetros, pero necesitamos declarar uno (out, retval) para satisfacer al
editor de Tipos, que como es menso :-) cree que está lidiando con un IDispatch de COM y necesita
que todas las funciones regresen un HResult (lo cual a nosotros, como programadores de CORBA,
no nos interesa).

Ahora veamos el código que Delphi nos ha generado:

TObjetoCurso = class(TCorbaImplementation, IObjetoCurso)


private
{ Private declarations }
public
{ Public declarations }
protected
function DeCabeza(const Cadena: WideString): WideString; safecall;
function TuQuienEres: WideString; safecall;
end;

implementation

uses CorbInit;

function TObjetoCurso.DeCabeza(const Cadena: WideString): WideString;


begin

end;

function TObjetoCurso.TuQuienEres: WideString;


begin

end;

Note como, aún cuando la librería de tipos nos hace especificar y dar nombre a parámetros de
salida y nos obliga a especificar HRESULT como el tipo de retorno, nos ha definido las funciones
correctamente (regresando WideString). Esto es porque aunque el editor de tipos está enfocado a
COM, Delphi sabe cómo escribir CORBA adecuadamente. ¡Además esto nos permite exportar el
objeto como objeto COM y convertirnos en un servidor COM y CORBA a la vez, cosa que ningún
paquete hasta ahora ha permitido hacer!

Todo está listo para que implementemos nuestro programa. Simplemente


llenamos los "begin... end"s de nuestras funciones con el código adecuado y listo:

function TObjetoCurso.DeCabeza(const Cadena: WideString): WideString;


var
i : Integer;
begin

Result := '';
// Este for invierte los caracteres del mensaje
for i := Length(Cadena) downto 0 do Result := Result + Cadena[i];

end;

function TObjetoCurso.TuQuienEres: WideString;


begin
Result := 'Yo soy el objeto ObjetoCurso, implementado en Delphi';
end;

Felicidades! Acaba usted de crear su primer ORB!

Exportando IDL Para su Uso en Otros Lenguajes

Como mencioné en la sección teórica de interfases, las interfases se comunican hablando en el


lenguaje IDL. Los servicios CORBA para todos los lenguajes de programación cuentan con
convertidores de IDL al lenguaje y viceversa.

Para que nuestros clientes de Java se comuniquen con nosotros necesitaremos generar la
especificación de nuestra interfase en lenguaje IDL. Para hacer esto utilizamos el botón de la
esquina derecha en la barra de botones de la librería de tipos ("Export to IDL"). Éste botón exporta
a COM IDL, pero tiene un menú junto al mismo (subrayado por la franja roja en la gráfica
siguiente) que le permite seleccionar qué tipo de IDL quiere exportar. Selecciónelo y elija "Export
to CORBA IDL".

El IDL que es exportado será como sigue:


module ORBDelCurso
{
interface IObjetoCurso;

interface IObjetoCurso
{
wstring DeCabeza(in wstring Cadena);
wstring TuQuienEres();
};

interface ObjetoCursoFactory
{
IObjetoCurso CreateInstance(in string InstanceName);
};

};

Grabe este archivo (he llamado al mío "OrbDelCurso.idl") Cuando hagamos nuestro cliente (y el
servidor) en Java, necesitaremos el archivo para que Java nos genere el código apropiado (con la
utilería "idl2java").

Si usted genera IDL manualmente o con algún ORB escrito en otro lenguaje, necesitará utilizar una
utilería equivalente para generar el código "pas".

Hasta ahora (Diciembre 1999), no existe un programa para convertir IDL a


Pascal (que se llamaría "IDL2PAS"). Inprise ha prometido este programa
para una revisión futura de Delphi 5 Enterprise.

Un Cliente CORBA en Delphi

Ya que tenemos un servidor CORBA, podemos crear nuestro cliente. Como de costumbre, el
cliente es más sencillo (en cuanto a la conexión de objetos) que el servidor. Para crear nuestro
cliente sólo tenemos que incluir el archivo "OrbDelCurso_TLB.pas", que es nuestra especificación
de la interfase en Pascal.

Comenzaremos por crear una simple interfaz de usuario con un EditBox y tres botónes, uno para
conectar/desconectar, otro para llamar la función DeCabeza y otro para averiguar quién es
nuestro servidor. También pondremos un memo para las respuestas.

Ahora, hacer el cliente es sencillísimo. Seleccione "Project-Add to Project" del menú de Delphi y
navegue al directorio donde hizo el servidor. Añada el archivo "ORBDelCurso_TLB.pas" a su
proyecto. Añada ORBDelCurso_TLB a su clausula de USES en la sección "interface" de su forma
principal. Ahora, dentro de la forma del cliente (ya sea en private o public) declare una variable de
tipo IObjetoCurso (el mío se llama ObjetodelCurso).

Ahora la única línea de código que necesita escribir es:

ObjetodelCurso := TObjetoCursoCorbaFactory.CreateInstance('');
Donde desee hacer la conexión. A partir de entonces, su variable será un objeto al
cual usted puede llamar como cualquier otro objeto de Delphi, como por ejemplo
este código, que pone el resultado a la llamada remota "DeCabeza" en el Memo,
utilizando como parámetro nuestro campo de edición:

// De Cabeza
Memo1.Lines.Add(ObjetoDelCurso.DeCabeza(Edit1.Text));

En el momento de la conexión (CreateInstance), Delphi buscará en el subnet local cualquier objeto


que soporte ObjetoCursoFactory, y ejecutará la función CreateInstance para obtener un
"ObjetoCurso", que es el objeto que nosotros definimos.

Esto quiere decir que usted puede ejecutar una o varias veces su servidor en alguna computadora
de su red TCP/IP y sus clientes lo encontrarán "mágicamente", sin necesidad de mencionar una
computadora.

Ejecutando un servidor escrito en Visibroker

Para poder ejecutar el servidor, usted necesitará tener el servicio SmartAgent ejecutando. Si su
servicio SmartAgent no está presente o no está configurado al mismo puerto TCP que su objeto
CORBA (vea el "Smart-Agent Reg-Edit tool" en su folder de Visibroker en el menú de inicio), el
programa no ejecutará (porque Delphi se quedará esperando a que un servicio de nombres
Visibroker conteste).

Así que, ejecute su "Visibroker Smart Agent" (que es el registro de objetos de Visibroker). Se
encuentra en el menú de inicio, en el Subgrupo de "Visibroker" en su Delphi 4 o 5 Enterprise.
SmartAgent muestra una ventana blanca sin ningún mensaje.

Ahora ejecute su servidor y su cliente (posiblemente en máquinas diferentes) y diviértase!

He aquí una imagen de mi cliente en acción (mi servidor también está funcionando):
Un Cliente CORBA en Java

A continuación veremos cómo implementar un cliente en Java. Como este curso no está enfocado
a Java, sólo explicaré cómo generamos nuestro código con idl2java, como conectarnos al servidor,
y cómo accesamos nuestro objeto desde Java, sin explicar gran cosa acerca de como compilar,
cómo funcionan los botónes, etcétera. Pero he incluido en el Zip el código fuente en Java también,
para que usted lo pueda ver y examinar.

Para que los programas en Java en esta sección funcionen, usted


necesitará JBuilder 3 Enterprise, Inprise AppCenter o algún SDK de Java
(Enterprise Edition) que tenga las librerías de Visibroker instaladas
apropiadamente. Utilice el comando vbj en vez del comando java y el
comando vbjc en vez de javac para asegurarse de que las librerías de
Visibroker están siendo utilizadas.

Como mencionamos con anterioridad, primero debemos convertir el IDL que generamos al crear el
servidor de Delphi al lenguaje que usaremos para conectarnos, en este caso Java. Así que
ejecutamos "idl2java ORBDelCurso.idl" en la línea de comando. En el caso de IDL2Java, nos
generará un directorio con el nombre del módulo de CORBA, en este caso "ORBDelCurso". Este
directorio es un paquete de Java al que podemos hacer referencia en nuestro código.

Como hemos visto con anterioridad, los clientes son más fáciles de implementar que los
servidores. Ahora que tenemos el paquete que nos dice cómo pedirle a CORBA que utilice el
objeto sólo tenemos que crear un ObjetoCursoFactory y pedirle que nos genere un ObjetoCurso.
Idl2Java ya nos ha escrito este código, y lo ha puesto en la clase ObjetoCursoFactoryHelper.

Así que, para implementar un cliente que utilice el objeto que hemos escrito en Delphi, debemos
instanciar un objeto con el FactoryHelper, y después llamar a CreateInstance en el objeto (por
aquello de que Delphi siempre usa Fábricas de clases) para obtener nuestro objeto del curso. Por
ejemplo:

ORB orb;
ObjetoCursoFactory fac;
IObjetoCurso obj;

orb = ORB.init(args, null);


fac = ObjetoCursoFactoryHelper.bind(orb, null);
obj = fac.CreateInstance("");

Éste pedacito de Código en Java:

 Inicializa el orb con ORB.init, y los posibles argumentos de la línea de comando (solo lo
tiene que hacer una vez, al comenzar la aplicación).
 Pide al SmartAgent que nos encuentre una implementación de la fábrica de clases (porque
Delphi publica la fábrica de clases, no el objeto).
 Llama a CreateInstance para que nos dé un puntero de interfase al objeto que queremos
usar. Delphi recibe esta llamada y crea un TObjetoCurso, devolviéndonos la interfase que
queremos. Ahora obj tiene un IObjetoCurso que podemos llamar en Java como si fuera un
objeto local.
He creado un pequeño cliente en Java que usted puede ejecutar si tiene Visibroker for Java o
JBuilder utilizando la línea de comando "vbj ClienteORB usabind".

En el código en Java que he escrito, he añadido un parámetro, "usabind"


(en minúsculas) para que la utilización de bind sea opcional (bind nos
conecta con el SmartAgent). Si usted no especifica "usabind", el programa
buscará un archivo .ior en el directorio ".." (padre) y lo utilizará en vez de
usar un servicio de nombres. Esto le permite a su código en Java correr sin
necesidad de Visibroker (utilizando el ORB nativo del JDK). Pero
obviamente, no podrá conectarse a los programas equivalentes en Delphi,
que sí lo requieren. Recuerde usar usabind en este caso en particular!

Un Servidor CORBA en Java

Ahora que hemos probado que nos podemos comunicar entre Delphi y Java, tratemos de crear un
servidor en Java, para tener las cuatro piezas y poder examinar cómo funciona todo esto.

Los pasos para hacer funcionar un servidor en Java son:

 Obtener el código Java de interface para nuestro IDL con IDL2Java


 Crear un objeto que implemente la fábrica. IDL2Java creará un archivo llamado
_nuestroObjetoImplBase (en nuestro caso, _ObjetoCursoFactoryImplBase) dentro del
paquete. Ahora podemos programar nuestro objeto.
 Inicializar el ORB (orb_init)
 Inicializar el adaptador de objetos (BOA - Basic Object Adaptor) con BOA_init(). Este es el
servicio que nos permite ser un servidor CORBA.
 Crear un objeto de implementación para la fábrica, y nombrarlo para que el servicio de
SmartAgent pueda encontrarlo.
 Decirle al adaptador de objetos que nuestro objeto está listo.
 Decirle al adaptador de objetos que nuestra implementación está lista, y puede comenzar a
escuchar.

Hé aquí el código:

class ObjetoCursoServidor extends ORBDelCurso._ObjetoCursoFactoryImplBase {


...
public static void main( String[] args ) {
try
{

ORB orb = ORB.init( args, null );


System.out.println(orb.getClass().getName());
BOA boa = orb.BOA_init();
System.out.print("ORB inicializado.");
ObjetoCursoServidor impl = new ObjetoCursoServidor("ObjetoCurso");
System.out.print(impl.toString()+"\n");
boa.obj_is_ready(impl);
String ior = orb.object_to_string(impl);
boa.impl_is_ready();

} catch ( SystemException sysx ) {


System.err.println(sysx);
}
...

La fábrica sólo tiene una función, que se llama CreateInstance. Delphi nos había ahorrado el tener
que implementar el CreateInstance, pero como estamos en java lo debemos hacer manualmente.
Afortunadamente es muy fácil:

public IObjetoCurso CreateInstance(String instanceName) {


IObjetoCurso resultado = new ObjetoCurso();
return ( resultado );
};

Obviamente, ahora necesitamos hacer un ObjetoCurso.java que responda a las peticiones del
cliente. Idl2Java también nos ha escrito una base que podemos extender, así que simplemente
hacemos una clase que extienda _IObjetoCursoImplBase e implemente nuestras funciones
"DeCabeza" y "TuQuienEres".

Ahora lo podemos ejecutar y pedir al cliente de Delphi (o al de Java) que se conecte. Para
ejecutarlo las reglas son las mismas que con Delphi. El SmartAgent tiene que estar ejecutando.
Usted puede ejecutarlo con la línea de comando "vbj ObjetoCursoServidor".

He aquí al cliente de Delphi conectado a un servidor de Java. El funcionamiento es idéntico (ni


siquiera tuvimos que recompilar o decirle a Delphi que Java "existe") y la única diferencia es que
"TuQuienEres" devuelve una cadena diferente.
Como podrá deducir, esto es poderosísimo! Ahora puede usted utilizar toda la facilidad de uso de
Delphi para programar clientes o servidores en varios ambientes (Java no es el único lenguaje con
el que podemos platicar; CORBA existe para Mainframes, Unix y para muchos lenguajes
"tradicionales" como COBOL y otros), y communicarse entre un ambiente y otro con muy pocas
dificultades, y en tiempo real. Si encuentra que JDBC es más potente que Delphi en el servidor, o
que prefiere utilizar Java en el cliente porque algunos de sus usuarios utilizan Mac, Unix o Linux,
usted puede simplemente exportar la interfase y conectarse, sin necesidad de reescribir
aplicaciones completas.

Con todo esto, apenas hemos tocado la punta del iceberg en cuanto a CORBA y Visibroker. Espero
que esto le haya picado la curiosidad de investigar el gran mundo de la computación de grande
empresa.

Copiar el Código fuente (74K, formato Zip) para esta sección

También podría gustarte