ES Guia Delphi Marco Cantu Desarrollo
ES Guia Delphi Marco Cantu Desarrollo
La guía de Delphi
Libro para Desarrollo sistemas integrados control, SA
© 2009
Versión en castellano
2 - Indice
DERECHOS RESERVADOS
El contenido de esta publicación tiene todos los derechos reservados, por lo que no se
puede reproducir, transcribir, transmitir, almacenar en un sistema de recuperación o
traducir a otro idioma de ninguna forma o por ningún medio mecánico, manual,
electrónico, magnético, químico, óptico, o de otro modo. La persecución de una
reproducción no autorizada tiene como consecuencia la cárcel y/o multas.
LIMITACIÓN DE LA RESPONSABILIDAD
Tantos el autor como en Danysoft hemos revisado el texto para evitar cualquier tipo de
error, pero no podemos prometerle que el libro esté siempre libre de errores. Por ello le
rogamos nos remita por e-mail a sus comentarios sobre el libro en
attcliente@danysoft.com
DESCUENTOS ESPECIALES
Recuerde que Danysoft ofrece descuentos especiales a centros de formación y en
adquisiciones por volumen. Para más detalles, consulte con Danysoft.
MARCAS REGISTRADAS
Todos los productos y marcas se mencionan únicamente con fines de identificación y están
registrados por sus respectivas compañias.
IMPRESO EN ESPAÑA
ISBN : 978-84-932720-9-8
© | Madrid, Noviembre-2009 | versión en castellano.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 3
Prólogo
Este libro es una secuela de Delphi 2007 Handbook, así que no re-
pito su contenido en absoluto. Si estás interesado en las nuevas
funcionalidades de Delphi 2009 desde Delphi 7 (o una vieja versión
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 5
Tabla de
Contenidos
Prólogo ........................................................................................................ 3
Introducción .............................................................................................. 13
Delphi ............................................................................................................................ 14
Por Qué Importa Win32.......................................................................................... 14
Este Libro ...................................................................................................................... 16
El Autor ..........................................................................................................................17
Información de Contacto ..........................................................................................17
Apartado I:
Unicode..................................................................................................... 19
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 7
Apartado II:
Delphi 2009 y Su Compilador ................................................................... 113
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 9
Resumen de las Nuevas Unidades y Las Nuevas Clases RTL ..................................... 262
Más y Menos FastCode .......................................................................................... 264
A continuación............................................................................................................. 264
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 11
Conclusión ...................................................................................................................420
Introducción
1La versión actual del compilador de Delphi, de hecho, es la 20.00. Esto es desta-
cado por el valor que la VER200 define, mencionado en la sección “Versión
del Compilador” al comienzo del Capítulo 7.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 13
Delphi
Como ya he mencionado, la creación de la división CodeGear
y luego la adquisición de esta división por Embarcadero Tech-
nologies está proporcionando unos nuevos cimientos para
Delphi, y nuevas inversiones en el producto. Incluso si no
tiene un marketing agresivo, y queda fuera del radar de la ma-
yoría de publicaciones, aún así Delphi tiene millones de usua-
rios activos, tanto en el sector de ISV (donde su simplicidad
en el despliegue gana sobre las versiones basadas en platafor-
mas) como en los entornos cliente/servidor, donde la estabili-
dad de una inversión es más valorada que el estar en la onda
de una plataforma.
Es verdad que la comunidad de Delphi es más pequeña de lo
que fue hace unos pocos años, y que parte de ella aguanta con
versiones más viejas del producto, pero sigue siendo el líder
en muchos países y realmente ha vuelto a estar de buen hu-
mor en el último año.
Este Libro
Habiendo introducido la situación de Delphi, es el momento
de hablar sobre este libro. Como mi reciente “Delphi 2007
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 17
El Autor
Para aquellos que tienen en sus manos por primera vez uno
de mis libros, y para aquellos que no han leído recientemente
uno, mi nombre es Marco Cantù, y he estado en el negocio de
“escritor de libros de Delphi” desde la primera versión del
producto, cuando lancé el “Mastering Delphi” original (un
corpulento tomo de 1.500 páginas). Esta no fue mi primera
experiencia escribiendo, ya que antes había escrito trabajos
sobre Borland C++ y la Object Windows Library.
En los últimos años, junto a mi continuo compromiso con la
comunidad de Delphi, también he dedicado mucho tiempo a
las tecnologías relacionadas con XML, y a XSLT, con servicios
web (incluyendo las implementaciones SOAP y REST), Ja-
vaScript y AJAX, y otras tecnologías Web 2.0. Después de un
descanso, he vuelto a escribir para auto-publicar mis libros, y
no solo sobre Delphi, ya que he finalizado también un volu-
men sobre redes sociales.
Junto a la escritura, me mantengo ocupado con consultorías
(la mayoría sobre arquitectura de aplicaciones), ayudando a
vender Delphi en Italia, haciendo revisiones de código, ense-
ñando Delphi, y realizando consultorías generales para desa-
rrolladores.
Información de Contacto
Finalmente, aquí hay alguna información de contacto:
http://blog.marcocantu.com
http://www.marcocantu.com
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 19
Apartado I:
Unicode
Capítulo 1: ¿Qué
es Unicode?
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 21
4Si bien la mayoría de los caracteres de control han perdido su sentido (como el
separador de archivo o el tabulador vertical), algunos como el retorno de ca-
rro (# 13), salto de línea (# 10), Tab (# 9), y Retroceso (# 8) se usan aún coti-
dianamente.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 23
por defecto) obtengo la siguiente salida (la suya puede ser di-
ferente)5:
5Si el sistema por defecto utilizase una página de códigos multi-byte, el código de
este programa se convierte en un sin sentido, porque la mayoría de los carac-
teres entre #$80 y #$FF son bytes perdidos, que no se puede mostrar por si
mismos.
6Como veremos en detalle en el próximo capítulo, en Delphi 2009 el tipo 'Char'
ha cambiado y el antiguo tipo Char, desde Delphi 1 a Delphi 2007, se llama
ahora AnsiChar.
var
I: Integer;
begin
ClearGrid;
for I := 32 to 255 do
begin
StringGrid1.Cells [I mod 16 + 1,
I div 16 + 1] := AnsiChar (I);
end;
end;
7Másinformación del libro “The Unicode Standard” que puede usted encontrar
en: http://www.unicode.org/book/aboutbook.html.
8Para una demostración de este ejemplo, vea el vídeo de YouTube "Delphi does
Unicode ", que realicé en agosto del 2008, durante el período en que se nos
permitió a los probadores experimentales de "Tiburón" anunciar las nuevas
características del producto. Con estos vídeos quedan cubiertos los otros
ejemplos de este capítulo. El vínculo es el siguiente:
http://www.youtube.com/watch?v=BJMakOY8qbw
9La página de códigos utilizada para compilar el programa sólo afecta a la forma
en que se gestiona el carácter AnsiChar, y no el Char Unicode. De hecho,
los caracteres Unicode y strings ignoran el código de la página por completo
(¡lo que es una gran razón para usarlos!)
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 27
11El Conjunto universal de caracteres 2-byte (UCS-2) se considera ahora una co-
dificación de caracteres obsoleta. Sin embargo, ambos UTF-16 y UCS-2, ma-
pean los puntos de código contenidos de la misma forma, dentro del BMP,
excluyendo el subrogado especial punto de código 2048.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 29
Transformación de Formatos en
Unicode (UTF)
Pocas personas saben que el término común "UTF" es el acró-
nimo de Unicode Transformation Format. Estos son algorit-
mos de asignación, mapeados, parte del Unicode estándar,
que ubica cada punto de código en su mapa (la representación
numérica absoluta de un carácter) a una secuencia única de
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 31
Estudiando UTF-16
¿Cómo crear una tabla de caracteres Unicode como la que he
mostrado anteriormente sólo para los ASCII? Podemos empe-
zar por ver los puntos de código en el plano básico multilingüe
sobre el 32 (los caracteres habituales de control) y excluir los
llamados pares subrogados. No todos los valores numéricos
son verdaderos puntos de código UTF-16, ya que hay algunos
valores numéricos no válidos para caracteres (llamados su-
brogados) utilizados para crear códigos pareados y represen-
tar puntos de código por encima de 65535.
Como mostrar una tabla de 256 * 256 es bastante duro, he
mantenido la rejilla tal como es y añadido un control Tree-
View en el costado que le permiten elegir un bloque arbitrario
de 256 puntos a mostrar. He usado un TreeView, ya que hay
256 secciones (incluidos los subrogados), por lo que he deci-
dido agruparlos en dos niveles:
// Función de Ayuda
function GetCharDescr (nChar: Integer): string;
begin
if nChar < 32 then
Result := 'Char #' + IntToStr (nChar) + ' [ ]'
else
Result := 'Char #' + IntToStr (nChar) +
' [' + Char (nChar) + ']';
end;
Descripciones de Puntos de
Código Unicode
En el sitio web del Consorcio de Unicode, usted podrá encon-
trar gran cantidad de información, incluso un archivo de texto
con una descripción escrita de un gran número de puntos de
código (la mayoría de ellos con exclusión de los ideogramas
unificados para el chino, japonés, y coreano). He usado este
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 35
sUnicodeDescr.Add(strNumber + '=' +
strDescr1 + ' ' + strDescr2);
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 37
Unicode en Win32
Desde sus primeros días, la API de Win32 (que se remonta a
Windows NT) ha incluido el soporte de los caracteres Uni-
code. La mayoría de funciones de la API de Windows tienen
PAnsiChar o PWi-
Las declaraciones son idénticas, pero ambas utilizan
deChar para el paso del string. Observe que la versión simple
sin indicación de formato de cadena es sólo un marcador de
posición para uno de ellos, invariablemente utiliza la 'A' en la
versiones anteriores de Delphi (de dónde se ha tomado el có-
digo), mientras que en Delphi 2009 (como veremos) la opción
por defecto se convierte en la versión "W". Básicamente, cada
función del API que tiene parámetros strings tiene dos versio-
nes separadas, mientras que todas las funciones que no utili-
zan strings tienen una sola, por supuesto.
Windows 95 (y las siguientes versiones de Windows 98 y ME)
aplicaban las funciones A y proveían las funciones W como
alias que convertían Wide en Ansi. Esto significa que estas
funciones generalmente no soportan Unicode, con algunas ex-
cepciones como TextOutW (que se implementa como una ver-
dadera función Unicode en Windows 95/98/ME). Por otra
parte, Windows NT y las siguientes versiones basadas en él
(Windows 2000, XP y Vista) aplican funciones W, y proveen
las funciones A como un alias de conversión de Ansi a Wide (a
veces, ralentizando las operaciones).
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 39
16Lafrase está escrita en bengalí y significa "¿Qué es Unicode?", por lo menos se-
gún http://www.unicode.org/standard/translations/bangla.html. Para el
nombre de la variable he utilizado parte de la frase ... que probablemente (o
afortunadamente) ¡no signifique nada!
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 41
Unicode
Usted puede preguntarse si utilizar Unicode llamando a la
API de Windows es más lento o más rápido que utilizando la
sencilla API "A". Huelga decir que he tenido la misma duda,
como Unicode causa algunas cargas extras en memoria, me
preguntaba si esta iniciativa realmente tiene sentido para
programas que no necesiten Unicode.
En teoría, como la única implementación de la API de Win-
dows Vista y XP es la basada en Unicode, deberíamos esperar
una velocidad mayor de ejecución, así como que el código
salte alguna conversión de cadena durante su llamada. De
modo que lo he intentado con el siguiente código, que es parte
del ejemplo UniApiSpeed:
procedure TForm30.btnUserNameClick(Sender: TObject);
var
I:Integer;
nSize: DWORD;
t1: TDateTime;
str: string;
pch: PChar;
begin
nSize := 100;
SetLength (str, nSize);
pch := PChar (str);
t1 := Now;
for I := 1 to 10000 do
begin
GetUserName (pch, nSize);
end;
t1 := Now - t1;
Memo1.Lines.Add ((Sender as TButton).Caption + ' ' +
FormatDateTime ('ss.zzz', t1));
Parámetros UnicodeString en
llamadas al API
Aunque la mayoría de funciones de la API de Windows que
tienen como parámetro una cadena están declaradas en la
unidad Windows con un parámetro PChar, hay algunas excep-
ciones a esta regla.
Las declaraciones de la API GetTextExtentPoint32, ExtTextOut,
LoadKeyboardLayout, DrawText, SetWindowText, LoadCursor,
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 43
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 45
nPoint: Word;
I: Integer;
begin
nPoint := 32 + random (1024*64 - 32 - numberOfChars);
if (nPoint >= $D800 - numberOfChars) and
(nPoint <= $DFFF) then
begin
// reintentar y saltar
PaintFonts;
Exit;
end;
A continuación
No quiero ahondar en los detalles de las características que
cambian considerablemente en Delphi 2009 y que tendremos
tiempo para cubrir posteriormente en este libro. Ahora es
hora de empezar a buscar la aplicación efectiva de las cadenas
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 47
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 49
Capítulo 2: El
Tipo Unicode
String
De AnsiChar a WideChar
Durante algún tiempo, Delphi ha incluido dos tipos de datos
para representar caracteres:
AnsiChar, con una representación de 8 bits (con un total de
256 símbolos diferentes), interpretados en función de su có-
digo de página;
WideChar, con 16 bits de representación (con un total de 64K
de símbolos diferentes)22.
En este sentido, nada ha cambiado en Delphi 2009. Lo que es
diferente es que el tipo Char antes era un alias de AnsiChar y
ahora es un alias de WideChar. Cada vez que el compilador
detecta Char en su código, lee realmente WideChar. Tenga en
cuenta que no hay forma de cambiar esta nueva compilación
por defecto23.
Este es un cambio, que afecta a una gran cantidad de código
fuente y con muchas ramificaciones. Por ejemplo, el puntero
PChar ahora un alias de PWideChar, en lugar de PAnsiChar,
como solía ser. Veremos cómo esto afecta a las llamadas a las
22WideChar es simplemente un entero de 16-bits sin signo sin ningún tipo de co-
dificación de caracteres específica adjunta. Cuando se utiliza un UnicodeS-
tring, sin embargo, un WideChar puede interpretarse como un subrogado, de
modo que dos WideChar pueden ser enlazados para representar a un único
punto de código Unicode. Amplía esta información en la sección “UnicodeS-
tring y Unicode”.
23Como con el tipo string, el tipo Char está específicamente mapeado a un tipo
fijo de datos por código. Los desarrolladores solicitaron una directiva de
compilación para cambiarlo, pero sería una pesadilla en terminos de control
de calidad, soporte o compatibilidad de paquetes entre otras cosas. De todas
formas, todavía tiene la opciónde convertir su código para que use un tipo
específico como el AnsiChar.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 51
24Si usted intenta declarar un amplio conjunto de, digamos, una serie de núme-
ros enteros (como lo hice en algunas líneas comentadas de código del ejem-
plo CharTest) obtendrá el error: E2028 Sets may have at most 256 ele-
ments.
var
charSet: set of AnsiChar; // suprime la alerta
begin
charSet := ['a', 'b', 'c'];
if AnsiChar('a') in charSet then // suprime la alerta
...
Chr (128)
Caracteres de 32-bit
A pesar de que el tipo por defecto Char está ahora asignada a
WideChar, vale la pena comentar que Delphi define también
un tipo de carácter de 4-bytes, UCS4Char, que se define en la
unidad System como:
type
UCS4Char = type LongWord;
ch2 := 'ù';
Memo1.Lines.Add ('AnsiChar');
Memo1.Lines.Add ('UpCase ù: ' + UpCase(ch2));
Memo1.Lines.Add ('ToUpper ù: ' + ToUpper (ch2));
27Lomismo también es válido para la función UpperCase, que gestiona sólo AS-
CII, mientras que AnsiUpperCase gestiona todo en Unicode, a pesar de su
nombre.
Sobre String y
UnicodeString
El cambio en la definición del tipo Char es importante porque
está ligado con el cambio en la definición del tipo String. A di-
ferencia de characters, strings se asigna a un nuevo tipo de
datos que antes no existía, llamado UnicodeString. Como ve-
remos, su representación interna es también, muy diferente
de la del tipo classic AnsiString29.
Como ya había un tipo WideString en el lenguaje, represen-
tando cadenas basadas sobre el tipo WideChar, ¿por qué mo-
lestarse con la definición de un nuevo tipo de datos? WideS-
tring no tenía (y sigue sin tener) un recuento de referencia y
es extremadamente pobre en términos de rendimiento y flexi-
bilidad (por ejemplo, utiliza el asignador de memoria global
de Windows, antes que los nativos FastMM4).
Al igual que AnsiString, UnicodeString tiene recuento de refe-
rencia, utiliza semánticas copy-on-write y se resuelve bas-
tante bien. A diferencia de AnsiString, UnicodeString utiliza
dos bytes por carácter30 y se basa en UTF-16.
El tipo string está ahora asignado al tipo UnicodeString en un
código duro tal como lo está el tipo Char por las mismas razo-
nes. No hay ninguna directiva del compilador u otro truco
para cambiar esto. Si tiene código que debe seguir utilizando
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 59
Code page Elem size Ref count length Primer carácter de la cadena
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 61
UnicodeString y Unicode
Huelga decir que el nuevo tipo string (o el nuevo tipo Unico-
deString, para ser más preciso) utiliza el conjunto de caracte-
res Unicode. Si ha leído el anterior capítulo, la pregunta sería,
“¿Qué sabor de Unicode?”
No debería de sorprendernos conocer que los nuevos tipos de
cadena usan, como ya he mencionado, UTF-1633. Esto tiene
mucho sentido por muchas razones, la más importante es que
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 63
El Tipo UCS4String
Existe también otro tipo de cadena que puede utilizar para
manejar una serie de puntos de código Unicode, el tipo
UCS4String. Este tipo de datos representa una matriz diná-
mica de caracteres de 4-bytes (del tipo UCS4Char). Como tal,
no tiene ningún recuento de referencia o apoyo copy-on-
write, y muy poco soporte en la RTL.
35El hecho de que dos puntos de código Unicode pueda ser visualizado como un
único grafema (véase la sección de "puntos de código Unicode y Graphemes"
en el Capítulo 1) hace que sea aún más difícil mapear el número de Wide-
Char en una cadena Unicode con el número de caracteres de la pantalla.
36Estoexcluye los tipos de cadenas que no son por referencia, entre los que se in-
cluyen los tipos ShortString, WideString, y UCS4String.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 65
personalizado
Además de utilizar el nuevo tipo AnsiString, que está vincu-
lado por defecto a la página de códigos utilizada cuando com-
piló la aplicación, usted puede utilizar el mismo mecanismo
para definir su propio tipo de cadena personalizada. Por
ejemplo, puede definir un tipo de cadena Latin-1 (como lo he
hecho en el ejemplo LatinTest) escribiendo:
type
Latin1String = type AnsiString(28591);
procedure TFormLatinTest.btnNewTypeClick(
Sender: TObject);
var
str1: Latin1String;
begin
str1 := 'a string with an accent: Cantù';
Log ('String: ' + str1);
procedure InternalUStrFromPCharLen(
var Dest: UnicodeString; Source: PAnsiChar;
Length: Integer; CodePage: Integer);
function WCharFromChar(WCharDest: PWideChar;
DestChars: Integer; const CharSource: PAnsiChar;
SrcBytes: Integer; CodePage: Integer): Integer;
function MultiByteToWideChar(CodePage, Flags: Integer;
MBStr: PAnsiChar; MBCount: Integer;
WCStr: PWideChar; WCCount: Integer): Integer; stdcall;
external kernel name 'MultiByteToWideChar';
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 69
I: Integer;
begin
for I := 128 to 255 do
begin
str1 := str1 + AnsiChar (I);
str2 := str2 + AnsiChar (I);
end;
for I := 0 to 15 do
begin
Log (IntToStr (128 + I*8) + ' - ' +
IntToStr (128 + I*8 + 7));
Log ('Lati: ' + Copy (str1, 1 + i*8, 8));
Log ('Ansi: ' + Copy (str2, 1 + i*8, 8));
end;
end;
str1: CyrillicString;
I: Integer;
begin
str1 := 'a string with an accent: Cantù';
Log ('String: ' + str1);
Log ('Last char: ' + IntToStr (
Ord (str1[Length(str1)])));
Log('ElemSize: ' + IntToStr (StringElementSize (str1)));
Log('Length: ' + IntToStr (Length (str1)));
Log ('CodePage: ' + IntToStr (StringCodePage (str1)));
str1 := '';
for I := 150 to 250 do
str1 := str1 + CyrillicString(AnsiChar (I));
Log ('High end chars: ' + str1);
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 71
str16 := str8;
Memo1.Lines.Add('UTF-16');
Memo1.Lines.Add('Length: ' + IntToStr (Length (str16)));
Memo1.Lines.Add('5: ' + IntToStr (Ord (str16[5])));
UTF-8
Length: 6
5: 195
6: 185
UTF-16
Length: 5
5: 249
Conversión de Cadenas
Hemos visto que usted puede asignar un valor UnicodeString
a un AnsiString, o a un UTF8String y la conversión se llevará
siempre a cabo. Del mismo modo, cuando usted asigne un An-
siString, con un determinado código de página, a otro basado
en un código de página diferente, aparece la conversión auto-
máticamente. También puede convertir una cadena asignando
una página de códigos diferente, preguntemos por la conver-
sión a realizar:
type
Latin1String = type AnsiString(28591);
procedure TFormStringConvert.btnLatin1Click(
Sender: TObject);
var
str1: AnsiString;
str2: Latin1String;
rbs: RawByteString;
begin
str1 := 'any string with a €';
str2 := str1;
Memo1.Lines.Add (str1);
Memo1.Lines.Add (IntToStr (Ord (str1[19])));
Memo1.Lines.Add (str2);
Memo1.Lines.Add (IntToStr (Ord (str2[19])));
rbs := str1;
SetCodePage(rbs, 28591, True);
Memo1.Lines.Add (rbs);
Memo1.Lines.Add (IntToStr (Ord (rbs[19])));
end;
Conversiones Ralentizando
Nuestro Código
Las conversiones automáticas, realizándose en segundo
plano, son muy prácticas, ya que el sistema hace un montón
de trabajo por nosotros, pero si no lo hace con cuidado, consi-
derando lo que está haciendo, podría terminar con un código
extremadamente lento, por las continuas conversiones y ope-
raciones de copia de las cadenas. Considere la posibilidad del
siguiente código (parte del ejemplo StringConvert):
str1 := 'Marco ';
str2 := 'Cantù ';
for I := 1 to 10000 do
str1 := str1 + str2;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 75
42El aumento exponencial es debido al hecho de que cada vez más las grandes ca-
denas deben volver a ser asignadas en la memoria muchas veces. Lo qué se
ve frenado por el código es parcialmente la conversión, pero sobre todo la
necesidad de crear nuevas cadenas grandes temporales en lugar de seguir
aumentando el tamaño de la actual.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 77
Concatenación
Hablando de la concatenación de cadenas, usted tiene que es-
tar atento a las concatenaciones que engloben cadenas litera-
les. Por ejemplo, debe considerar las aparentes siguientes lí-
neas triviales de código:
Log ('String: ' + str1);
Log (str1 + ' is a string');
Usando RawByteString
¿Qué pasa si usted necesita pasar un AnsiString como pará-
metro a una rutina? Cuándo el parámetro es asignado a una
cadena con un tipo de codificación especifico, esta se conver-
tirá al tipo adecuado, con la posibilidad de pérdida de datos.
Esa es la razón por la que Delphi 2009 introduce un nuevo
tipo de cadena personalizada, llamado RawByteString y que
se define como:
type
RawByteString = type AnsiString($ffff);
44Nodebe confundirse por este soporte ampliado para 1-byte por carácter de las
cadenas compatibles ANSI: la solución preferida, es de lejos, migrar el pro-
cesamiento de código de su cadena al tipo UnicodeString. No se deje tentar
demasiado por estos nuevos tipos de cadenas adicionales.
45Paraver algunas consideraciones interesantes sobre RawByteString vaya al
blog de Jan Goyvaerts http://www.micro-isv.asia/2008/08/using-rawbytes-
tring-effectively/
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 81
DisplayStringData (strAnsi);
DisplayRawData (strAnsi);
end;
DisplayStringData(str: AnsiString)
String: Some text Ò€
CodePage: 1252
Address: 28149532
DisplayRawData(str: RawByteString)
String: Some text Ò€
CodePage: 1252
Address: 28149532
Si esto parece evidente, tal vez no sea tan claro lo que ocurre
cuando pasamos una UTF8String como parámetro real a los
métodos. La llamada del código es bastante similar, aunque
convierto cada carácter tratándolo como un valor UTF-8 :
var
strUtf8: UTF8String;
nChar: Integer;
begin
strUtf8 := 'Some text ';
nChar := 210;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 83
DisplayStringData (strUtf8);
DisplayRawData (strUtf8);
end;
DisplayStringData(str: AnsiString)
String: Some text ?
CodePage: 0
Address: 28804732
DisplayRawData(str: RawByteString)
String: Some text
CodePage: 65001
Address: 28804892
DisplayStringData(str: AnsiString)
String: Some text Ò?
DisplayRawData(str: RawByteString)
String: Some text Ò
Cyrillic string
String: Some text ТФ
DisplayStringData(str: AnsiString)
String: Some text ??
DisplayRawData(str: RawByteString)
String: Some text ТФ
Cadenas y Caracteres
Literales
Hemos visto varios ejemplos en los que puede asignar un ca-
rácter literal individual o una cadena literal a cualquiera de
los tipos de cadenas, con la conversión propia que tienen lu-
gar detrás de estas escenas.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 85
47あい se traduce por "reunión", según BabelFish, pero no estoy 100% seguro de
dónde lo encontré inicialmente .
Streams y Codificaciones
Si en nuestra aplicación movemos todas nuestras cadenas a
Unicode, cuando se trabaja con la RTL y la VCL, y mientras
que la invocación de la API de Windows no sea difícil, las co-
sas pueden ser un poco más complicadas, tal como leer y es-
cribir sus cadenas desde ficheros. ¿Qué sucede, por ejemplo,
con las operaciones de archivos con TStrings?
Delphi 2009 introduce otra nueva clase de base para manejar
archivos codificados, denominada TEncoding y como imi-
tando algo a la clase System.Text.Encoding del .NET Frame-
work. La clase TEncoding, que se define en la unidad SysUtils,
tiene varias subclases que representan las codificaciones auto-
máticamente soportadas por Delphi (estas son codificaciones
estándares a las que puede añadir las suyas propias):
type
TEncoding = class
TMBCSEncoding = class(TEncoding)
TUTF7Encoding = class(TMBCSEncoding)
TUTF8Encoding = class(TUTF7Encoding)
TUnicodeEncoding = class(TEncoding)
TBigEndianUnicodeEncoding = class(TUnicodeEncoding)
public
class property ASCII: TEncoding read GetASCII;
class property BigEndianUnicode: TEncoding
read GetBigEndianUnicode;
class property Default: TEncoding read GetDefault;
class property Unicode: TEncoding read GetUnicode;
class property UTF7: TEncoding read GetUTF7;
class property UTF8: TEncoding read GetUTF8;
48Estas
líneas se han extraído de la web “¿Qué es Unicode?” del Consorcio de
Unicode, que tiene su texto traducido en varios idiomas utilizando una varie-
dad de alfabetos.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 91
if ListBox1.Items.Text <>
UnicodeString (AnsiString(ListBox1.Items.Text)) then
encoding1 := TEncoding.UTF8;
ListBox1.Items.SaveToFile(strFileName, Encoding1);
procedure TStringsHelper.SaveToFile(
const strFileName: string);
begin
inherited SaveToFile (strFileName, TEncoding.UTF8);
end;
50Si está interesado en aprender más acerca de los ayudantes de clase, una buena
fuente es mi “Manual Delphi 2007”, pero seguramente puede encontrar
otras referencias buscando en la web. El concepto de clase de ayuda es poco
conocido pero es una característica muy potente de las últimas versiones
Delphi.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 93
end;
function TUTF32Encoding.GetByteCount(
Chars: PChar; CharCount: Integer): Integer;
begin
Result := CharCount * SizeOf(UCS4Char);
end;
function TUTF32Encoding.GetCharCount(
Bytes: PByte; ByteCount: Integer): Integer;
begin
Result := ByteCount div SizeOf(UCS4Char);
end;
function TUTF32Encoding.GetMaxByteCount(
CharCount: Integer): Integer;
begin
Result := (CharCount + 1) * 4;
end;
function TUTF32Encoding.GetMaxCharCount(
ByteCount: Integer): Integer;
begin
Result := (ByteCount div 4) + (ByteCount and 1) + 1;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 95
Result[0] := $FF;
Result[1] := $FE;
Result[2] := $00;
Result[3] := $00;
end;
Unicode y la VCL
Disponer de soporte para cadenas Unicode en el lenguaje Del-
phi es emocionante, después de haber sido reasignada la API
de Win32 a la versión Wide ofrece así un montón de migracio-
nes fáciles, pero el cambio fundamental es que toda la RTL y
la Visual Component Library (VCL) están ahora plenamente
habilitadas para Unicode. Todos los tipos strings (y las string
lists) gestionados por los componentes están declarados como
52Estos
dos programas son parte de “Mastering Delphi 2005” y no he copiado el
código fuente, ya que son bastante simples. Puedes descargarlos al igual que
todo el código fuente del libro desde www.marcocantu.com/md2005
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 99
Width = 75
Height = 25
Caption = #12354#12356
TabOrder = 0
end
Localizando la VCL
Con el soporte a Unicode, el tradicional soporte de Delphi "bi-
direccional mode ", o BiDiMode, reflejo de los controles en un
formulario, y el Translation Manager, que forma parte del
IDE, es cada vez más relevante.
No voy a cubrir BiDiMode en detalle, ni proveer orientación
para el Internal y External Translation Managers, ya que estas
herramientas no cambian comparadas con las versiones ante-
riores de Delphi. La arquitectura de traducción de la VCL son
La guía de Delphi por Marco Cantù
100 - Indice
A continuación
Ahora que ha visto cómo trata Delphi 2009 las cadenas Uni-
code, podemos centrarnos en la transición existente en el có-
digo fuente Object Pascal del mundo ASCII al mundo Uni-
code. Hay muchas cuestiones relacionadas, como PChar ba-
sado en un puntero matemático, una buena razón por la que
se trata este tema en un capítulo separado.
La cobertura de las nuevas características relacionadas con
cadenas, no termina aquí, en el capítulo 7 cubriré otras nue-
vas características de la RTL como la clase TStringBuilder y
otras clases mejoradas para el tratamiento de texto.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 101
Capítulo 3:
Exportando a
Unicode
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 103
{$ENDIF}
Operaciones Char
Erróneas
Como acabo de mencionar, la mayor parte de operaciones ba-
sadas en cadenas de caracteres se recompilan y migran sin
problemas. Sin embargo, hay algunas que no y requerirán una
solución en el código.
Una gran cantidad de código Pascal, Turbo Pascal, Object
Pascal, y Objet Pascal de Delphi, asume que el tamaño de un
carácter es un byte. Todo este código puede potencialmente
fallar al pasar a Delphi 2009. Como veremos en la sección
acerca de FillChar a continuación, para obtener el tamaño ac-
tual en bytes de una cadena se deberá siempre multiplicar la
longitud de la cadena por el valor StringElementSize, ya que a
menudo un carácter requiere de dos bytes (pero no siempre).
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 105
var
str1, str2: string;
begin
str1 := 'here comes a string';
str2 := 'here comes a string';
FillChar (str2[1],
Length (str2) * StringElementSize (str2), 0); // yes!
Memo1.Lines.Add ('15 char is: ' + str2[15]);
FillChar (str2[1],
Length (str2) * StringElementSize (str2), 'A');
Memo1.Lines.Add ('15 char is: ' + str2[15]);
Operaciones de Cadena
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 109
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 111
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 113
finally
memStr.Free;
end;
Añadiendo y Concatenando
Cadenas
Otro tipo de codificación que debe sustituir siempre que sea
posible, es la cadena de concatenación de código. No es dema-
siado difícil encontrar las apariciones de AppendStr en su có-
digo (también porque utilizándolo provocará una advertencia
por obsoleto: deprecated warning), pero es más complicado el
modo de sustituir la concatenación de cadenas directa reali-
zada con el signo +.
También, la sugerencia es sustituir la concatenación de cade-
nas directa con el uso de la clase TStringBuilder en el caso que
esté realizando una concatenación56 compleja. Para mostrar
un mensaje compuesto de dos cadenas, mantener el signo +
es totalmente correcto.
Una vez más, lo que realmente debería velar es por la concate-
nación que cause conversiones implícitas de cadena, ya que
esto significa que se copien los datos muchas, muchas veces.
En otras palabras, añadir y concatenar cadenas funciona bien
cuando todas las variables de cadena (left-value y right-va-
lues) son del mismo tipo (toda UnicodeString, toda AnsiS-
tring, toda UTF8String, etc.). En ese caso, el compilador uti-
liza el código de la página correcto para los strings literales.
Cuando se mezclen cadenas con diferentes páginas de código,
se harán conversiones explícitas para evitar que una conver-
sión oculta ralentice el código (o cause pérdida de datos).
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 115
Molestas “Importaciones”
Actuales
Mientras recompilaba cientos de aplicaciones de mis anterio-
res libros, choqué con unos pocos casos concretos en los que
portar a Unicode requeriría algunas actualizaciones reales y
no una simple recompilación. Algunos de estos casos son real-
mente sólo errores triviales, y fáciles de solucionar in situ ob-
servando el código fuente, pero creo que es importante refe-
renciarlos aquí, ya que su código podría utilizar técnicas simi-
lares. Yo podría haber construido interminables ejemplos “a
propósito”, pero decidí utilizar casos reales, aunque posible-
mente sean menos importantes.
var
ssample : string;
predeterminadas
En StrUtils y SysUtils solía haber una gran variedad de fun-
ciones y procedimientos con ANSI en su nombre. ¿Qué sucede
con ellos en el Delphi Unicode? Debemos de eliminarlos,
mantenerlos, ¿o qué?
No hay una respuesta única, pero en general pueden seguir tal
como están implementadas aplicándose a las cadenas de tipo
genérico, pero sería aún mejor renombrarlas para utilizar el
mismo nombre, sin el prefijo Ansi.
En algunos casos, la actualización es automática. La mayor
parte de las funciones de cadenas Ansi de la RTL (con o sin un
prefijo Ansi) se han trasladado a la nueva unidad y la mayoría
de ellas tienen una versión sobrecargada sobre la base del tipo
UnicodeString. Si usted no incluye esta unidad, acabará vin-
culando automáticamente58 a la versión UnicodeString.
58Si lo que desea es seguir usando el tipo AnsiString, y no desea añadir la unidad
AnsiStrings en demasiados lugares, considere la posibilidad de utilizar una
directiva de alias a la unidad, por ejemplo, la redefinición de SysUtils como
SysUtils más AnsiStrings. En una línea de comandos sería:
-AsysUtils=SysUtils;AnsiString
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 119
Para hacer las cosas aún más complicadas, hay funciones que
tienen una versión Wide (de nuevo para mantener la compati-
bilidad con la unidad WideStrUtils) y algunas funciones que
sólo tienen una versión Ansi.
// in AnsiStrings
function UpperCase(const S: AnsiString):
AnsiString; overload;
function UpperCase(const S: AnsiString;
LocaleOptions: TLocaleOptions): AnsiString;
overload; inline;
function AnsiUpperCase(const S: AnsiString):
AnsiString; overload;
// in WideStrUtils
function UTF8UpperCase(const S: UTF8string): UTF8string;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 121
Se convertirá en:
GetProcAddress (hmodule, PAnsiChar (
AnsiString(strFnName)));
begin
aString := 'My ten Euros (10€)';
try
fileStream1 := TFileStream.Create(
GetStdHandle(STD_OUTPUT_HANDLE));
textWriter1 := TStreamWriter.Create (
fileStream1, TEncoding.Unicode);
try
textWriter1.Write (aString);
finally
textWriter1.Free;
fileStream1.Free;
end;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
end.
PChar y el Puntero
Matemático
El tipo PChar en Delphi ha sido tradicionalmente utilizado en
dos escenarios totalmente diferentes. El primero es la gestión
de cadenas de caracteres de un modo compatible con el len-
guaje C y la API de Windows. El segundo es para sustituir un
puntero de tipo genérico, porque PChar era el único tipo de
puntero con soporte a punteros matemáticos. Por ejemplo,
puede moverse al siguiente carácter de una cadena escri-
biendo uno de los siguientes métodos:
La guía de Delphi por Marco Cantù
124 - Indice
var
pCh1: PChar;
begin
...
pCh1 := PChar1 + 1;
Inc (PChar1);
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 125
De PChar a PByte
Si este problema es potencialmente problemático, al menos
para una secuencia de código de bajo nivel, la solución está al
alcance de la mano. En el código anterior, usted puede sim-
plemente sustituir la versión-específica del tipo PChar por la
PInteger y la Directiva
POINTERMATH
Sin embargo, como estamos tratando con números enteros,
¿no sería mejor escribir código como este (cambiando al in-
cremento a uno y pasando del modelado del código original)?
procedure TFormPointerMath.btnPIntegerClick (
Sender: TObject);
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 127
var
TenIntegers: array [1..10] of Integer;
pOneInteger: PInteger;
I: Integer;
begin
// escribir
for I := 1 to 10 do
TenIntegers [I] := I;
Una vez más, esto ha sido posible usando una llamada Inc in-
cluso en Delphi 2007 (y que el ejemplo PointerMathD2007
pueda abrirse con esta versión del IDE, lo demuestra), pero
en Delphi 2009 usted puede compilar el código anterior aña-
diendo al código fuente la directiva:
{$POINTERMATH ON}
Parámetros Variants y
Open Arrays
Cuando esté trabajando con variants, la mayoría del código de
conversión de variants a cadenas funcionará tal como cabe es-
perar, ya que hay un nuevo tipo de variant:
varUString = $0102;
{ Unicode string 258 } {not OLE compatible}
Todas las conversiones basadas en variants deberían trabajar
correctamente, sin muchas diferencias con su código variant
relacionado, a menos que tenga que interactuar con COM o
automatización OLE, en cuyo caso todavía tiene que utilizar el
tipo WideString (al igual que antes, esto no cambia).
Cuando trabaje con parámetros variant open array, y otras es-
tructuras de datos sin tipificar, las opciones AnsiString y Uni-
codeString deben ser manipuladas específicamente. Por ejem-
plo, la estructura TVarRec tiene ahora tres entradas distintas
relacionadas con la cadena (solían ser dos), entre muchos
otros tipos que he omitido:
type
TVarRec = record
case Byte of
vtString: (VString: PShortString);
vtAnsiString: (VAnsiString: Pointer);
vtUnicodeString: (VUnicodeString: Pointer);
...
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 129
A continuación
Acabamos de finalizar la cobertura al soporte de Unicode en
Delphi 2009. A continuación, en la Parte II voy a tratar en
profundidad los cambios en el IDE, el compilador y la RTL.
En la sección RTL volveremos a estudiar las funciones de ges-
tión de cadenas. Y más adelante, en la parte del libro dedicada
a bases de datos, cubriré la forma en que los cambios introdu-
cidos por el soporte Unicode afectan a la clase TDataSet y sus
clases relacionadas.
Apartado II:
Delphi 2009 y
Su Compilador
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 131
Capítulo 4:
Nuevas
Características
del IDE
Instalación y Ejecución
Como en Delphi 2007, la instalación de Delphi 2009 está ba-
sada en InstallAware. Esta vez, sin embargo, la experiencia de
instalacion ha sido mejorada considerablemente, especial-
mente su velocidad. En Delphi 2009 se puede completar la
instalación en 20 minutos en lugar de varias horas. La instala-
ción de la actualización 1 del producto (lanzado a finales de
Octubre de 2009) es igualmente fácil.
Un cambio notable en este sentido, es el hecho de que la
ayuda es ahora una instalación separada, por lo que se puede
actualizar con más frecuencia y por separado del producto
principal (de este modo, no tiene que volver a reinstalar Del-
phi cuando actualice la ayuda, ni tampoco tiene que reinstalar
la ayuda en el caso de que desee volver a instalar el IDE). La
instalación de la ayuda puede tomarse más tiempo que la ins-
talación del producto ya que la imagen de la ayuda es más
grande que la misma del IDE.
Cuando se instala en Windows Vista, tendrá (por defecto) el
producto instalado en las siguientes carpetas:
C:\Program Files\CodeGear\RAD Studio\6.0
C:\Users\Public\Documents\RAD Studio\6.0\Demos\
C:\Program Files\Common Files\CodeGear Shared
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 133
63El SDK .NET se requiere para el Explorador de Documentos, hasta que Micro-
soft tenga disponible un instalador independiente para la ayuda. Otras par-
tes de la arquitectura .NET utilizadas por el IDE de Delphi, incluyendo el
motor de MSBuild, son parte del Standard runtime, no del SDK.
El Flag -idecaption
Usted probablemente sabe (aunque esto era un secreto bien
guardado durante muchos años64) que puede ejecutar varias
instancias del IDE, al mismo tiempo, con diferentes configu-
raciones de registro utilizando el comando en línea –R.
El problema está, en que si usted ejecuta dos versiones dife-
rentes del IDE a la vez, es muy difícil saber cuál es cuál. Otro
parámetro en la línea de comandos para el IDE es -idecap-
tion, que toma un título como valor. Sumando estos dos co-
mandos en línea se pueden ejecutar el IDE con el siguiente
enlace:
"C:\Program Files\CodeGear\RAD Studio\6.0\bin\bds.exe" -
pDelphi -rSmall -idecaption="Small Tiburòn"
Gestión de Proyectos en
Delphi
La gestión de los proyectos es una operación muy habitual. Si
Delphi 2007 añadió algunos conceptos totalmente nuevos,
como el soporte de MSBuild los parámetros de construcción
(Depuración y Liberación) y eventos para situaciones de pre-
construcción y post-construcción, la nueva versión hace que
estas características sean más flexibles y mucho más fáciles de
usar, a partir de una importante modernización del Project
Manager en si mismo. Antes de mirar el Project Manager, sin
embargo, tenemos que mirar la mejora de los archivos de pro-
yecto y la renovada caja de diálogo de Opciones de Proyecto.
65Como puede haber oído, Tiburón fue el nombre en clave de Delphi 2009.
Actualizando
Desde los primeros días de Delphi, el fichero de código fuente
del proyecto (con la extensión .DPR) contiene el código Object
Pascal y utiliza una o más configuraciones separadas de pro-
yecto para almacenar otros ajustes. El formato y la extensión
del archivo de configuración de proyecto ha cambiado varias
veces en las últimas versiones, pasando de un archivo INI a
un archivo XML y, a continuación, a un archivo XML de (el
formato de fichero ).
Desde Delphi 2007 a Delphi 2009, el formato general de este
proyecto de configuración de archivo no cambia. Pero su con-
tenido es diferente, y Delphi 2007 no reconoce las opciones
añadidas por la versión más reciente del IDE. Al abrir un pro-
yecto existente de Delphi 2007, el IDE de Delphi 2009 le pe-
dirá el nombre de un archivo de copia de seguridad en donde
pueda copiar la versión del proyecto de archivo de configura-
ción:
<BuildConfiguration Include="Release">
<Key>Cfg_Release</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Debug">
<Key>Cfg_Debug</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
</ItemGroup>
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 139
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 141
Ubicación Predeterminada de
Proyectos
Desde Delphi 2005, la ubicación por defecto para todos los
proyectos nuevos es la carpeta de documentos del usuario.
Pocos desarrolladores de Delphi saben que esto puede modifi-
carse estableciendo un valor por defecto para el proyecto me-
diante el cuadro de edición en Environment Options page of
the Tools | Options dialog box.
El Project Manager
Junto con un rediseño del cuadro de diálogo de Opciones de
Proyecto (que todavía no he cubierto totalmente al examinar
las nuevas características de configuración) Delphi 2009
muestra una importante actualización del panel Project Ma-
nager, uno de los paneles más comúnmente utilizado del IDE.
Incluso con una mirada superficial a su ventana se revelan al-
gunas de sus nuevas características:
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 145
tas):
Directory (Flat) es una nueva visión en la que los archivos
están todavía divididos por directorios pero cada directorio
diferente es parte de un lista plana, independientemente de su
archivos:
Construcción de Configuraciones
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 147
y Opciones de Configuración
Como he dicho antes y se puede ver en las imágenes de las pá-
ginas anteriores, el Proyect Manager cuenta con un nuevo
nodo de construcción de configuraciones para cada proyecto
(es decir, para los casos en que usted este trabajando con un
grupo de proyecto con múltiples proyectos activos). Este nodo
sustituye a la engorrosa separación de ventana utilizada para
la gestión de la configuración en Delphi 2007. Usando el nodo
y sus sub-nodos puede cambiar la configuración de la cons-
trucción en la que esté trabajando con un doble clic, y actuali-
zar la construcción directamente en el nodo dado.
Al seleccionar una determinada configuración en el nodo
principal, puede añadir también una nueva configuración. De-
pendiendo del origen del objeto seleccionado cuando realiza
la operación, usted creará una configuración principal o una
sub-configuración. Para ser más preciso, el nodo que elija de-
termina la configuración base, desde incluso las configuracio-
nes básicas predefinidas heredando sus principales ajustes de
la configuración Base (que es el núcleo a partir del cual here-
dan la configuración de Debug y Release). ¿Qué quiero decir
con "heredar opciones" de una configuración? Delphi 2009
dispone de un nuevo sistema de gestión de configuración, en
el que se puede aplicar un ajuste para una configuración espe-
cífica (como de Debug y Release) o configurar una opción
para las dos configuraciones, pero no que no se especifica,
sino que hereda estas de la configuración Base. En una confi-
guración específica puede ver su valor específico y el que he-
reda de la configuración base en dos líneas consecutivas, ver
si realizan su tarea y cambiarlas, ya sea una o la otra (afec-
tando también a la configuración específica). Esto se consigue
al expandir cada opción de configuración seleccionando el
signo más a la izquierda del nodo. Esto es lo que usted puede
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 149
Administrador de Configuración
de Proyecto
Con el constructor de opciones disponible directamente en el
panel del Project Manager, usted no tiene porque utilizar el
Configuration Manager para cambiar la actual estructura de
configuración. Sin embargo, este cuadro de diálogo es muy
útil ya que le permite cambiar la estructura de la configura-
ción para muchos proyectos, de un grupo de proyectos, al
mismo tiempo. De hecho, el Configuration Manager también
está disponible en Delphi 2009, y en una versión muy mejo-
rada lo que le permite administrar varias estructuras de confi-
guración diferentes y determinar un conjunto de opciones
para todos los proyectos de un grupo a la vez.
Para invocar el Configuration Manager no utilice el menú
emergente del Project Manager, como en Delphi 2007, sino
que seleccione el elemento correspondiente en el menú Pro-
ject del IDE. Cuando lo haga, obtendrá esta rediseñada inter-
faz de usuario:
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 151
Gestión de Recursos en el
IDE
En las últimas versiones de Delphi, se pueden añadir scripts
de recursos (ficheros.RC) o archivos de recursos precompila-
dos (ficheros .RES) al Project Manager para dejar que se com-
pilen junto con el proyecto y se unan al ejecutable. En Delphi
2009 la gestión de los recursos se ha simplificado con la inclu-
sión de algunas herramientas más.
En primer lugar, ahora puede arrastrar los archivos de recur-
sos hasta el Project Manager para conseguir que los recursos
se incluyan en un proyecto. Puede arrastrar los iconos, mapas
de bits, y mucho más. Delphi generará un archivo de secuen-
cia de comandos de recursos adicionales para estos recursos
de proyecto, y lo compilan directamente junto con su pro-
grama, embebiendo estos recursos en el ejecutable. Puede
cambiar cualquier atributo de estos archivos de recursos (in-
cluyendo su nombre interno) en el Object Inspector:
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 153
{$R *.dres}
uses
Forms,
ResourceTest_MainForm in
'ResourceTest_MainForm.pas' {FormResourceTest};
{$R *.res}
begin
Application.Initialize;
...
Creating ResourceTest.dres
Using codepage 65001 as default
ResourceTestResource.rc.
procedure TFormResourceTest.btnIconClick(
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 155
Sender: TObject);
begin
Icon.LoadFromResourceName(hInstance, 'Icon_Factory');
Application.Icon.LoadFromResourceName(
hInstance, 'Icon_Factory');
end;
Un "Nuevo"
Las recientes versiones de Delphi, hasta incluso Delphi 2007,
han utilizado el Compilador de Recursos de Borland
(BRCC32.EXE) un anticuado programa cuyos derechos de autor
muestran en su nota ya histórica:
Copyright (c) 1990, 1999 Inprise Corporation. Reservados
todos los derechos.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 157
La Clase
Un nuevo panel en Delphi 2009 es el nuevo panel Explorador
de Clases (disponible en la opción Delphi Class Explorer del
menú View). El Delphi Class Explorer ofrece una amplia re-
presentación de los símbolos del proyecto, diferente a la op-
ción Structure View68, que muestra una (o algo similar) repre-
sentación gráfica de los elementos de una sola unidad.
En el Explorador de Clase de Delphi en el primer nivel, verá
una lista de nodos alojando la definición global de cada uni-
dad (más el archivo de proyecto), mientras los nodos restan-
tes muestran todas las clases definidas en el proyecto:
Otras nuevas
características
La actualización del diálogo de Opciones de Proyecto, las nue-
vas características de Project Manager y la ampliación de la
estructura de configuraciones, el mejor soporte para recursos,
y el Explorador de Clases son probablemente las nuevas ca-
racterísticas más relevantes del IDE de Delphi 2009, si no
pero con otra interfaz de usuario que hace que sea más evi-
dente para todos los usuarios que se pueden buscar en la lista
de componentes escribiendo:
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 161
Actualización de Asistentes de
Componentes
Los cuadros de diálogo utilizados para crear un nuevo compo-
nente VCL o para importar un componente (un control Acti-
veX o un ensamblado .NET, para ser utilizados como un con-
trol COM) se han mejorado y se convertido en asistentes con
múltiples-pasos.
La capacidad real de crear el esqueleto de un componente va-
cío o un embalaje de un control externo, no se ha modificado
significativamente. La única característica realmente nueva es
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 163
Depurador
Como el resto del IDE, el depurador se ha trabajado también
para soportar Unicode plenamente. Este soporte estaba par-
cialmente disponible en versiones anteriores, pero en Delphi
2009 se extiende. Por ejemplo, si usted quiere inspeccionar
una variable de cadena con Run | Inspect (o Debug | Inspect
en el menú local del editor) no sólo va a obtener el valor co-
rrecto de Unicode, además le informará, en la parte inferior,
del tipo verdadero de variable de esta cadena.
A continuación se puede ver, en el Debug Inspector, una com-
paración entre un AnsiString y un UnicodeString (reportado
este como string):
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 165
69Un artículo técnico de MSDN que describe Wait Chain Transversal a nivel sis-
tema operativo está disponible en http://msdn.microsoft.com/en-us/li-
brary/ms681622.aspx. Chris Hesik de Embarcadero trata en su blog esta
nueva característica del depurador en Delphi http://blogs.code-
gear.com/chrishesik/2008/07/21/34833.
Depuración y Nuevas
Características del Lenguaje
Aunque el depurador parezca muy similar a la versión ante-
rior, se ha dedicado gran cantidad de esfuerzo para permitir
que los usuarios puedan depurar aplicaciones que utilizan ge-
néricos y métodos anónimos. Debido a la sofisticada genera-
ción de código que se realiza en segundo plano, el código que
está depurando es bastante diferente del que escribió original-
mente. Aún con algunos problemas, la depuración de las nue-
vas características del lenguaje, en general, funciona bastante
bien.
A continuación
Habiendo examinado las nuevas características del IDE de
Delphi 2009, ahora puedo volver al lenguaje. Ya hemos visto
que hay muchas características nuevas relacionadas con el so-
porte de UnicodeString y AnsiString, pero el compilador tiene
muchas mejoras más.
Con los genéricos y lo métodos anónimos (o closures) que
aparecen por primera vez en el lenguaje, Object Pascal da su
salto más importante hacia adelante desde la aparición de
Delphi. Es por eso que hay dos capítulos completos, y algo
más de información en un tercero, plenamente dedicado a la
compilación y el lenguaje.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 167
Capítulo 5 :
Genéricos
70El libro es "Borland C++ 4.0 Programación Orientada a Objetos", escrito por
mí y Steve Tendon, con una presentación de Philippe Kahn.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 169
// Button1Click
kv.Key := 'mykey';
kv.Value := Sender;
// Button2Click
kv.Value := self; // the form
// Button3Click
ShowMessage('[' + kv.Key +',' + kv.Value.ClassName + ']');
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 171
// FormCreate
kv := TKeyValue<TButton>.Create;
// Button1Click
kv.Key := 'mykey';
kv.Value := Sender as TButton;
// Button2Click
kv.Value := Sender as TButton; // was "self"
// Button3Click
ShowMessage ('[' + kv.Key + ',' + kv.Value.Name + ']');
begin
kvi := TKeyValue<Integer>.Create;
try
kvi.Key := 'object';
kvi.Value := 100;
kvi.Value := Left;
ShowMessage ('[' + kvi.Key + ',' +
IntToStr (kvi.Value) + ']');
finally
kvi.Free;
end;
var
sg1: TSimpleGeneric<string>;
sg2: TSimpleGeneric<Integer>;
begin
sg1 := TSimpleGeneric<string>.Create;
sg2 := TSimpleGeneric<Integer>.Create;
sg1.Value := 'foo';
sg1.Value := 10; // Error
// E2010 Incompatible types: 'string' and 'Integer'
sg2.Value := 'foo'; // Error
// E2010 Incompatible types: 'Integer' and 'string'
sg2.Value := 10;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 173
Genéricos en Delphi
En el ejemplo anterior hemos visto como puede definir y utili-
zar una clase genérica en Delphi, una de la ampliaciones de
mayor alcance del lenguaje Object Pascal desde que Delphi 3
introdujo las interfaces. Me decidí a presentar esta caracterís-
tica con un ejemplo, antes de profundizar en los aspectos téc-
nicos, que son bastante complejos y muy importantes al
mismo tiempo. Después de cubrir los genéricos desde la pers-
pectiva del lenguaje, volveremos con más ejemplos, inclu-
yendo el uso y la definición del contenedor genérico de clases,
una de las principales razones por la que estas técnicas se han
añadido al lenguaje.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 175
begin
array1 := array2;
array2 := array3; // Error
// E2010 Incompatible types: 'TArrayOf10' and 'Array'
array3 := array4;
array4 := array1; // Error
// E2010 Incompatible types: 'Array' and 'TArrayOf10'
end;
TIntGenericArray = TGenericArray<Integer>;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 177
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 179
end;
function TSampleClass<T>.ReadT: T;
begin
Result := data;
end;
t2 := TSampleClass<string>.Create;
t2.SetT ('hello');
t2.One;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 181
procedure TSampleClass<T>.Zero;
begin
73Estamemoria sin inicializar tiene el mismo valor de una variable global del
mismo tipo. A diferencia de las variables locales, ya que de hecho, las varia-
bles globales se inicializan a “cero” por el compilador.
t2 := TSampleClass<string>.Create;
...
Log ('data: ' + t2.data);
t3 := TSampleClass<double>.Create;
...
Log ('data: ' + FloatToStr (t3.data));
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 183
data: 0
type: Double
size: 8
s := Default (string);
Log ('Default String': + s);
Restricciones Genéricas
Como hemos visto, es muy poco lo que usted puede hacer en
los métodos de su clase genérica sobre el valor de tipo gené-
rico. Puede pasar alrededor (es decir, asignarlo) y realizar las
operaciones limitadas permitidas por el tipo de funciones ge-
néricas tal como acabo de describir.
74Nose puede aplicar la llamada TypeInfo a una variable, como en el código an-
terior TypeInfo(s) sino sólo a un tipo.
Restricciones de clase
La restricción más simple que puede adoptar es la limitación
de clase. Para usarla, usted puede declarar un tipo genérico
como:
type
TSampleClass <T: class> = class
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 185
Restricciones Específicas de
Clase
Si su clase genérica necesita trabajar con un subconjunto es-
pecífico de clases (una jerarquía especifica), es posible que
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 187
Restricciones de interfaz
En lugar de una clase genérica restringida a una clase deter-
minada, es más flexible en general, aceptar como parámetro
de tipo sólo clases implementadas por una interfaz determi-
nada. Esto hace posible llamar a una interfaz con instancias
de tipo genérico. Este empleo de restricciones de interfaz para
genéricos es también muy común en el entorno .NET. Permí-
tanme empezar por mostrar un ejemplo (llamado ). En primer
lugar, necesitamos declarar una interfaz:
type
IGetValue = interface
['{60700EC4-2CDA-4CD1-A1A2-07973D9D2444}']
function GetValue: Integer;
procedure SetValue (Value: Integer);
property Value: Integer
read GetValue write SetValue;
end;
procedure TInftClass<T>.IncreaseByTen;
begin
val1.SetValue (val1.GetValue + 10);
val2.Value := val2.Value + 10;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 189
procedure TFormIntfConstraint.btnValueClick(
Sender: TObject);
var
iClass: TInftClass<TGetValue>;
begin
iClass := TInftClass<TGetValue>.Create;
try
iClass.Set1 (TGetValue.Create (5));
iClass.Set2 (TGetValue.Create (25));
Log ('Average: ' + IntToStr (iClass.GetAverage));
iClass.IncreaseByTen;
Log ('Min: ' + IntToStr (iClass.GetMin));
finally
iClass.val1.Free;
iClass.val2.Free;
iClass.Free;
end;
end;
self, ScrollBox1));
iClass.Set2 (TButtonValue.MakeTButtonValue (
self, ScrollBox1));
Log ('Average: ' + IntToStr (iClass.GetAverage));
Log ('Min: ' + IntToStr (iClass.GetMin));
iClass.IncreaseByTen;
Log ('New Average: ' + IntToStr (iClass.GetAverage));
finally
iClass.Free;
end;
end;
type
TPlainInftClass = class
private
val1, val2: IGetValue;
public
procedure Set1 (val: IGetValue);
procedure Set2 (val: IGetValue);
function GetMin: Integer;
function GetAverage: Integer;
procedure IncreaseByTen;
end;
¿Cómo podemos usar esta clase genérica, y cuáles son las re-
glas? En los próximos ejemplos, he definido dos clases, una
con un constructor predeterminado (sin-parámetros), la se-
gunda con un único constructor que tiene un parámetro:
type
TSimpleConst = class
public
Value: Integer;
constructor Create; // set Value to 10
end;
TParamConst = class
public
Value: Integer;
constructor Create (I: Integer); // set Value to I
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 193
end;
paramCostObj := TConstrClass<TParamCost>.Create;
Log ('Value 2: ' + IntToStr (paramCostObj.Get.Value));
Genéricas y Su Combinación
Como hay tantas restricciones diferentes que usted puede im-
poner a un tipo genérico, permítame que provea un breve re-
sumen, en términos de código:
type
TSampleClass <T: class> = class
TSampleRec <T: record> = class
TCompClass <T: TButton> = class
TInftClass <T: IGetValue> = class
TConstrClass <T: constructor> = class
Contenedores Genéricos
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 195
Predefinidos
Desde los primeros días de las plantillas en el lenguaje C++,
uno de los usos más evidentes de las clases genéricas ha sido
la definición de los contenedores genéricos o listas. Cuando se
define una lista de objetos, como la propia de Delphi: TObje-
ctList, de hecho, usted tiene una lista que potencialmente
puede contener objetos de cualquier tipo. Usando la herencia
o la composición, usted de verdad puede definir contenedores
a medida para especificar un tipo, pero este es un enfoque78
tedioso (y potencialmente propenso a errores).
Delphi 2009 define un pequeño conjunto de contenedores de
clases genéricas que se pueden encontrar en la nueva unidad
Generics.Collections. Las cuatro clases principales de conte-
nedor están todas implementadas de forma independiente
(no existe herencia entre estas clases), todas implementadas
de forma similar (utilizando una matriz dinámica), y estando
todas mapeadas a los correspondientes contenedores de clase
no-genéricos de la unidad Contnrs:
type
TList<T> = class
TQueue<T> = class
TStack<T> = class
TDictionary<TKey,TValue> = class
78Aquíno quiero cubrir la diferencia entre los diversos enfoques que usted po-
dría utilizar en Delphi para definir contenedores especializados antes que ge-
néricos disponibles, porque ahora estamos con los genéricos. Usted puede
encontrar material ampliado en mi libro Mastering Delphi 7 (Sybex) y en
otras ediciones de esa serie.
Usando TList<T>
El programa, llamado ListDemoMd2005, tiene una unidad
que define una clase TDate, y el formulario principal utilizaba
para referirlos un TList de fechas. Como punto de partida, he
añadido la cláusula uses que hace referencia a Generics.Colle-
ctions, y he cambiado la declaración del campo en el formula-
rio principal a:
private
ListDate: TList <TDate>;
79El programa solamente utiliza unos pocos métodos, aunque esto no es una
gran prueba para la compatibilidad de interfaz entre las listas de genéricos y
no genéricos, pero decidí que valía la pena coger un programa existente en
lugar de hacer uno nuevo.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 197
end;
Ordenando un TList<T>
Lo que es interesante es entender cómo funciona la ordena-
ción (mi objetivo aquí es añadir la capacidad de ordenación al
ejemplo ListDemoMd2005). El método Sort se define así:
procedure Sort; overload;
procedure Sort(const AComparer: IComparer<T>); overload;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 199
82Lesugiero que eche un vistazo a esta sección incluso si usted no sabe mucho
sobre los métodos anónimos, y luego volver a leerlo de nuevo después de
profundizar en el siguiente capítulo.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 201
Result := 0
else if lDate < rDate then
Result := -1
else
Result := 1;
end));
end;
Contenedores de Objetos
Además de las clases genéricas cubiertas al principio de este
apartado, hay también cuatro clases genéricas heredadas que
se derivan de las clases base definidas en la unidad Gene-
rics.Collections, imitando a las clases existentes de la unidad
Contnrs:
type
TObjectList<T: class> = class(TList<T>)
TObjectQueue<T: class> = class(TQueue<T>)
TObjectStack<T: class> = class(TStack<T>)
84Dictionaryen este caso significa una colección de elementos cada uno con un
valor (único) clave refiriéndose a estos. (También se conoce como una matriz
asociativa). En un diccionario clásico usted tiene palabras que actúan como
clave de sus definiciones, pero en términos de programación la clave no
tiene que ser una cadena (incluso si esto es un caso bastante frecuente).
TCustomer = class
private
..
procedure Init;
procedure EnforceInit;
public
constructor Create (aCustKey: TCustomerKey);
property CustKey: TCustomerKey
read FCustKey write SetCustKey;
published
property CustNo: Double
read GetCustNo write SetCustNo;
property Company: string
read GetCompany write SetCompany;
property Addr1: string
read GetAddr1 write SetAddr1;
property City: string
read GetCity write SetCity;
property State: string
read GetState write SetState;
property Zip: string
read GetZip write SetZip;
property Country: string
read GetCountry write SetCountry;
property Phone: string
read GetPhone write SetPhone;
property FAX: string
read GetFAX write SetFAX;
property Contact: string
read GetContact write SetContact;
class var
RefDataSet: TDataSet;
end;
procedure TCustomer.Init;
begin
RefDataSet.Locate('custno', CustKey.CustNo, []);
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 207
begin
listItem := ListView1.Items.Add;
listItem.Caption := custkey.Company;
listItem.SubItems.Add(FloatTOStr (custkey.CustNo));
listItem.Data := custkey;
end;
end;
Interfaces Genéricas
En la sección “Ordenando un TList<T>” puede ser que usted
haya notado algo extraño el uso de una interfaz predefinida,
que tenía una declaración genérica. Vale la pena ahondar al
detalle en esta técnica, ya que abre importantes oportunida-
des y cambios (aunque moderados) en la forma en que los in-
terfaces trabajan en el lenguaje.
86Esta
es la versión genérica de la interfaz IGetValue del ejemplo IntfContraints
cubierto en el apartado anterior “Restricciones de Interfaz” de este capítulo.
En ese caso, el interfaz tenía un valor entero, ahora es de carácter genérico.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 209
begin
aVal := TGetValue<string>.Create (Caption);
try
Log ('TGetValue value: ' + aVal.GetValue);
finally
aVal.Free;
end;
end;
Interfaces Genéricos
Predefinidos
Ahora que hemos explorado como definir interfaces genéricas
y combinarlas con el uso de genéricos y clases específicas, po-
demos volver a dar un segundo vistazo a la unidad Gene-
rics.Default. Esta unidad define dos interfaces genéricas de
comparación:
IComparer<T> tiene un método Compare
IEqualityComparer<T> tiene los métodos Equals y
GetHashCode
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 211
Punteros inteligentes en
87El termino singleton es generalmente utilizado para definir una clase de la que
sólo se puede crear una instancia, y no una sin recuento de referencia. Con-
sidero que se trata de un término inapropiado.
Delphi
Al aproximarse a los genéricos, se puede llevar una primera
impresión falsa de que este lenguaje de construcción se usa
principalmente para las colecciones. Si bien este es el caso
más sencillo para el uso de clases genéricas, y muy a menudo
el primer ejemplo en los libros y documentos, los genéricos
son muy útiles más allá de la esfera de clases de colecciones (o
contenedores). En el último ejemplo de este capítulo voy a
mostrarle una colección de tipo no-genérica, que es la defini-
ción de un puntero inteligente.
Si usted viene de una formación estrictamente de Delphi, es
posible que no haya oído hablar de punteros inteligentes, una
idea que proviene del lenguaje C++. En C++ usted puede te-
ner punteros a objetos, con lo cual usted tiene que gestionar la
memoria directamente y manualmente, y las variables locales
del objeto son gestionadas de forma automática, pero tienen
muchas otras limitaciones (como la falta de polimorfismo88).
La idea de los punteros inteligentes es usar un objeto admi-
nistrado localmente para cuidar de la vida del puntero del ob-
jeto real que desea utilizar. Si esto le parece demasiado com-
plicado, espero que la versión de Delphi (y su código) le ayude
a aclararlos.
En Delphi los objetos son administrados por referencia, sin
embargo los registros tienen una vida útil vinculada con el
método en que se hayan declarado. Cuando el método fina-
liza, la zona de memoria para el registro se limpia. Así que lo
88El término polimorfismos en los lenguajes POO se utiliza para indicar la situa-
ción en la que se asigna a una variable de una clase base un objeto de una
clase derivada y llama a uno de los métodos virtuales de la clase base, poten-
cialmente acaba llamando la versión del método virtual de la subclase espe-
cífica.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 213
constructor TFreeTheValue.Create(
anObjectToFree: TObject);
begin
fObjectToFree := anObjectToFree;
end;
destructor TFreeTheValue.Destroy;
begin
fObjectToFree.Free;
inherited;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 215
strict private
FValue: T;
FFreeTheValue: IInterface;
function GetValue: T;
public
constructor Create(AValue: T); overload;
property Value: T read GetValue;
end;
90Enla práctica, los bloques implícitos try-finally se añaden en todos los lu-
gares por dónde el compilador maneja la interfaz dentro del registro, pero no
tenemos que escribirlo (y el compilador es menos probable que se olvide).
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 217
var
smartP: TSmartPointer<TStringList>;
begin
smartP := TStringList.Create;
TStringList(smartP).Add('foo2');
function TSmartPointer<T>.GetValue: T;
begin
if not Assigned(FFreeTheValue) then
Create;
Result := FValue;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 219
A continuación
Después de cubrir los cambios en el tipo de cadena, en este
capítulo hemos empezado a explorar otra importante y nueva
característica del compilador de Delphi 2009, el soporte de
los tipos genéricos. Incluso si el capítulo que estamos aca-
bando es bastante largo, solamente hemos empezado a arañar
la superficie de lo que puede considerarse un nuevo para-
digma de programación para los desarrolladores Delphi.
Pero hay más: los métodos anónimos, tratados en el siguiente
capítulo, nos proporcionan otro cambio de paradigma, y se
pueden utilizar junto con los genéricos como ya he anticipado
en este capítulo. Tienen un papel muy útil en aplicaciones
multi-hilo y en muchos otros casos, como veremos en el pró-
ximo capítulo. Ciertamente Delphi 2009 no es una actualiza-
ción aburrida para aquellos que son, como yo, unos apasiona-
dos por los lenguajes de programación en general y del len-
guaje Object Pascal en particular.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 221
Capítulo 6:
Métodos
Anónimos
91Enel caso de que quiera obtener más información sobre los tipos de procedi-
miento esta se recoge en el capítulo 6 de “Essential Pascal”, 4ª edición; los
tipos de punteros a método se describen en los libros de mi serie Mastering
Delphi.
Sintaxis y Semántica de
los Métodos Anónimos
Un método anónimo en Delphi es un mecanismo para crear
un valor de método en un contexto93. Una definición bastante
críptica, pero que resume con mucha precisión y subraya la
diferencia clave con los punteros a métodos, el contexto de ex-
presión. Antes de llegar a este, sin embargo, permítanme que
empiece desde el principio con un sencillo ejemplo de código
(incluido en el proyecto AnonymFirst junto con la mayoría de
los demás de esta sección).
Esta es la declaración de un tipo de método anónimo, algo que
usted necesita ya que Delphi sigue siendo un lenguaje fuerte-
mente tipado:
type
TIntProc = reference to procedure (n: Integer);
93Enlas palabras del implementador de los métodos anónimos Barry Kelly del
I+D de Embarcadero, http://barrkel.blogspot.com.
Sender: TObject);
var
anIntProc: TIntProc;
begin
anIntProc :=
procedure (n: Integer)
begin
Memo1.Lines.Add (IntToStr (n));
end;
anIntProc (22);
end;
Un Parámetro de Método
Anónimo
Como un ejemplo más interesante (con una sintaxis aún más
sorprendente), podemos enviar un método anónimo como pa-
rámetro a una función. Suponga que tiene una función to-
mando un método anónimo como parámetro:
procedure CallTwice (value: Integer;
anIntProc: TIntProc);
begin
anIntProc (value);
Inc (value);
anIntProc (value);
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 225
94Unos pocos detalles técnicos más, los métodos anónimos copian las variables y
los parámetros que utilizan para el almacenamiento dinámico cuando se
crean, y los mantienen vivos, mientras dure la instancia específica de este
método anónimo.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 227
Ahora presione Store una vez más y pulse Call de nuevo. ¿Qué
es lo que pasa, cuál es el valor de la variable local restaurada?
Mediante la asignación de una nueva instancia del método
anónimo, el viejo método anónimo se suprime (junto con su
propio contexto de ejecución) y un nuevo contexto de ejecu-
ción es capturado, incluyendo una nueva instancia de la varia-
ble local. La secuencia completa Store - Call - Call – Store-
Call produce:
5
8
10
13
5
8
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 229
El (Potencialmente) Paréntesis
Perdido
Observe como en el código anterior he utilizado el símbolo
AnonMeth para referirme al método anónimo, y no para invo-
carlo. Para invocarlo, debería haber escrito:
AnonMeth (2)
x: Integer;
begin
x := Random (100);
ShowMessage ('New x is ' + IntToStr (x));
Result :=
procedure (n: Integer)
begin
x := x + n;
ShowMessage (IntToStr (x));
end;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 231
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 233
Métodos Anónimos en el
Mundo Real
A primera vista, no es fácil de comprender plenamente el po-
der de los métodos anónimos y los escenarios que su uso
puede beneficiarnos. Esa es la razón por la que, en lugar de
seguir con más enrevesados ejemplos que abarquen el len-
guaje, decidí centrarme en algunos que tienen un impacto
práctico y proporcionan puntos de partida para una explora-
ción más profunda.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 235
// interceptor class
TButton = class (StdCtrls.TButton)
private
FAnonClick: TAnonNotif;
procedure SetAnonClick(const Value: TAnonNotif);
public
procedure Click; override;
public
property AnonClick: TAnonNotif
read FAnonClick write SetAnonClick;
end;
El código de esta clase es bastante simple, ya que el método
Setter guarda el nuevo puntero, y el método Click lo llama an-
tes de hacer el procesamiento estándar (es decir, llamando al
gestor del evento OnClick si este está disponible):
procedure TButton.SetAnonClick(const Value: TAnonNotif);
begin
FAnonClick := Value;
end;
procedure TButton.Click;
begin
if Assigned (FAnonClick) then
FAnonClick (self)
97Uninterceptor de clase es una clase derivada que tiene el mismo nombre que
su clase base. Que haya dos clases con el mismo nombre es posible porque
están en diferentes unidades, por lo que su nombre completo (Nombre-
DeUnidad.NombreDeClase) es diferente. Declarar un interceptor de clase
puede ser útil, así puede colocar simplemente un botón en el formulario y
adjuntarle un comportamiento adicional, sin tener que instalar un nuevo
componente en el IDE y reemplazar los controles de su formulario con el
nuevo tipo. El único truco que tiene que recordar es que si la definición del
interceptor de clase se encuentra en una unidad independiente (no la unidad
del formulario como en este ejemplo), esta unidad tiene que estar inscrita en
los estamentos de uses después de haber definido la unidad de la clase base.
inherited;
end;
¿Cómo puede usar este nuevo manipulador de eventos? Bási-
camente puede asignarle un método anónimo
procedure TFormAnonButton.btnAssignClick(
Sender: TObject);
begin
btnInvoke.AnonClick :=
procedure (Sender: TObject)
begin
ShowMessage ((Sender as TButton).Caption);
end;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 237
Cronometraje de Métodos
Anónimos
Con frecuencia los desarrolladores añaden código a las rutinas
existentes para comparar su velocidad relativa. Hice lo mismo
varias veces en los ejemplos de la Parte I del libro, para averi-
guar la velocidad de las cadenas Unicode. Suponiendo que
tiene dos fragmentos de código y que desea comparar su velo-
cidad ejecutando estas unos pocos millones de veces, usted
podría escribir lo siguiente (tomado del ejemplo StringCon-
vert del capítulo 2 y comentado en la sección “Conversión de
Cadenas”):
procedure TFormAnonTiming.btnClassicClick(
Sender: TObject);
var
str1: string;
str2: AnsiString;
I: Integer;
t1: TDateTime;
begin
str1 := 'Marco Cantù';
t1 := Now;
for I := 1 to MaxLoop2 do
str1 := AnsiUpperCase (str1);
t1 := now - t1;
Memo1.Lines.Add ('AnsiUpperCase (string): ' +
FormatDateTime('nn:ss.zzz', t1));
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 239
procedure TFindWebThread.ShowStatus;
begin
Form1.StatusBar1.SimpleText := Status;
end;
TThread = class
...
procedure Synchronize(
AMethod: TThreadMethod); overload;
procedure Synchronize(
AThreadProc: TThreadProcedure); overload;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 243
strRead: string;
end;
// pasar
nBegin := PosEx ('>', strRead, nEnd) + 1;
// añadir la URL si "google" no es
if Pos ('google', strAddr) = 0 then
begin
nText := PosEx ('</a>', strRead, nBegin);
strText := copy (strRead, nBegin, nText - nBegin);
// eliminar caché y las referencias duplicadas
if (Pos ('cache', strText) = 0) then
begin
Synchronize (
procedure
begin
if Form1.ListBox1.Items.IndexOf (
strAddr) < 0 then
begin
Form1.ListBox1.Items.Add (strAddr);
Form1.DetailsList.Add (strText);
end;
end);
end;
end;
end;
until nBegin = 0;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 245
procedure TFormParallelFor.btnPlainClick(
Sender: TObject);
var
I, Tot: Integer;
Ticks: Integer;
begin
// cuenta con los nº primos por debajo de un valor dado
Tot := 0;
Ticks := GetTickCount;
for I := 1 to Max do
begin
if IsPrime (I) then
Inc (Tot);
Application.ProcessMessages;
end;
Ticks := GetTickCount - Ticks;
Memo1.Lines.Add (Format (
'No threads: %d - %d', [Ticks, Tot]));
end;
begin
if IsPrime (I) then
InterlockedIncrement (Tot);
end);
Ticks := GetTickCount - Ticks;
Memo1.Lines.Add (Format (
'2 threads: %d - %d', [Ticks, Tot]));
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 247
type
TParallel = class(TThread)
private
FProc: TProc<Integer>;
protected
procedure Execute; override;
function GetNextValue: Integer;
public
constructor Create;
destructor Destroy; override;
Los métodos más interesantes son los que se utilizan para to-
mar el siguiente valor y realizar el proceso real sobre este. Su
código debe ser auto-explicativo:
procedure TParallel.Execute;
var
nCurrent: Integer;
begin
nCurrent := GetNextValue;
while nCurrent <= MaxPos do
begin
Proc (nCurrent);
nCurrent := GetNextValue;
end;
end;
function TParallel.GetNextValue: Integer;
begin
cs.Acquire;
try
Result := CurrPos;
Inc(CurrPos);
finally
cs.Release;
end;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 249
AJAX en Delphi
El último ejemplo de este apartado, llamado AnonAjax, es uno
de mis favoritos, por la sencilla razón que lo he aprendido uti-
lizando closures (o métodos anónimos) en JavaScript, escri-
biendo aplicaciones AJAX con la biblioteca jQuery.
La función global AjaxCall no es distinta de la función Paral-
lelFor del ejemplo anterior, ya que también produce un hilo.
Esta vez, sin embargo, la función termina sin esperar a que el
hilo se complete, pero pasa el hilo a un método anónimo tras
su finalización. La función es sólo una envoltura alrededor del
constructor del hilo:
type
TAjaxCallback = reference to procedure (
ResponseContent: TStringStream);
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 251
99Este
fragmento de código es el tema de un post en mi blog, “Anónimo, Anó-
nimo, Anónimo” de septiembre del 2008, que atrajo ya algunos comentarios,
como puede ver en: http://blog.marcocantu.com/blog/anonymous_3.html.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 253
A continuación
Ahora que he cubierto las dos nuevas principales característi-
cas del lenguaje de Delphi 2009, los genéricos y los métodos
anónimos, es el momento de empezar a estudiar otros muchos
(pero aún relevantes) cambios menores. Este será el tema de
la primera parte del próximo capítulo, que también abarca los
cambios en la RTL desde Delphi 2007.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 257
Capítulo 7: Más
Cambios del
Lenguaje y de la
RTL
Otras Nuevas
La guía de Delphi por Marco Cantù | para Desarrollo
sistemas integrados control, SA
Indice - 259
Características del
Lenguaje
Con tantas nuevas características importantes en el lenguaje
Object Pascal es fácil perderse alguna de las menores, que hu-
bieran sido más significativas en otras versiones con un me-
nor conjunto de cambios.
D2006 VER180
D2007.Net VER190
Delphi VER200
2009
procedure TFormMinorLang.btnDepracatedClick(
Sender: TObject);
begin
DoNothing;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 261
Configuración de Propiedades
por Referencia
En el marco de Delphi 6, el compilador le permitía definir
propiedades utilizando un método de configuración que tenía
un parámetro de referencia. Esta no deseada característica fue
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 263
100Este es el nombre, que el miembro del equipo de Delphi I+D Chris Bensen dio
a esta característica y que introduce el tema en su blog: http://chrisben-
sen.blogspot.com/2008/04/delphi-put-by-ref-properties.html
begin
...
mc.Count := 10; // Error: E2036 Variable required
mc.Number := n;
Cambios en Overloading
El compilador de Delphi 2009 considera un buen número de
cambios internos en el modo en que el compilador selecciona
la función a llamar, en el caso de múltiples versiones sobre-
cargadas, en dónde ninguna de ellas tenga una coincidencia
exacta. Esto es particularmente cierto cuando están involucra-
das variantes.
Hay dos situaciones diferentes que pueden venir a través de:
El Código que se utiliza para compilar emite ahora un error
de compilación
El Código que se utiliza para llamar a un método y que ahora
termina llamando a otro diferente
Huelga decir que, si bien la primera puede ser molesta, esta se
puede arreglar fácilmente añadiendo una conversión explícita
al tipo, en cambio la segunda es mucho más sutil y peligrosa,
ya que solamente descubrirá que las cosas van mal al ejecutar
el programa.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 265
TFormVariantOver.ShowValue(Integer);
Related method: procedure
TFormVariantOver.ShowValue(string);
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 267
private
X: Integer;
public
class operator Implicit (
const Value: Variant): TMyRecord;
end;
Enteros Naturales
ShortInt Byte
SmallInt Word
Integer Cardinal
NativeInt NativeUInt
Int64 UInt64
Nuevos Métodos de
TObject
La estructura de la clase TObject se ha mantenido bastante es-
table a lo largo de los años. En Delphi 2009 se ven algunas
mejoras interesantes. La madre de todas las clases de Delphi
no sólo tiene cuatro nuevos métodos, sino que tres de estos
son métodos virtuales que se supone puede usted redefinir en
sus propias clases. Si ha utilizado el entorno .NET (con Delphi
para .NET u otros lenguajes) usted reconocerá inmediata-
mente que estos métodos son parte de la clase System.Object
de la librería102 de clases .NET.
El Método ToString
La función virtual ToString es un marcador de posición para el
retorno de la representación textual (la descripción) de un de-
terminado objeto. El valor implementado por defecto de este
método en la clase TObject devuelve el nombre de la clase:
function TObject.ToString: string;
begin
Result := ClassName;
end;
El Método Equals
La función virtual Equals es un marcador de posición para
comprobar si dos objetos tienen el mismo valor lógico, una
operación distinta a la de comprobar si dos variables se refie-
ren al mismo objeto, algo que puede lograr con el signo =. Sin
embargo, y esto es realmente confuso, la aplicación por de-
fecto hace exactamente esto:
function TObject.Equals(Obj: TObject): Boolean;
begin
Result := Obj = Self;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 271
El Método GetHashCode
La función virtual GetHashCode es tomada de otro marcador de
posición del entorno .NET, para que cada clase pueda calcular
el código hash de sus objetos. El valor por defecto devuelve un
valor aparentemente aleatorio103, la dirección del objeto en sí
mismo:
function TObject.GetHashCode: Integer;
begin
Result := Integer(Self);
end;
El Método UnitName
El otro método (no descrito) es la función de clase UnitName,
que no es una función virtual, y devuelve el nombre de la uni-
dad en el que la clase esta definida. Anteriormente usted ha-
bría tenido que recurrir a técnicas de bajo nivel (accediendo a
la representación interna de una clase) para acceder a esta
misma información.
Value := aValue;
end;
ComboBox1.Items [ComboBox1.ItemIndex] +
' and ' +
ComboBox2.Items [ComboBox2.ItemIndex]);
Log ('Equals: ' + BoolToStr (
ComboBox1.Items.Objects [ComboBox1.ItemIndex].Equals (
ComboBox2.Items.Objects [ComboBox2.ItemIndex]),
True));
Log ('Reference = ' + BoolToStr (
ComboBox1.Items.Objects [ComboBox1.ItemIndex] =
ComboBox2.Items.Objects [ComboBox2.ItemIndex],
True));
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 275
Resumen de la Clase
Como resumen104, esta es la interfaz completa de la clase
TObject en Delphi 2009 (Advierta los diferentes tipos de datos
string utilizados):
type
TObject = class
constructor Create;
procedure Free;
class function InitInstance(Instance: Pointer):
TObject;
procedure CleanupInstance;
function ClassType: TClass; inline;
class function ClassName: string;
class function ClassNameIs(const Name: string):
Boolean;
class function ClassParent: TClass;
class function ClassInfo: Pointer;
class function InstanceSize: Longint; inline;
class function InheritsFrom(AClass: TClass): Boolean;
class function MethodAddress(
const Name: ShortString): Pointer; overload;
class function MethodAddress(const Name: string):
Pointer; overload;
class function MethodName(Address: Pointer): string;
function FieldAddress(const Name: ShortString):
Pointer; overload;
function FieldAddress(const Name: string):
Pointer; overload;
function GetInterface(const IID: TGUID; out Obj):
Boolean;
class function GetInterfaceEntry(const IID: TGUID):
PInterfaceEntry;
class function GetInterfaceTable: PInterfaceTable;
class function UnitName: string;
function Equals(Obj: TObject): Boolean; virtual;
function GetHashCode: Integer; virtual;
function ToString: string; virtual;
function SafeCallException(ExceptObject: TObject;
ExceptAddr: Pointer): HResult; virtual;
procedure AfterConstruction; virtual;
Cambios en el Soporte
Threading
Ya hemos visto en el capítulo 6, y, en particular en la sección
“Sincronización de procesos con la VCL” que la clase TThread
se ha ampliado para aprovechar las ventajas de los métodos
anónimos. Las extensiones toman la forma de nuevas versio-
nes sobrecargadas de los métodos Synchronize y Queue, aunque
el código Delphi anterior debería trabajar sin problemas.
Otra nueva característica de Delphi 2009 es la presencia del
registro105 TMonitor, una estructura de datos definidos en la
unidad System que usted puede utilizar para proporcionar ac-
ceso sincronizado a cualquier objeto. Este soporte monitor,
que se asemeja a la clase correspondiente del entorno .NET,
nos permite definir un proceso (Thread) ligado a un objeto es-
pecífico. En lugar de tener un semáforo global de sincroniza-
ción, puede establecer un control para cada uno al que usted
procedure TAddToListThread.Execute;
var
aList: TListBox;
I: Integer;
begin
while not Terminated do
begin
aList := Application.MainForm.FindComponent (
'ListBox' + IntToStr (GetTickCount mod 3 + 1))
as TListBox;
System.TMonitor.Enter (aList);
try
aList.Items.Add(IntToStr (GetCurrentThreadID) +
' starting: ' + TimeToStr (Now));
// wait loop, omitted
aList.Items.Add(IntToStr (GetCurrentThreadID) +
' stopping: ' + TimeToStr (Now));
finally
System.TMonitor.Exit (aList);
end;
end;
end;
aListBox: TListBox;
begin
for aListBox in fListBoxes do
begin
if System.TMonitor.TryEnter(aListBox) then
try
aListBox.Items.Add('Available');
finally
System.TMonitor.Exit(aListBox);
end;
end;
end;
Construyendo Cadenas
Hemos visto que la aparición de múltiples tipos de cadenas
causa posibles escollos en la concatenación de cadenas (véase
la sección “Conversión de Cadenas” en el capítulo 2 y el apar-
tado “Operaciones de Cadena Que Fallan o Ralentizan” en el
La guía de Delphi por Marco Cantù | para
Indice - 281
Métodos de Encadenamiento en
StringBuilder
Una característica específica de la clase TStringBuilder es que
la mayoría de los métodos son funciones que devuelven el ob-
jeto actual. Esta codificación del lenguaje abre la posibilidad
de los métodos encadenados106, lo que supondría llamar a un
método sobre el objeto devuelto por el anterior. En vez de es-
cribir:
sBuilder.Append(12);
sBuilder.AppendLine;
sBuilder.Append('hello');
La Velocidad en la Construcción
de Cadenas
Huelga decir que la mayoría de los desarrolladores de Delphi
inmediatamente se preguntaron si utilizando la clase TString-
Builder haría que su código fuera más rápido o más lento
cuando usasen la concatenación de una cadena simple u otras
operaciones de cadena. La respuesta abreviada es que el ren-
dimiento es similar, con una ligera ventaja para la concatena-
ción clásica de cadenas, a pesar de que las situaciones del
mundo real son probablemente diferentes de las pruebas sen-
cillas que he realizado en el ejemplo StringBuilder.
He hecho tres pruebas diferentes: simple concatenación de
cadenas, la adición de números enteros a una cadena, y la in-
serción de una cadena dentro de otra cadena (que es mucho
más lenta y ejecutada una parte de las veces). La lista com-
pleta está en el ejemplo, aquí están las líneas clave de los 6
métodos (con exclusión de las declaraciones utilizadas para
crear y liberar los objetos TStringBuilder):
// 1a. concatenación de cadenas
for I := 1 to MaxLoop do
str1 := str1 + str2;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 285
sBuilder.Append(I);
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 287
for I := 1 to maxCount do
begin
nPos := I mod strB.Length;
strB.Remove(nPos, 1);
strB.Insert(nPos, strB [(I*2) mod strB.Length]);
end;
ListBox1.Items.Add (strB.ToString);
// final del código
107Para
obtener más ideas sobre esta cuestión, véase también mi blog “No tan rá-
pido, TstringBuilder” en: http://blog.marco-
cantu.com/blog/not_so_fast_tstringbuilder.html.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 291
finally
fstr.free;
end;
procedure TFormReaderWriter.btnXmlCorrectClick(
Sender: TObject);
var
sw: TStringWriter;
txw: TTrivialXmlWriter;
theString: string;
begin
sw := TStringWriter.Create;
try
txw := TTrivialXmlWriter.Create (sw);
try
txw.WriteStartElement('book');
txw.WriteStartElement('title');
txw.WriteString('Delphi 2009 Handbook');
txw.WriteEndElement;
txw.WriteEndElement;
finally
txw.Free;
end;
theString := sw.ToString;
finally
sw.Free;
end;
Memo1.Lines.Text := theString;
end;
Mejoras Excepción(ales)
Junto con TObject, otro núcleo de la clase Delphi que ha visto
un par de importantes mejoras en Delphi 2009, es la clase Ex-
ception. Por un lado, hay una nueva función virtual que se
llama después de que un objeto excepción haya sido creado,
pero antes de que se haya lanzado. Por otro lado, existe ahora
el soporte para anidar (o interiorizar) las excepciones. Por úl-
timo, aunque esto no es tan importante, hay algunas clases
nuevas de excepciones en la unidad SysUtils.
El Mecanismo InnerException
¿Qué sucede si usted plantea una excepción dentro de un ma-
nipulador de excepciones? La respuesta tradicional de Delphi
es que las nuevas excepciones sustituirán a la existente, razón
por la cual esta es una práctica común para combinar al me-
nos los mensajes de error, con código como éste (que carece
de cualquier operación real, y muestra sólo las declaraciones
relacionadas con las excepciones):
procedure TFormExceptions.ClassicReraise;
begin
try
// hacer algo ...
raise Exception.Create('Hello');
except on E: Exception do
// intentar arreglar algunos ...
raise Exception.Create('Another: ' + E.Message);
end;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 295
108La
razón por la que he conectado esta nueva función del framework de dbEx-
press es simple: las unidades DBXCommon y la DBXPlatform son actual-
mente las dos únicas unidades de la VCL (para Win32), que se refieren a la
propiedad InnerException.
109Heomitido en esta lista de la clase Exception otras nuevas características
comparadas con Delphi 2007, como la nueva clase de datos de punteros a
funciones que pueden utilizarse para conectar dentro de la pila de rastreo de
la excepción (un tema avanzado que no voy a tratar en el libro) y el nuevo
método RaisingException detallado en el siguiente apartado.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 297
Preprocesamiento de
Excepciones
Una de las características de la clase Exception es una nueva
función virtual protegida, declarada como:
procedure RaisingException(P: PExceptionRecord); virtual;
procedure ECustomException.
RaisingException(P: PExceptionRecord);
begin
// registrar la información de la excepción (¡a un
//archivo sería más inteligente!)
FormExceptions.Log('Exception Addr: ' + IntToHex (
Integer(P.ExceptionAddress), 8));
FormExceptions.Log('Exception Mess: ' + Message);
// modifica el mensaje
Message := Message + ' (filtered)';
// proceso estándar
inherited;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 301
Generics.Collec- TArray
TEnumerator<T>
tion TEnumerable<T>
TList<T>
TQueue<T>
TStack<T>
TDictionary<TKey,TValue>
TObjectList<T>
TObjectQueue<T>
TObjectStack<T>
TObjectDictionary<TKey,TValue>
Generics.Default TComparer<T>
TEqualityComparer<T>
TSingletonImplementation
TDelegatedEqualityComparer<T>
TDelegatedComparer<T>
TCustomComparer<T>
TStringComparer
Las siguientes son las nuevas clases de Delphi 2009 (o los rec-
ords con sus métodos) que se han añadido a las actuales uni-
dades de la RTL. Fíjese, en particular, que lo que hay aquí son
las clases de la unidad SysUtils (y no sólo las de la unidad
Classes), mientras que la unidad System añade dos registros
con métodos. Está es la lista:
Classes TBytesStream
TTextReader
TTextWriter
TStringReader
TStringWriter
TStreamWriter
TStreamReader
SyncObjs TSemaphore
TConditionVariableMutex
TConditionVariableCS
System TMonitor
SysUtils TStringBuilder
TEncoding
TMBCSEncoding
TUTF7Encoding
TUTF8Encoding
TUnicodeEncoding
TBigEndianUnicodeEncoding
ZLib TCustomZStream
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 303
A continuación
Este capítulo sobre la variedad de cambios en el compilador y
las nuevas características de la librería de Delphi en tiempo de
ejecución, completa la segunda parte del libro, que se ha cen-
trado en el compilador y en el IDE. La tercera parte del libro
se centrará en la VCL, incluyendo las nuevas características de
soporte a Vista, la interfaz de usuario Ribbon, el soporte para
traducción, y el soporte COM. Después trataremos la pro-
gramación con bases de datos y las aplicaciones multi-tarea
sobre bases de datos.
Apartado III: La
VCL y Las Bases
de Datos
Capítulo 8:
Mejoras En la
VCL
Mejoras Fundamentales
de la VCL
Además de los diversos cambios y correcciones para compo-
nentes y controles específicos, tratados en este capítulo, hay
algunas mejoras introducidas en el núcleo de la VCL a nivel de
clase que benefician a todos y cada uno de los controles visua-
les de la librería.
Una de estas mejoras es el hecho de haber añadido la propie-
dad ParentDoubleBuffered en la clase TWinControl que hace
más fácil disponer de doble buffer de memoria para un for-
mulario completo o un grupo de controles. El doble buffering
112Siusted compara la VCL con la librería WinForms del .NET Framework o con
las principales librerías Java verá a qué me refiero. Uno de los elementos
clave de la VCL, es su estricta relación con la API de Windows, sin embargo,
este es también uno de sus puntos débiles, como portar fuera del mundo
Windows lo cual se ha demostrado difícil (como el proyecto CLX y en parte
como a demostrado la VCL para .NET).
113El
soporte de Vista en la VCL está cubierto al detalle en mi “Delphi 2007
Handbook”.
Hint =
'This is a button|' +
'This is a longer description for the button, ' +
'taking some space|2'
CustomHint = BalloonHint1
Caption = 'Button3'
end
Mejoras para
Componentes Estándares
Si hay algunas características nuevas que afecten a todos los
controles, la mayoría de las mejoras en la VCL de Delphi 2009
son específicas de controles individuales. El núcleo de los con-
troles estándar, así como los controles comunes, se han am-
pliado de una versión de Windows a otra por parte de Micro-
soft, mientras que la VCL ha descuidado a menudo el soporte
a estas nuevas características del nuevo sistema operativo, a
veces por las razones de compatibilidad hacia atrás (como
aplicaciones similares podrían tener problemas si se ejecutan
en versiones anteriores del sistema operativo, de las que en
cualquier caso Delphi ya ha dejado de dar soporte).
En esta sección voy a centrarme en las mejoras de algunos de
los controles básicos de Windows, tales como botones y cua-
dros de edición. En la siguiente sección me voy a centrar en
las mejoras (más limitadas) de los controles comunes.
Características
Usted podría pensar que en el clásico Windows los botones de
pulsación están bien establecidos, y son controles estables.
Pero, en la actualidad, esto no es cierto. Desde Windows XP,
usted puede conectar la imagen de una lista de imágenes a un
botón, y tener un botón gráfico con mapa de bits, sin tener
que derivar un control personalizado auto-dibujado tal como
hizo Delphi desde los primeros días con el control BitBtn (bit-
map button). En Delphi 2009 usted puede obtener ahora el
mismo efecto gráfico con un simple y estándar TButton. El
soporte de ImageList se obtiene a través de una serie de pro-
piedades que puede utilizar para determinar qué imagen
quiere usar en cada uno de los varios estados del botón. Aquí
está la lista de la nueva imagen relacionada con las propieda-
des de la clase TCustomButton listada sólo con sus tipos:
property DisabledImageIndex: TImageIndex ...
property HotImageIndex: TImageIndex ...
property ImageAlignment: TImageAlignment ...
property ImageIndex: TImageIndex ...
property ImageMargins: TImageMargins ...
property Images: TCustomImageList ...
property PressedImageIndex: TImageIndex ...
property SelectedImageIndex: TImageIndex ...
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 313
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 315
Envoltura de Texto en
RadioGroup
El componente RadioGroup (la combinación personalizada de
un GroupBox con los actuales controles RadioButton) obtiene
una sola nueva característica, el soporte de envoltorio sobre la
palabra que los botones de radio contienen por si mismos.
El inconveniente en este caso es que el componente no será
capaz de calcular el espaciamiento vertical de los distintos ele-
mentos correctamente, y si usted tiene (por ejemplo) un ele-
mento, con tres líneas de texto, podría resultar que la parte
superior de la primera línea o la parte inferior de la última lí-
nea no sea visible.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 317
116Paraobtener una lista detallada de los estilos de ventanas para un control Edit
a nivel de la API, consulte la Documentación del SDK en: http://msdn.mi-
crosoft.com/en-us/library/bb775464.aspx.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 319
end
memoLowercase.CharCase := ecUpperCase;
memoLowercase.Lines.Text := 'Cantù';
end;
117Enel API de Windows, no hay diferencia entre un Edit y un Memo, ambos son
controles EDIT, se inician con una sola línea o con un estilo de línea múlti-
ple.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 321
ComboBoxes y Hints
En la API de Windows, los ComboBoxes tiene una relación es-
tricta con los Edit boxes, ya que consiguieron su nombre (y al-
gunas de sus implementaciones de código) de una combina-
ción de un Edit y un ListBox. Por lo que usted apenas debería
sorprenderse por ver una propiedad TextHint añadida tam-
bién a la clase TComboBox, al igual que en la clase TEdit. Una
vez más, esta función requiere Windows XP o una versión
más moderna de Windows118.
Hay un simple cuadro combinado con un texto personalizado
en el ejemplo EditFamilyDemo como usted puede ver en la úl-
tima imagen mostrada (un par de páginas atrás).
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 323
RightButton.Visible = True
TextHint = 'Some text'
OnLeftButtonClick = edClearLeftButtonClick
OnRightButtonClick = edClearRightButtonClick
end
Actualizaciones de
Controles Comunes
Las mejoras de los controles estándares de la VCL de Delphi
2009 son sumamente importantes puesto que también están
relacionadas con los controles habituales de uso común como
los edits y los botones. La nueva versión de la VCL también
incluye muchas mejoras en los demás controles establecidos
por la API de Windows desde que esta mutó a la versión de 32
bits del sistema operativo. A continuación comentamos algu-
nos controles que tienen características nuevas:
ImageList: Aunque a no todos los desarrolladores les benefi-
ciará esto, ahora el componente ImageList soporta imágenes
alpha, lo que le permite establecer una profundidad de color
personalizada, con una nueva propiedad y su correspondiente
nombre (ColorDepth).
TreeView: Otro componente con escasos cambios en el pasado
es el TreeView, que ahora le permite definir un índice de ima-
gen para los nodos expandidos y (en Windows XP o poste-
rior) soporta también nodos de árbol deshabilitados.
Agrupaciones en un ListView
Un control común que merece la pena explorar con más deta-
lle es el ListView, que en Delphi 2009 recibe el soporte directo
para agrupación. Esta característica requiere Windows XP o
Vista, esta última con funciones ampliadas.
Hay tres nuevas propiedades en el control ListView. El opera-
dor Booleano GroupView permite este nuevo tipo de repre-
sentación, el GroupHeaderImages se refiere a un ImageList
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 327
end;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 329
Cabecera
Otro control común, aunque no usado con frecuencia, es el
componente HeaderControl. En la VCL de Delphi 2009, este
control soporta ahora secciones de cabecera de ancho fijo (uti-
lizando la propiedad NoSizing), cabeceras extras no visibles si
no se ajustan (utilizando su propiedad Overflow) y, más in-
teresante aún, casillas de verificación en las secciones de ca-
becera.
Para activar esta función usted tiene que conectarlo para el
control en su conjunto y después para cada sección individual,
según lo indicado por las propiedades del control (y su grupos
de secciones) en el ejemplo CheckBoxHeader:
object HeaderControl1: THeaderControl
Sections = <
item
AutoSize = True
CheckBox = True
Text = 'one'
end
item
AutoSize = True
CheckBox = True
Checked = True
Text = 'two'
end
item
AutoSize = True
CheckBox = True
Text = 'three'
end
item
AutoSize = True
CheckBox = True
Text = 'four'
end>
OnSectionCheck = HeaderControl1SectionCheck
CheckBoxes = True
end
RichEdit 2.0
El componente RichEdit se utiliza en Delphi para encapsular
la versión original del correspondiente control común. Para
compatibilizar una nueva versión del control, la VCL en Del-
phi 2009 usa ahora la versión 2 de la DLL específica que hos-
peda este control común:
RichEditModuleName = 'RICHED32.DLL'; // Delphi 2007
RichEditModuleName = 'RICHED20.DLL'; // Delphi 2009
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 333
Componentes Nativos de
la VCL
Después de examinar los controles estándar y los controles
comunes del API de Windows, envueltos por los controles co-
rrespondientes VCL, ha llegado el momento de centrarse en
las nuevas características de los controles VCL nativos y un
nuevo control, el componente CategoryPanels.
En particular, voy a comenzar por examinar algunas amplia-
ciones en la arquitectura del Action Manager, dedicar algún
tiempo a los paneles, a algunos componentes globales de la
VCL, y echar un vistazo a la ampliación del soporte a los gráfi-
cos, que ahora incluye Imágenes PNG, para ambos compo-
nentes, Image e ImageList.
Sobre Paneles
Hasta hace unos años, el componente Panel era un compo-
nente utilizado comúnmente con funciones limitadas, aunque
soportase el acoplamiento. En Delphi 2006, tuvo un significa-
tivo rediseño, con la llegada de los paneles que no utilizan po-
sicionamiento absoluto de los controles que contienen, sino
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 335
El Nuevo Control
CategoryPanelGroup
Una familia de componentes para los que hemos visto el ma-
yor número de controles VCL disponibles en los últimos años
ha sido la denominada barra lateral de la familia Outlook Si-
debar, imitando así esta interfaz que estableció originalmente
Microsoft en su programa de correo electrónico.
En las aplicaciones modernas, los estilos han cambiado mu-
cho desde la colección original de grandes iconos utilizados
para las diversas secciones del programa, pero el uso de una
123Una vez más, se puede hacer referencia a mi “Delphi 2007 Handbook” para
obtener más información acerca de estos controles. Perdone que me refiera a
mi anterior libro, pero hay poca información pública relativa a estos contro-
les... y mi anterior libro realmente complementa esta información.
Actualización de
El componente TrayIcon, introducido por primera vez en Del-
phi 2007, tiene un nuevo evento OnBalloonClick, utilizado
para la manipulación del clic sobre el área del globo de ayuda,
cuando esta sea visible. Para mostrar esto en la práctica he
ampliado el ejemplo MyTrayIcon de Delphi 2007 Handbook
124Esto habría sido un buen caso para usar una lista genérica o lista de objetos,
en lugar de un simple TList, pero como esto se añade en paralelo a las nue-
vas características del compilador, no es sorprendente que no dependa de
ellos.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 341
En este punto todo lo que tuve que hacer fue activar la propie-
dad de ParentFont en los dos formularios en tiempo de di-
seño. Dos botones, uno en cada formulario, muestran su nom-
bre de fuente, como prueba de que esta técnica funciona (aun-
que probablemente pueda ver los diferentes tipos de fuentes
en estos formularios). Estas son las propiedades del formula-
rio secundario:
object FormSecondary: TFormSecondary
Caption = 'Secondary'
ParentFont = True
Visible = True
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 343
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 345
El Portapapeles y Unicode
El objeto global Clipboard es un envoltorio bastante simple de
la correspondiente API, definido en la unidad ClipBrd. Una
extensión importante de este componente es la forma en que
maneja las cadenas Unicode. Cuando pegue texto en el porta-
papeles, de hecho, el envoltorio Delphi ahora asocia el
CF_UNICODETEXT al formato de datos del portapapeles, en
lugar del formato clásico CF_TEXT.
Esto queda demostrado en el sencillo programa Uni-
Clipboard, que puede añadir el contenido de un cuadro de
texto al Portapapeles (conteniendo un texto simple o dos ca-
racteres Japoneses) y pegarlos después de comprobar que los
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 349
procedure TFormUniClipboard.btnPasteClick(
Sender: TObject);
begin
Clipboard.Open;
if Clipboard.HasFormat(CF_TEXT) then
Memo1.Lines.Add('CF_TEXT');
if Clipboard.HasFormat(CF_UNICODETEXT) then
Memo1.Lines.Add('CF_UNICODETEXT');
Memo1.Lines.Add(Clipboard.AsText);
Clipboard.Close;
end;
A continuación
En esta sección he explorado innumerables mejoras en los
controles clásicos VCL en Delphi 2009, en parte relacionadas
con las nuevas características del sistema operativo. También
se muestra un ejemplo de un nuevo componente, el Cate-
goryPanelGroup.
Este no es el único nuevo componente visual de la VCL, sino
todo lo contrario. Una notable ampliación de la VCL son el
conjunto de controles nativos de Delphi 2009 para dar so-
porte a la interfaz de usuario Ribbon. Este tema es tan impor-
tante que he decidido dedicar un capítulo específico, en lugar
de abordar toda su amplitud en este capítulo de actualizacio-
nes VCL.
Antes de llegar al control Ribbon, sin embargo, existe otra
área de la VCL que fue modificada de manera significativa en
Delphi 2009: El soporte COM. Como veremos en el siguiente
capítulo, hay una introducción de un lenguaje de definición de
interfaz (RIDL), un papel diferente para la librería de archivos
de tipos, un nuevo panel del IDE, y asistentes actualizados.
Para los que usan COM en su arquitectura, estas son unas no-
ticias muy positivas.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 353
Capítulo 9:
Soporte COM En
Delphi 2009
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 355
129Elcódigo fuente completo, del que tomó estos fragmentos de código, se en-
cuentra en la siguiente sección, "El Formato RIDL ".
El Formato RIDL
(Servidores COM)
Para ver de que se trata este nuevo formato RIDL, vamos a
convertir un proyecto COM ya existente mediante su apertura
en Delphi 2009. Como ejemplo, he tomado el ejemplo COM
SimpleServer de Mastering Delphi 2005 y convertido este a
Delphi 2009. Junto a la norma de conversión del formato del
archivo del proyecto, Delphi me advirtió de la migración de la
biblioteca de tipos:
Converting '...\08\SimpleServer\SimpleServer.tlb'
to .ridl format
Reading 'SimpleServer.tlb'
Writing 'SimpleServer.ridl'
Adding 'SimpleServer.ridl'
Removing 'SimpleServer.tlb'
130Usando la convención safecall todas las llamadas COM son asignadas, por lo
que la comprobación de errores en términos de HRESULT en el sistema deben
reasignarse a las excepciones propias de Delphi. Básicamente, cada función
o procedimiento se convierte en una función con un retorno con valor HRE-
SULT, según lo solicitado por la doble interfaz COM, y un parámetro de sa-
lida adicional, posiblemente añadido al valor de retorno real. En el lado del
servidor, Delphi envuelve el código en un bloque try except que eventual-
mente atraparía una excepción y devolvería un código de error. En el lado
del cliente, un código de error en una llamada obligaría a Delphi a lanzar la
correspondiente excepción.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 359
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 361
helpstring("NumberProp")
]
coclass NumberProp
{
[default] interface INumberProp;
};
};
CoNumberProp = class
class function Create: INumberProp;
class function CreateRemote(
const MachineName: string): INumberProp;
end;
Registrando y Llamando al
Servidor
Ahora que he recompilado el servidor, puedo registrarlo en el
sistema para poder recurrir al mismo (y también utilizar el
nuevo panel Registered Type Libraries del IDE de Delphi).
Después de compilar, debe utilizar el comando del menú Run
| . La primera vez que lo hice, obtuve el siguiente y terrible
error: Unspecified Error (Error sin especificar). Resulta que,
si está ejecutando el IDE en Vista con el (UAC) activo, no
puede realizar este paso ya que el IDE no tratará de elevar
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 363
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 365
Una vez más, es muy poco (o nada) lo que tiene que hacer en
el lado de la aplicación cliente COM para pasarlo a Delphi
2009. Sin embargo, si usted está creando un nuevo proyecto
de cliente, como yo he hecho, probablemente le agradarán las
mejoras en el asistente de importación para la biblioteca de ti-
pos.
COM y Unicode
Una de las razones por la que los cambios, en el soporte COM
y clientes COM en particular, están limitados, es debido al he-
cho de que las aplicaciones COM generalmente no utilizan el
sencillo string Delphi sino que se basan en el tipo nativo
WideString habilitado para COM (o BSTR en términos COM).
Como vimos en la Parte I del libro, ya se utilizaba el tipo
WideString de dos-bytes por carácter y no ha cambiado desde
Delphi 2007. La razón de que este tipo de cadena menos efi-
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 367
Características que
Vuelven: Active Forms
Algunas características de los tiempos de Delphi 7 han vuelto
en Delphi 2009 después de una larga ausencia. Uno de ellos
es el ActiveX Control Wizard (incluyendo Active Forms). Ad-
vierto, no obstante que este asistente, no genera los archivos
de distribución HTML apropiados como lo hizo en el pasado.
En realidad la mayoría de los asistentes COM han mejorado
gráficamente (y parcialmente en su conjunto de característi-
cas) en Delphi 2009, como se puede ver en la sinopsis facili-
tada por Chris Bensen en su blog sneak peek en:
http://chrisbensen.blogspot.com/2008/07/
tiburn-sneak-peek-com-wizards.html
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 369
>
</object>
</html>
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 371
A continuación
En este breve capítulo he explorado algunos de los cambios
más significativos del soporte COM en Delphi 2009, incluidos
los nuevos archivos RIDL, los diferentes papeles de las biblio-
tecas de tipos, y algunos de los asistentes y actualizaciones de
herramientas del IDE. Ya no tiene sentido que describa la tec-
nología COM en detalle, ya que he utilizado para ello dos
grandes capítulos de mi serie “Mastering Delphi”.
Ahora que hemos visto todos los cambios en el núcleo VCL y
su subsistema COM, es el momento de centrarse en la nove-
dad visual más interesante de la VCL Delphi 2009, el nuevo
control Ribbon.
Capítulo 10:
Ribbon
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 373
Presentando el “Fluent
User Interface”
Como mencioné anteriormente, el Fluent User Interface fue
inventado por Microsoft, que está buscando una patente133
para él. Esta patente no se centra en el código del interfaz de
usuario (los controles “Ribbon” usados en Office 2007), sino
en el diseño del interfaz de usuario en si mismo. Microsoft
también se refiere a este interfaz como “Microsoft for the Of-
fice UI.”
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 379
Acciones y la “Ribbon”
Como ya he mencionado alguna vez, el control “Ribbon” se
basa en el ActionManager de Delphi. Veremos como crear una
UI basada en “Ribbon” en el siguiente ejemplo. Antes, sin em-
bargo, necesito recapitular una serie de características clave
de esta arquitectura para los que nunca la han usado135. Si ya
ha usado el componente ActionManager anteriormente, se
puede evitar las dos siguientes secciones y saltar a “Acciones y
Ribbon en la práctica”.
De eventos a Acciones
El manejo de eventos de Delphi es muy abierto: se puede es-
cribir un manejador sencillo de evento y conectarlo a los even-
tos OnClick de los botones de una barra de herramientas y un
menú. También puede conectar el mismo gestor de eventos a
diferentes botones o elementos de menú, porque el gestor de
eventos puede usar el parámetro Sender para referirse al ob-
jeto que lanzó el evento. Es un poco más difícil el sincronizar
el estado de los botones de la barra de herramientas y elemen-
tos de menú. Si tiene un elemento de menú y un botón que
“ActionList” y “ActionManager”
Cada acción existe en memoria pero no son componentes
VCL. De hecho, son manejados por componentes contenedo-
res, llamados ActionList y ActionManager. Realmente es un
contenedor antiguo y simple, la integración y generación de
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 383
Grupos y comandos
Ahora que tengo todas esta acciones en su sitio, se puede
crear un interfaz de usuario Ribbon de ellos. Después de crear
dos pestañas y unos cuantos grupos, puedo arrastrar las ac-
El Menú de aplicación
Para completar nuestra aplicación, para la cual he enlazado
diversas acciones personalizadas sin tener que escribir código,
debería añadir dos elementos relevantes para el interfaz de
usuario Ribbon. Ambos son añadidos usando comandos al
editor del componente “Ribbon” (el menú de acceso rápido
que aparece en diseño cuando el componente está seleccio-
nado) y puede ser añadido solo si el ActionManager está esta-
blecido.
El primer elemento en el menú de aplicación, el control re-
dondo en la esquina superior izquierda de la “Ribbon” reem-
plaza el menú de aplicación tradicional de Windows. Aquí
está el componente en ejecución en la demo:
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 387
procedure TRibbonEditorForm.FileSaveAs1Accept(
Sender: TObject);
begin
RichEdit1.Lines.SaveToFile(FileSaveAs1.Dialog.FileName);
Ribbon1.DocumentName := FileSaveAs1.Dialog.FileName;
AddToMru(FileSaveAs1.Dialog.FileName);
end;
procedure TRibbonEditorForm.AddToMru(
const strFilename: string);
begin
Ribbon1.AddRecentItem(strFilename);
end;
La barra de herramientas de
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 389
acceso rápido
El segundo elemento gráfico de la “Ribbon” es la barra de he-
rramientas de acceso rápido, una barra de herramientas con
operaciones de sistema automáticamente gestionada por el
sistema. Se añade a la derecha del selector redondo del menú
de aplicación, en este caso mostrando un par de acciones
(Save as y Exit):
end
item
Action = RichEditBold1
CommandProperties.GroupPosition = gpEnd
end>
ActionBar = RibbonGroup8
end
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 395
139Enteoría, estos tipos de comando podrían ser usados por cualquier otro con-
tenedor de la acción visual de enlaces, ya que esta se define como parte de la
arquitectura de Action Manager que no esté específicamente vinculada al
Ribbon. En este momento sin embargo, los demás visualizadores de acción y
estilos ignoran esta propiedad.
“Ribbons” en aplicaciones
de bases de datos
Es muy obvio ver como el uso de un control Ribbon se adapta-
ría a una aplicación orientada a documentos, pero ¿cómo se
adaptaría a programas completamente diferentes como son
los de base de datos? Considerando que tenemos un conjunto
de acciones básicas relacionadas con base de datos disponi-
bles, podríamos ser tentados de utilizar una “Ribbon” en vez
un DBNavigator, clásico, y esto es de hecho posible (y además
bastante sencillo de lograr). No estoy exactamente seguro de
que esto respete las reglas de uso de Microsoft pero cierta-
mente no infringe la norma de clonación de Office.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 399
Caption = 'Undo'
FollowChange = False
end
object FileOpen1: TFileOpen
Caption = '&Open...'
Dialog.Filter = 'CDS|*.cds|XML|*.xml'
Dialog.InitialDir = '...\CodeGear Shared\Data'
OnAccept = FileOpen1Accept
end
object FileExit1: TFileExit...
end
object DBGrid1: TDBGrid
Align = alClient
DataSource = DataSource1
end
object DataSource1: TDataSource
DataSet = ClientDataSet1
end
object ClientDataSet1: TClientDataSet
FileName = '...\CodeGear Shared\Data\customer.cds'
end
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 403
ScreenTip.ShowImage = True
ScreenTipManager = ScreenTipsManager1
Visible = False
end
object ScreenTipsManager1: TScreenTipsManager
FooterImage.Data = {...}
end
end
ScreenTipsManager y las
acciones
Incluso aunque se usen las “Screen Tips” sin una “Ribbon” y
una ActionList o ActionManager, este sería el escenario más
clásico y en el cual trabajan mejor y para el cual hay un so-
porte específico. De hecho, si se sitúa un componente Screen-
TipsManager en un formulario que usa una ActionList o un
ActionManager (con o sin un control Ribbon), se podrán utili-
zar varias características del editor de componente, que son
los comandos de su menú de contexto:
El comando “Generate Screen Tips” ayudará a crear un
“Screen Tip” básico para cada acción y conectarlos. Si se tie-
nen ya generados los “Screen Tips” para algunas acciones se
preservaran.
El comando “Regenerate Screen Tips” trabaja como el co-
mando anterior pero quitará cualquier “Tip” anterior y co-
menzará luego desde el principio.
El comando “Edit Screen Tips” le permitirá ver y personalizar
todos los “Screen Tips” relacionados, con un editor fácil de
usar.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 405
ScreenTipsManager:
Sin embargo, para hacer la cosas mucho más fáciles, se debe-
ría usar el editor de “Screen Tips”, en lugar de hacer doble clic
sobre el ScreenTipsManager.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 407
A continuación
Después de haber tocado la RTL al final de la parte II del li-
bro, en los tres últimos capítulos he cubierto las nuevas carac-
terísticas de la VCL (Capítulo 8), los cambios en el soporte de
COM (Capítulo 9) y el novísimo componente “Ribbon” basado
en la arquitectura del ActionManager (en el capítulo actual).
En la otra esquina se sitúa el soporte de base de datos de la
VCL. La tecnología de base de datos no ha cambiado desde la
última versión, si no se considera el hecho de ahora se soporta
Unicode. De hecho, la clase TDataSet introdujo el soporte de
Unicode en la versión anterior. Pero se basaba en el tipo
WideString, no en el nuevo tipo UnicodeString. Los cambios
en la arquitectura de acceso a base de datos, incluyendo la li-
brería dbExpress, serán tratados en el siguiente capítulo,
mientras que la ampliamente mejorada arquitectura multi-
capa DataSnap será el tema principal del capítulo número 12.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 409
Capítulo 11:
Datasets Y
dbExpress
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 411
Un ClientDataSet Unicode
Antes de empezar a observar los cambios de los componentes
de bases de datos en Delphi 2009, creo que vale la pena dar
antes un vistazo a un ejemplo de aplicación basada en bases
de datos Unicode. Para mantener la sencillez, por ahora voy a
utilizar un componente ClientDataSet que se rellena dinámi-
camente con las cadenas procedentes de múltiples alfabetos.
En este ejemplo, denominado UniCds, la estructura de datos
del ClientDataSet se define en tiempo de ejecución, en el
evento OnCreate del formulario principal:
procedure TFormUniCds.FormCreate(Sender: TObject);
begin
cds.FieldDefs.Clear;
cds.FieldDefs.Add ('code', ftInteger, 0, True);
cds.FieldDefs.Add ('uni', ftWideString, 30, False);
cds.FieldDefs.Add ('ansi', ftString, 30, False);
cds.CreateDataSet;
cds.Open;
end;
try
I := 1;
sList.LoadFromFile('utf8text.txt');
for strLine in sList do
begin
cds.InsertRecord([I, strLine, AnsiString(strLine)]);
Inc (I);
end;
finally
sList.Free;
end;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 413
Unicode en Datasets,
Toma 2
Las clases TDataSet y TField se encuentran entre las pocas
clases que soportaban ya Unicode desde Delphi 2006. Este
soporte Unicode, sin embargo, está basado sobre el tipo Wid-
eString, que todavía está disponible pero que no es la norma
de enfoque utilizada en Delphi 2009 para soportar Unicode.
Como vimos en el Capítulo 2, el tipo WideString representa
un tipo menos optimizado y sin recuento de referencia hospe-
dando caracteres wide, originalmente introducidos para la
compatibilidad COM.
Si usted compara el código fuente de los componentes data-
base de la VCL de Delphi 2006 y Delphi 2009, podrá ver cla-
ramente que la mayoría de las propiedades declaradas como
WideString han vuelto al tipo de cadena predefinido, hasta el
punto de que el código fuente parece más similar al de versio-
nes anteriores, como Delphi 7 y Delphi 2005. Por ejemplo, si
ha mirado el código fuente de la clase TField, en Delphi 2007,
puede observar las siguientes propiedades:
La guía de Delphi por Marco Cantù
414 - Indice
type
TField = class(TComponent)
public
property FullName: WideString read GetFullName;
property DisplayLabel: WideString
read GetDisplayLabel write SetDisplayLabel
property FieldName: WideString
read FFieldName write SetFieldName;
property LookupKeyFields: WideString
read FLookupKeyFields write SetLookupKeyFields;
property LookupResultField: WideString
read FLookupResultField write SetLookupResultField;
property KeyFields: WideString
read FKeyFields write SetKeyFields;
Bookmarks
La clase TDataSet maneja los bookmarks para mantener el
foco a un determinado registro del conjunto de datos y permi-
tir al programa volver a este. Técnicamente, los bookmarks
son punteros a estructuras de datos internas, pero (desde mu-
chas versiones) se declaraban como si se fuesen strings para
aprovechar la ventaja de las cadenas con recuento de referen-
cia:
type
TBookmark = Pointer;
TBookmarkStr = string;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 417
2009141:
type
TBookmark = TBytes;
TBookmarkStr = AnsiString;
// deprecated use TBookmark instead.
// from SysUtils:
TBytes = array of Byte;
141Conla nueva directiva deprecated teniendo ahora como parámetro una des-
cripción, no estoy realmente seguro de por qué este tipo de datos está co-
mentado como obsoleto. Usando de la directiva adecuada en el caso descrito
aquí, obtendremos una advertencia clara antes del mensaje de error.
TIndexDefs = class(TDefCollection)
constructor Create(ADataSet: TDataSet); virtual;
TFieldDefList = class(TFlatList)
// from base class
constructor Create(ADataSet: TDataSet); virtual;
TFields = class(TObject)
constructor Create(ADataSet: TDataSet); virtual;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 421
142Podría
ser interesante añadir en cada definición de campo una referencia a la
información de metadatos, un diccionario de datos, una definición de
campo, o cualquier cosa que le permita tener un más flexible y potente capa
de acceso a datos.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 423
initialization
DefaultFieldClasses [ftString] := TMyStringField;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 425
Extensiones de Campos
Además de cambiar la propiedad de algunos tipos de Wid-
eString de nuevo a string, como se mencionó anteriormente
en la sección “Unicode en Datasets, Toma 2” la clase TField
ahora tiene soporte para algunos de los nuevos tipos de cam-
pos (además esto diferencia entre AsString, que ahora de-
vuelve un UnicodeString, y el nuevo AsAnsiString):
type
TField = class(TComponent)
public
property AsExtended: Extended
read GetAsExtended write SetAsExtended;
property AsAnsiString: AnsiString
read GetAsAnsiString write SetAsAnsiString;
property AsBytes: TBytes
read GetAsBytes write SetAsBytes;
TUnsignedAutoIncField = class(TLongWordField)
TExtendedField = class(TNumericField)
Extensiones de Parámetros
Como los campos, los parámetros tienen algunas propiedades
nuevas, pero en este caso puede no sólo ver el soporte para los
nuevos tipos de campo, sino también para los nuevos tipos de
parámetros utilizados para DataSnap:
type
TParam = class(TCollectionItem)
public
property AsShortInt: LongInt;
property AsByte: LongInt;
DataSets Internos
Usted probablemente ya sabe que la clase TDataset es una
clase base abstracta que define los fundamentos de acceso a
la base de datos de Delphi. Puede que no sepa, sin embargo,
que esta clase tiene un gran número de métodos virtuales que
requieren una puesta en práctica de nivel de implementación
bastante bajo para su administración a nivel-buffer, que en el
pasado se basaron todos en punteros PChar.
Huelga decir que, en Delphi 2009 esto ya no es cierto. La ma-
yoría de punteros a bajo nivel están declarados como PByte o
TBytes (es decir, array of Byte). Para aclarar y simplificar el
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 429
Podría listar una docena de otros métodos con las mismas di-
ferencias. Es importante señalar que muchos de estos son mé-
todos virtuales, los métodos que necesita aplicar para definir
un dataset personalizado. Los métodos de la interfaz pública
de TDataSet, en cambio, sufren cambios muy limitados. En
otras palabras, los cambios en la clase de TDataSet tienen
poco efecto sobre los usuarios de clases datasets, pero afectan
de forma significativa a los que escribieron una clase persona-
lizada de dataset.
personalizado
Para Mastering Delphi 7 escribí144 un conjunto de datos per-
sonalizados sobre la base de una arquitectura registro-a-
stream. Así que pensé que la adaptación de este dataset perso-
nalizado a Delphi 2009 sería una buena prueba del esfuerzo
necesario para dicho proceso.
Una vez hecha esta importación (sin tener que pasar toda la
extensión a soporte de cadenas Unicode en mi base de datos),
tengo que decir que fue fácil. El CustomDataset está dividido
en dos unidades de código fuente: la unidad MdDsCustom,
que define la clase TMdCustomDataSet, de alto nivel abstracto, y
la unidad MdDsStream, que define la implementación actual
de la clase TMdDataSetStream.
Abrí las dos unidades, hice un Buscar / Reemplazar de PChar a
TRecordBuffer encontrando 19 apariciones en la búsqueda de
la primera unidad y 4 en la segunda, aceptando el cambio en
todos ellos. La mayoría de las referencias a PChar estaban en la
declaración de los métodos virtuales que se han modificado,
un par eran variables locales de carácter temporal que se uti-
lizan para almacenar el buffer en uso, obtenidas con el mé-
todo ActiveBuffer de la clase TDataSet que ahora devuelve un
TRecordBuffer.
Hasta este punto, el componente compilará. En el programa
principal tuve que modificar el código para probar book-
marks, declarando la variable local como:
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 431
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 433
GETDRIVERFUNC=getSQLDriverINTERBASE,
DATABASE=..\CodeGear Shared\Data\Employee.GDB,
ROLENAME=RoleName,
USER_NAME=sysdba,
PASSWORD=masterkey,
SERVERCHARSET=,
SQLDIALECT=3,
BLOBSIZE=-1,
COMMITRETAIN=False,
WAITONLOCKS=True,
ERRORRESOURCEFILE=,
LOCALECODE=0000,
INTERBASE TRANSISOLATION=ReadCommited,
TRIM CHAR=False
Properties ['ConnectionString']);
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 437
initialization
SetConnectionManager;
Drivers en el Ejecutable
Por último, para que la aplicación funcione tiene que agregar
la unidad DbxInterBase a su cláusula uses, ya que contiene el
controlador y la información de metadatos de la base de datos
específica.
Esta unidad se añade generalmente automáticamente al con-
figurar el controlador con el componente SQLConnection,
pero he visto situaciones en las que esto no era gestionado
adecuadamente, lo que produce el siguiente error:
procedure TFormMetaCreateTable.InitMetaProvider;
begin
if not Assigned (metaProv) then
begin
metaProv := TDBXDataExpressMetaDataProvider.Create;
metaProv.Connection := SqlConnection1.DBXConnection;
metaProv.Open;
end;
end;
MetaDataTable := TDBXMetaDataTable.Create;
MetaDataTable.TableName := edTableName.Text;
MetaDataTable.AddColumn(
TDBXInt32Column.Create('id'));
MetaDataTable.AddColumn(
TDBXDecimalColumn.Create('amount', 10, 2));
MetaDataTable.AddColumn(
TDBXUnicodeCharColumn.Create('city', 32));
metaProv.QuoteIdentifierIfNeeded('');
metaProv.CreateTable(MetaDataTable);
Log ('Table ' + MetaDataTable.TableName + ' created');
end;
for str in sl do
begin
Log (str);
end;
finally
sl.Free;
end;
end;
dbxTable := metaProv.GetCollection (
TDBXMetaDataCommands.GetTables)
as TDBXTablesTableStorage;
while dbxTable.Next do
if not (dbxTable.TableType = 'SYSTEM TABLE') then
Log (dbxTable.TableName);
end;
dbxTable := metaProv.GetCollection (
TDBXMetaDataCommands.GetColumns + ' ' +
edTableName.Text) as TDBXColumnsTableStorage;
while dbxTable.Next do
Log (dbxTable.ColumnName +
' [' + dbxTable.TypeName + ']');
end;
Controles Data-Aware
Al primer vistazo, teniendo en cuenta los controles de datos
de la VCL, le puede parecer que hay muy pocos cambios. En
efecto, es cierto que se han limitado las nuevas características,
si no considera el hecho de que todos los controles de datos
están habilitados para Unicode.
También vimos en el último capítulo cómo crear un control
“navegador” de base de datos basado en el control Ribbon. Sin
embargo, sería bueno tener algunas de las características que
A continuación
Este capítulo me centre en las nuevas características de arqui-
tectura para base de datos de Delphi, una parte importante de
la VCL, tanto en términos de tamaño como en importancia.
149Por lo menos durante algún tiempo, no está claro si la oferta tendrá una dura-
ción indefinida.
Capitulo 12:
DataSnap 2009
Construyendo la primera
demostración de
La guía de Delphi por Marco Cantù | para
Indice - 451
DataSnap 2009
Antes de entrar en detalles, permitame que comience por una
demostración orientada a datos en el modelo “tres capas”.
Esto ayudará a aclarar algunos puntos y también a ilustrar las
diferencias con las versiones previas de la tecnología.
Construyendo el servidor
El primer paso es construir una aplicación servidora DataS-
nap 2009. Esta puede ser una aplicación estándar VCL, a la
cual añadimos un módulo de servidor (que se puede encon-
trar en la página “Delphi Files” en el diálogo “New Items”).
Al módulo de servidor (aunque también podríamos haber
usado un “Data Module” estándar) generalmente añadimos
los componentes dbExpress para conectar al servidor de base
de datos, además de un “DataProvider” para exponer los “Da-
taSets” dados:
object IBCONNECTION: TSQLConnection
ConnectionName = 'IBCONNECTION'
DriverName = 'Interbase'
LoginPrompt = False
Params.Strings = (
'DriverName=Interbase'
'Database=C:\Program Files\...\Data\Employee.GDB')
end
object EMPLOYEE: TSQLDataSet
CommandText = 'EMPLOYEE'
CommandType = ctTable
SQLConnection = IBCONNECTION
end
object DataSetProviderEmployee: TDataSetProvider
DataSet = EMPLOYEE
end
El primer cliente
Ahora que tenemos el servidor disponible, podemos continuar
y construir el primer cliente. En la aplicación cliente DataS-
nap 2009 necesitamos un componente SQLConnection aso-
ciado con el nuevo driver DataSnap dbExpress, configurado
con el puerto TCP/IP.
A continuación necesitamos un componente , usado para
identificar la clase de servidor, con la propiedad . Esta no es
una clase intermediara a la fábrica de clases del servidor
Precision = 2000
Name = 'ReturnParameter'
ParamType = ptResult
Size = 2000
Value = 'Hello from TDSFirst3TierServerModule...'
end>
SQLConnection = SQLConnection1
ServerMethodName = 'TDSFirst3TierServerModule.GetHello'
end
151Hay
una demo sobre las clases a bajo nivel de dbExpress en la sección “Utili-
zando las clases de DBXCommon” en el capítulo 10 de mi libro Delphi 2007
Handbook.
function TSimpleServerClass.SlowPrime(
MaxValue: Integer): Integer;
var
I: Integer;
begin
// counts the prime numbers below the given value
Result := 0;
for I := 1 to MaxValue do
begin
if IsPrime (I) then
Inc (Result);
end;
end;
type
TStorageServerClassClient = class
public
procedure SetValue(Value: Integer);
function GetValue: Integer;
function ToString: string;
152Los tres valores para esta propiedad son tres constantes de la clase
TDSLifeCycle definida en la unidad DSNames.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 467
procedure TFormDsnapMethodsServer.DSServerClass2GetClass(
DSServerClass: TDSServerClass;
var PersistentClass: TPersistentClass);
begin
DSServerClass2.LifeCycle := ParamLifeCycle;
Log ('LifeCycle: ' + DSServerClass2.LifeCycle);
PersistentClass := TStorageServerClass;
end;
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 469
begin
InitStorageServer;
Result := StorageServer.ToString;
end;
Gestión de memoria
La gestión de la memoria de los objetos de servidor está ligada
a las conexiones cliente y al ciclo de vida del servidor. Los ob-
jetos de servidor se mantienen en memoria generalmente
hasta que la conexión (Session) se cierra o hasta que el servi-
dor se cierra (Server) aun a pesar de cualquier conexión ac-
tiva.
La situación es diferente con el ciclo de vida Invocation, ya
que en este caso el objeto de servidor (TStorageServerClass en
el ejemplo) se crea en cada invocación y debería ser inmedia-
tamente destruido. Lo que ocurre, sin embargo, es que (in
Delphi 2009 con el Update 1 instalado) para cada invocación
de un método de servidor hay una pérdida con cada objeto de
servidor. Por ejemplo, usando el ciclo Invocation, creando
una conexión de cliente y llamando al método de servidor dos
veces, se produce el siguiente error cuando el servidor se cie-
rra:
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 471
Gestión de hilos
Otro tema relacionado es la gestión de hilos en el servidor (y
en algunos casos en el cliente). El gestor de hilos es el compo-
nente de transporte TCP/IP, el cual puede usar un “pooling”
de hilos para mejorar la eficiencia de la llamada. Se puede
configurar el “pooling” de hilos de servidor usando la propie-
dad PoolSize del componente de transporte del servidor (y es-
tablecer un límite de hilos usando la propiedad MaxThreads).
De acuerdo con la documentación (en el código fuente, no en
el fichero de ayuda) el valor de la propiedad PoolSize debe ser
10 por defecto, pero parece como si esta estuviera establecida
a 0 por defecto, lo que deshabilita el “pooling” de hilos. Esta-
blécela al valor que desees, pero no a 10 ya que sería reinicia-
lizada por un aparente error en la definición del compo-
nente154.
Los hilos en el servidor se crean según una base por conexión
y no por petición, y se mantienen mientras las conexiones es-
tán abiertas. Esto significa que el modelo de “pooling” de hilos
y la configuración requieren adaptarse a la configuración de
155Bien,el hecho de que las llamadas concurrentes del cliente usen una única co-
nexión es la teoría, como informa la limitada documentación disponible. En
la práctica, si trata de invocar al servidor usando hilos, y se realiza una se-
gunda petición antes de que la primera se complete, el servidor encolará las
peticiones, por lo menos cuando se está usando el ciclo de vida sesión. Vere-
mos un ejemplo más adelante sobre ello en esta sección.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 473
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 475
Portando un ejemplo
anterior de DataSnap
Habiendo explorado algunas alternativas de uso de DataSnap
2009, permítaseme volver a un escenario de uso más clásico,
que son las aplicaciones de datos “multi-capa”. Como ya he-
mos podido ver los pasos para crear una nueva aplicación de
datos, vamos a centrarnos en un elemento igual de relevante:
portar una aplicación DataSnap (o MIDAS) a esta nueva ar-
quitectura.
Como ejemplo práctico, he decidido portar la aplicación lla-
mada ThinPlus156 que se recogía en Mastering Delphi 2005, la
cual muestra algunas de las capacidades de DataSnap, y que
me permitirá cubrir un ejemplo más completo, además de en-
focarnos en lo necesario para portar un servidor COM invo-
cado desde un cliente usando un “socket” a lo que es una ar-
quitectura puramente “socket”. El nuevo ejemplo (con los
proyectos del servidor y del cliente) se encuentra en la carpeta
ThinPlus2009.
Nótese que portar aplicaciones DataSnap a la nueva arquitec-
tura es una opción interesante, pero no debe ser obligatoria.
Portar el servidor
Para portar el servidor he seguido estos pasos:
Quité la sección de inicialización de la unidad de “remote data
module” llamada AppsRDM. El código sustraído fue la lla-
mada al constructor de la clase TComponentFactory.
También quité el método de clase UpdateRegistry de la clase
TAppServerPlus de la misma unidad.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 477
Actualizando el cliente
Portar la aplicación cliente a DataSnap 2009 es generalmente
más fácil que portar el servidor. El paso fundamental es quitar
los componentes de conexión (el ejemplo tiene tres, ya que
permite a los usuarios experimentar con varias opciones de
conexión) y reemplazarlos con una conexión “SQLConnec-
tion” y un DSProviderConnection, y referir el componente
ClientDataSet a este nuevo componente de conexión remota.
El único código específico que he tenido que cambiar fue la
llamada al método Login del servidor. Esto tiene lugar en el
OnAfterConnection de la conexión, moviéndose ahora al
evento correspondiente del componente “SQLConnection”:
procedure TClientForm.SQLConnection1AfterConnect(
Sender: TObject);
begin
// was: ConnectionBroker1.AppServer.
// Login (Edit2.Text, Edit3.Text);
SqlServerMethod1.ParamByName('Name').AsString :=
Edit2.Text;
SqlServerMethod1.ParamByName('Password').AsString :=
Edit3.Text;
SqlServerMethod1.ExecuteMethod;
end;
Características avanzadas de
ThinPlus2009
He actualizado las aplicaciones cliente y servidor de ThinPlus
a DataSnap 2009 siguiendo los pasos mencionados anterior-
mente, incluso aunque estos sean programas DataSnap bas-
tante más complicados y con diversas personalizaciones. Esto
incluye la transmisión de paquetes de datos manualmente,
usando estructuras maestro/detalle, ejecutando consultas pa-
rametrizadas, transfiriendo datos extra en los paquetes de da-
tos y la validación de usuario ya tratada.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 479
end
end
object cdsDet: TClientDataSet
DataSetField = cdsSQLEmployees
end
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 481
procedure TAppServerPlus.
ProviderQueryGetDataSetProperties(Sender: TObject;
DataSet: TDataSet; out Properties: OleVariant);
begin
Properties := VarArrayCreate([0,1], varVariant);
Properties[0] := VarArrayOf(['Time', Now, True]);
Properties[1] := VarArrayOf([
'Param', SQLWithParams.Params[0].AsString, False]);
end;
El interfaz administrativo
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 483
de DataSnap
Cuando se escribe un servidor DataSnap 2009, se puede eje-
cutar y conectar con el IDE en tiempo de diseño con el fin de
ayudar a escribir el código de cliente. Esta ayuda se materia-
liza en listas de los métodos y proveedores disponibles y tam-
bién en términos de generación de las clases proxy. Para lo-
grar esto cada servidor tiene un interfaz extra, llamado inter-
namente DSAdmin. En un servidor en producción se puede
deshabilitar, para evitar que otros escriban aplicaciones
cliente usando Delphi (o al menos hacérselo más difícil). Esto
se logra cambiando el valor de la propiedad HideDSAdmin en
el componente DSServer lo que generalmente está recomen-
dado cuando se despliega una aplicación.
Si el interfaz DSAdmin157 está activo, se puede usar para ex-
plorar el servidor dinámicamente. He escrito un ejemplo lla-
mado “bare-bones” que hace exactamente eso. Puede ser am-
pliado aportando un interfaz genérico de llamada e incluso
dejándole generar clases proxy extendidas.
El programa tiene un SQLConnection que conecta con un ser-
vidor disponible. Se podría querer personalizar el código para
conectar al servidor disponible en una IP y puertos dados (el
ejemplo usa los valores por defecto, escritos en código). Para
probar esta aproximación, he llamado inicialmente el método
GetPlatformName, usando un componente SqlServerMethod
configurado como:
object smGetPlatformName: TSqlServerMethod
GetMetadata = False
Params = <
item
157Para más información acerca del interfaz DSAdmin puede dirigirse a la clase
DSAmin (sin T al comienzo) en la unidad DSCommonServer.
DataType = ftWideString
Precision = 2000
Name = 'ReturnParameter'
ParamType = ptResult
Size = 2000
end>
SQLConnection = SQLConnection1
ServerMethodName = 'DSAdmin.GetPlatformName'
end
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 485
Otra vez este ejemplo solo aporta una idea de lo que se puede
hacer usando el interfaz administrativo de DataSnap. Otros
métodos del interfaz DSAdmin le permitirán devolver los pa-
rámetros de los métodos y otros elementos. Finalmente se
puede usar un componente SqlServerMethod y establecer su
nombre y parámetros dinámicamente para invocar un método
de servidor.
Conclusión
En este capítulo he cubierto una de las más significativas ac-
tualizaciones en términos de la librería de componentes de
Delphi 2009, la nueva arquitectura DataSnap para construir
aplicaciones “multi-tier” sin tener que recurrir a COM. Se
puede usar DataSnap 2009 para la programación orientada a
bases de datos pero también para invocar fácilmente métodos
de servidor.
Ya que este es el último capítulo del libro, no hay sección “A
continuación” solo una pequeña conclusión acerca del pro-
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 487
Indice
1995 ..................................................................................................................................... 13
211 ..................................................................................................................................... 391
Acción del diálogo de fuente............................................................................................. 333
Acciones ............................................................................................................................ 329
Acciones estándar ............................................................................................................. 332
Action ................................................................................................................................330
Action Manager ......................................................................................................291, 331p.
ActionItem ........................................................................................................................340
ActionLink ........................................................................................................................330
ActionList.......................................................................................................................... 331
ActionManager ................................................................................................................. 331
Actions .............................................................................................................................. 327
Active Form ...................................................................................................................... 319
ActiveX Control Wizard .................................................................................................... 319
ActMan.............................................................................................................................. 342
AddRecentItem ................................................................................................................. 335
AJAX .......................................................................................................................... 217, 221
Alertas de Conversión de Cadenas ..................................................................................... 94
Alineación ......................................................................................................................... 277
Allen Bauer ....................................................................................................................... 213
Anders Melander ............................................................................................................. 300
AnsiChar ......................................................................................46, 48, 50, 73, 75, 90p., 93
AnsiString ............................................................................................................... 52p., 58p.
AnsiStrings........................................................................................................... 102pp., 264
AnsiStrings unit ................................................................................................................ 263
Application................................................................................................................ 297, 304
ApplicationMenu ..............................................................................................................344
Apply Option Set............................................................................................................... 130
Archivos DFM ..................................................................................................................... 86
Asistentes de Componentes............................................................................................... 141
Associate ........................................................................................................................... 348
AsString ....................................................................................................................362, 368
BabelFish ............................................................................................................................ 76
BackgroundColor .............................................................................................................. 287
BalloonHint ...................................................................................................................... 269
BarColor ............................................................................................................................ 287
Barry Kelly ................................................................................................................. 187, 195
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 489
ColorDepth .......................................................................................................................302
Columns ............................................................................................................................340
COM .......................................................................................................................307, 393p.
ComboBox................................................................................................................ 280, 305
CommandLinkHint .......................................................................................................... 273
CommandProperties ..................................................................................................... 341p.
CommandStyle ................................................................................................................. 333
CommandType ................................................................................................................. 337
Common User Access ....................................................................................................... 323
Compilador de Recursos .................................................................................................. 136
Compilador de Recursos de Borland................................................................................ 136
Compiler directive ..................................................................................................................
INLINE ........................................................................................................................ 122
M .................................................................................................................................. 123
MethodInfo.................................................................................................................. 394
POINTERMATH ......................................................................................................... 109
STRINGCHECKS ........................................................................................................ 124
VARPROPSETTER ...................................................................................................... 229
Z ................................................................................................................................... 123
$HIGHCHARUNICODE ............................................................................................... 76
$STRINGCHECKS ........................................................................................................ 69
Compiler option ......................................................................................................................
--string-checks ...............................................................................................................68
-$M .............................................................................................................................. 123
-$Z ............................................................................................................................... 123
ConnectionData ................................................................................................................ 375
ConnectionName .............................................................................................................. 374
ConnectionString .............................................................................................................. 374
Construcción de Configuraciones .................................................................................... 129
Construct .......................................................................................................................... 176
Contnrs .......................................................................................................................171, 177
Control de cuentas de usuario .......................................................................................... 315
Conversión de Cadenas ...................................................................................................... 65
ConvertFromUtf32 ....................................................................................................... 50, 56
CreatePanel ....................................................................................................................... 293
Cuenta de referencia ........................................................................................................... 53
CustomHint .............................................................................................................. 269, 271
CustomizeDlg.................................................................................................................... 331
Danysoft ............................................................................................................................ 387
Danysoft ............................................................................................................................ 1p.
Danysoft. ..............................................................................................................................17
DataSetProvider ....................................................................................................... 392, 418
DataSnap ............................................................................................................... 389p., 416
DBError ............................................................................................................................ 257
DbExpress ........................................................................................................ 373, 380, 394
DBGrid ................................................................... 345, 357, 365, 367, 386, 392, 414p., 418
DBImage ...........................................................................................................................386
DBNavigator ..................................................................................................................... 344
Dbxdrivers.ini ................................................................................................................... 377
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 491
ButtonsDemo............................................................................................................... 273
CategoryPanels ............................................................................................................ 293
CharTest ........................................................................................................... 50p., 90p.
CharTroubles ................................................................................................................. 92
CheckBoxHeader ........................................................................................................ 288
ClassContraint ............................................................................................................. 162
CustomEncoding ........................................................................................................... 84
CustomerDictionary .................................................................................................... 178
CustomFields ............................................................................................................... 365
DataRibbon ................................................................................................................. 345
DbEditPlus .................................................................................................................. 385
DbxMulti2009 ..................................................................................................... 373, 378
DfmTest ......................................................................................................................... 86
DsnapMethods ................................................................................................... 403, 407
DsnapMethodsClient.................................................................................................. 408
DsnapMethodServer ................................................................................................... 399
EditFamilyDemo ................................................................................................ 278, 280
ExceptionsTest ................................................................................................. 257p., 261
First3Tier2009 ............................................................................................................ 396
GenericCodeGen.......................................................................................................... 156
GenericInterface ....................................................................................................... 182p.
GenericTypeFunc ..................................................................................................... 159p.
GraphicsTest....................................................................................................... 300, 302
GraphicTest ................................................................................................................. 299
GroupingList ............................................................................................................... 285
HighCharTest ................................................................................................................ 75
HintsDemo ............................................................................................................ 269pp.
IntfConstraint ............................................................................................ 164, 167p., 183
IntfContraints .............................................................................................................. 182
KeyValueClassic .......................................................................................................... 148
KeyValueGeneric ...................................................................................................... 150p.
LabelsDemo ................................................................................................................. 275
LatinTest ............................................................................................................... 59, 61p.
ListDemoMd2005 .................................................................................................... 172p.
ListMonitor..................................................................................................................242
MiniPack ........................................................................................................................ 85
MiniSize ......................................................................................................................... 85
MinorLang ..............................................................................................................226pp.
MoveStrings................................................................................................................ 96p.
MyTrayIcon ................................................................................................................. 296
MyTrayIconClick ......................................................................................................... 296
PlainTips ...................................................................................................................... 349
PointerMath ................................................................................................................ 107
PointerMathD2007 ......................................................................................................110
ProjManagerTest .................................................................................................. 127, 131
RadioGroupDemo ....................................................................................................... 277
RawTest ..........................................................................................................................71
ReaderWriter ....................................................................................................... 252, 254
ResourceTest ............................................................................................................ 134p.
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 493
GetCategoryPanelClass..................................................................................................... 295
GetCollection .................................................................................................................... 383
GetFieldsList ..................................................................................................................... 359
GetHashCode .................................................................................................................... 236
GetNextPacket .................................................................................................................. 415
GetPlatformName............................................................................................................. 417
GetPreamble ....................................................................................................................... 77
GetProcAddress ........................................................................................................ 105, 404
GetServerClasses .............................................................................................................. 418
GetServerMethods ............................................................................................................ 419
GetTableNames ................................................................................................................ 381
GetTickCount .................................................................................................... 209, 214, 243
GetTypeName ................................................................................................................... 159
GetUserName ..................................................................................................................... 39
GetWindowText .................................................................................................................. 36
GIF ................................................................................................................................ 300p.
GlassFrame .......................................................................................................................304
GlowSize ................................................................................................................... 275, 305
GlyFX ................................................................................................................................ 301
Google ............................................................................................................................... 210
GridPanel .......................................................................................................................... 294
GroupAlign .......................................................................................................................340
GroupHeaderImages ........................................................................................................284
GroupPosition................................................................................................................... 341
Groups ..............................................................................................................................284
GroupView ........................................................................................................................284
Grupo de Google ................................................................................................................. 18
Gustavo Daud .................................................................................................................. 300
HeaderControl ................................................................................................................. 288
Helper ................................................................................................................................. 81
HideDSAdmin................................................................................................................... 417
Hint ................................................................................................................................... 271
HRESULT ......................................................................................................................... 314
HTML........................................................................................................................ 276, 320
HTTP ................................................................................................................................. 218
IAppServer ............................................................................................... 394, 396, 398, 400
IComparer<T>................................................................................................... 173, 175, 184
ID de interfaz .................................................................................................................... 182
IdHttp ............................................................................................................................... 210
IDL ................................................................................................................................... 308
IEqualityComparer<T> .................................................................................................... 184
ImageList ......................................................................................................... 284, 299, 332
Images ............................................................................................................................... 332
Implicit ..................................................................................................................... 189, 232
Indy ............................................................................................................................210, 217
InfoPower Grid Essentials ................................................................................................ 387
InnerException ...................................................................................................256p., 259p.
Instalacion ......................................................................................................................... 116
InstallAware....................................................................................................................... 116
La guía de Delphi por Marco Cantù | para
Indice - 495
Move ................................................................................................................................... 96
MoveBy ............................................................................................................................. 363
MSBuild ......................................................................................................................... 118p.
MultiByteToWideChar .......................................................................................................60
NewRow ............................................................................................................................ 341
NumbersOnly ........................................................................................................... 278, 385
Número primo .................................................................................................................. 213
Office 2007 ....................................................................................................................... 324
Office Fluent UI ................................................................................................................ 325
OnAccept........................................................................................................................... 336
OnAfterConnection............................................................................................................ 411
OnBalloonClick ................................................................................................................. 296
OnClose .............................................................................................................................404
OnConnect ........................................................................................................................ 392
OnCreateInstance .............................................................................................................403
OnDestroyInstance .................................................................................................. 403, 406
OnDisconnect ................................................................................................................... 392
OnExecute.........................................................................................................................330
OnGetDataSetProperties .................................................................................................. 416
OnItemChecked ................................................................................................................286
OnLinkClick ...................................................................................................................... 276
OnMouseEnter .................................................................................................................270
OnSectionCheck ...............................................................................................................289
Opciones de Configuración .............................................................................................. 129
Open Arrays ....................................................................................................................... 111
Ordenando ........................................................................................................................ 173
Overloading ......................................................................................................................230
PacketRecords .................................................................................................................. 414
Paleta de Herramientas .................................................................................................... 140
Panel ................................................................................................................................. 292
PAnsiChar ............................................................................................................. 36, 46, 105
Parámetros Variants .......................................................................................................... 111
ParentCustomHint ........................................................................................................... 269
ParentDoubleBuffered......................................................................................................268
ParentFont ........................................................................................................................ 297
PasswordChar ................................................................................................................... 278
PByte ..........................................................................................................................109, 371
PChar .................................................................................................... 40, 46, 105, 107, 109
Peek ................................................................................................................................... 254
Philippe Kahn ................................................................................................................... 147
PInteger .................................................................................................................... 107, 109
PNG ....................................................................................................................... 300p., 386
Polimorfismos................................................................................................................... 185
PoolSize............................................................................................................................. 407
PopupActionBar ............................................................................................................... 291
PopupActionBarEx ........................................................................................................... 331
Portapapeles .....................................................................................................................303
Potential data loss............................................................................................................... 67
Prime number ................................................................................................................... 399
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 497
ProcessMessages............................................................................................................... 214
ProgressBar............................................................................................................... 287, 305
Project Manager ........................................................................................................ 126, 133
Proportional ......................................................................................................................303
Protección ......................................................................................................................... 385
ProviderName................................................................................................................... 392
Proxy ......................................................................................................................... 179, 396
Puntero Matemático ......................................................................................................... 107
Punteros inteligentes ........................................................................................................ 185
Punto de código .................................................................................................................. 57
Put by ref........................................................................................................................... 229
PWideChar ............................................................................................................ 36, 46, 105
QueryPerformanceCounter ..............................................................................................209
QuickAccessToolbar ......................................................................................................... 344
RadioGroup ..............................................................................................................276, 404
RaiseOuterException ........................................................................................................ 258
RaisingException ..................................................................................................... 260, 262
RawByteString ........................................................................................................ 58, 70, 97
ReadFromFile ..................................................................................................................... 78
RecentItems ...................................................................................................................... 337
Recursos............................................................................................................................ 133
Register ActiveX Server .................................................................................................... 314
Registered Type Libraries ................................................................................................ 315
RemoteServer ................................................................................................................... 392
ReportMemoryLeaksOnShutdown .................................................................................. 188
ResemblesText .................................................................................................................. 103
Resourcestring .................................................................................................................. 137
Restringido IDL ................................................................................................................309
ReverseString.................................................................................................................... 103
Ribbon .......................................................... 326p., 329, 331pp., 338p., 342, 344, 348, 350
RibbonComboBox ............................................................................................................ 343
RibbonSpinEdit ................................................................................................................ 327
RichEdit ....................................................................................................................289, 332
RIDL ............................................................................................................................. 309p.
RightButton ...................................................................................................................... 281
RoundTo ........................................................................................................................... 264
Rows..................................................................................................................................340
Safecall ................................................................................................................ 311, 313, 411
Salidas ...............................................................................................................................228
Screen ...............................................................................................................................298
Screen Tips ....................................................................................................................... 348
ScreenTipsManager .............................................................................................. 348, 350p.
ScreenTipsPopup ........................................................................................................ 348pp.
Server ................................................................................................................................402
ServerClassName .............................................................................................................. 392
ServerMethodName ......................................................................................................... 396
Session ..............................................................................................................................402
Set of Char .................................................................................................................... 47, 90
SetCodePage ...................................................................................................... 55, 59, 66, 71
La guía de Delphi por Marco Cantù
498 - Indice
SetWindowText .................................................................................................................. 39
ShellExecute ..................................................................................................................... 276
ShortString ................................................................................................................. 53, 240
ShowCaption ..................................................................................................................... 292
ShowHelpButton .............................................................................................................. 326
ShowMessage....................................................................................................................298
Sincronización de Procesos ..............................................................................................209
Singleton ........................................................................................................................... 185
SizeOf ......................................................................................................................... 159, 162
SmoothReverse ................................................................................................................. 287
Soporte de Metadatos Extendidos .................................................................................. 380
SQLConnection ................................................................. 374, 379, 381, 392, 394, 400, 417
SqlServerMethod .............................................................................................. 395pp., 417p.
SqlServerMethod150 ........................................................................................................ 396
Stdcall ............................................................................................................................... 314
Steve Tendon .................................................................................................................... 147
StringCodePage ............................................................................................................ 54, 60
StringElementSize .....................................................................................................54p., 60
StringOfChar....................................................................................................................... 93
StringRefCount ................................................................................................................... 54
Style .................................................................................................................................. 273
SupportsPartialTransparency .......................................................................................... 299
Synchronize .............................................................................................................. 210, 409
SyncObjs unit .................................................................................................................... 263
System ......................................................................................... 48, 53, 60, 233p., 242, 263
System unit ....................................................................................................................... 263
System.Object ................................................................................................................... 234
System.Text.Encoding ........................................................................................................ 77
SysUtils .................................................................................. 54, 77, 91, 97, 203, 256, 262p.
SysUtils unit...................................................................................................................... 264
TAction..............................................................................................................................330
TActionClientItem .................................................................................................... 334, 341
TBalloonHint .................................................................................................................... 269
TBasicAction .....................................................................................................................330
TBDXProperties ............................................................................................................... 376
TBitmap ............................................................................................................................ 299
TBlobField ........................................................................................................................ 370
TBookmark ........................................................................................................... 100, 360p.
TButton ............................................................................................................................. 272
TButtonProperties ............................................................................................................342
TButtonStyle ..................................................................................................................... 273
TBytes ................................................................................................................................. 97
TCategoryPanel................................................................................................................. 295
Tcharacter .................................................................................................................. 49, 55p.
TComboBox ..................................................................................................................... 280
TComparer<T> .......................................................................................................174p., 184
TConnectionData .............................................................................................................. 375
TControl .................................................................................................................... 269, 343
TCP/IP ................................................................................................................... 391p., 394
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA
Indice - 499
TCustomAction .................................................................................................................330
TCustomButton ................................................................................................................ 272
TCustomEdit ..................................................................................................................... 385
TCustomHint .................................................................................................................... 269
TDataSet ........................................................................................................... 358pp., 371p.
TDBEdit .................................................................................................................... 359, 385
TDBImage .........................................................................................................................303
TDBXCommand ............................................................................................................... 397
TDBXMetaDataCommands.............................................................................................. 382
TDBXTable ....................................................................................................................... 383
TDictionary<TKey,TValue> .............................................................................................. 171
TDrawingStyle ..................................................................................................................302
TDSServerModule .........................................................................................................394p.
Teclado .............................................................................................................................. 338
Tecnologías Web 2.0 ...........................................................................................................17
TEdit ...................................................................................................................... 277, 279p.
TEditButton ...................................................................................................................... 281
TEncoding............................................................................................................ 64, 77p., 81
TEqualityComparer<T> ................................................................................................... 184
TextHint ................................................................................................... 278, 280, 343, 385
TextOut ........................................................................................................................41, 105
TField ........................................................................................................................358, 368
TFieldDef .......................................................................................................................... 367
TFileStream .............................................................................................................. 106, 253
TFunc<TResult> ..............................................................................................................203
TGraphic ..................................................................................................................... 299pp.
Threading.......................................................................................................................... 241
Threads Status .................................................................................................................. 145
Tiburón ..............................................................................................................................118
TInterfacedObject ............................................................................................................. 182
Tipos de procedimiento .................................................................................................... 193
Tipos Enteros .................................................................................................................... 233
TJPEGImage ..................................................................................................................... 301
TLabel ............................................................................................................................... 275
TLB..................................................................................................................................... 311
Tlibimp.exe .......................................................................................................................309
TList<T> ......................................................................................................................... 171p.
TLookupList...................................................................................................................... 365
TMonitor .................................................................................................................. 242, 402
TObject......................................................................................................................234, 239
TObjectDictionary<TKey, TValue>................................................................................... 177
TObjectList<T> ................................................................................................................. 177
ToString ............................................................................ 234, 237, 246, 257, 259, 401, 405
ToUpper .............................................................................................................................. 50
TParam ............................................................................................................................. 370
TProc .................................................................................................................................203
TQueue<T>........................................................................................................................ 171
TrayIcon ............................................................................................................................ 296
TRecordBuffer ............................................................................................................... 371p.
La guía de Delphi por Marco Cantù
500 - Indice
WideCharToMultiByte ....................................................................................................... 63
WideString ............................................................................................................ 38, 42, 318
WideStrUtils ......................................................................................................... 43, 64, 104
Wikipedia .......................................................................................................................... 324
Win32.................................................................................................................................. 14
Windows 9x ........................................................................................................................40
Windows Vista .................................................................................. 273, 275, 278, 281, 287
Windows XP ................................................ 40, 272, 275, 277p., 280p., 284, 287, 291, 305
WinExec ............................................................................................................................404
WriteToFile ......................................................................................................................... 78
Yorai Aminov .................................................................................................................... 383
ZLib unit ........................................................................................................................... 264
Explorer ........................................................................................................................... 137
Genéricos ......................................................................................................................... 147
puntero............................................................................................................................. 193
.DPROJ ...........................................................................................................................119p.
.OPTSET ............................................................................................................................ 131
.RES .................................................................................................................................. 133
€ .......................................................................................................................................... 75
La guía de Delphi por Marco Cantù | para Desarrollo sistemas integrados control, SA