Boletín Pascal #39
Los ejemplos completos de código fuente de este número están disponibles para descargar.
![]() |
![]() |
Boletín Pascal #39- 13-SEP-2002 Índice 1. Unas palabras del editor 2. En las noticias - Delphi 7 está aquí! - Anticipo del compilador Delphi para .NET - Kylix 3 obtiene 5 estrellas de LinuxPlanet - Eventos Borland que se se avecinan 3. Entendiendo VisualCLX ¿Que son los objetos de enganche (hook-objects) en una aplicación Qt? 4. Creando aplicaciones middleware de alto rendimiento con Indy 5. Inline Assembler en Delphi (III) - Arreglos estáticos 6. Foros / listas de correo 7. Delphi en la Red - Componentes, librerías y aplicaciones . Shareware/Comercial . Freeware - Artículos, trucos y consejos - Tutoriales - Otros enlaces ________________________________________________________________________ Tecno Soft Solutions. Reseller Autorizado de Symbol Technologies, líder mundial en captura de códigos de barras. >>> http://www.tecno-symbol.com ________________________________________________________________________ 1. Unas palabras del editor Antes que nada, quisiera pedir disculpas por la demora en publicar esta edición, pero he estado enterrado en trabajo estas últimas semanas. Espero poder retomar una periodicidad más aceptable a partir del próximo número. Mi sitio web estuvo fuera de línea unos días esta semana, y antes de eso he experimentado algunos problemas con la recepción de mensajes de email. Si alguien ha intendado contarme en este tiempo y no ha recibido respuesta de mi parte, le ruego que vuelva a intentarlo ahora. En esta edición quiero agradecer a Max Kleiner por contribuir otro de sus artículos al boletín, y me complace entregarle una licencia de AnyShape Transpack v2.0 para Kylix, el componente de plataformas cruzadas que facilita la creación de ventanas transparentes y de formas extrañas, con edición WYSIWYG, vista preliminar en tiempo de diseño, arrastre automático, verdaderos formularios "stay-on-top" y la posibilidad de combinar regiones, provisto por MindBlast Software: http://www.mindblastsoftware.com/?page=transpack&ref=PascalNL A propósito, el autor del próximo artículo sobre Kylix que publiquemos recibirá otra licencia de AnyShape Transpack v2.0 para Kylix. También quiero agradecer a Romeo Lefter por su artículo sobre Indy, y me complace entregarle el Delphi Information Library CD (DIL CD), un gran recurso de información con artículos, trucos, consejos, compo- nentes, javascripts, imágenes, update packs, y mucho más, provisto por el UK Borland User Group: http://www.richplum.co.uk/html/dil.asp Para la próxima edición, tenemos los siguientes premios disponibles: * llPDFLib v1.1 - por llionsoft, Shareware ($70, $280 con fuentes) llPDFLib en una biblioteca en puro Object Pascal para crear documentos PDF. No usa ninguna DLL ni software externo de terceras partes para generar ficheros PDF. La librería consiste del componente TPDFDocument con propiedades y métodos como los del TPrinter de Delphi, pero diseñado para generar un fichero PDF. http://www.llion.net/ * Greatis Form Designer v3.4 - por Greatis Software, Shareware ($49.95) Es un diseñador de formularios en tiempo de ejecución que le permite mover y cambiar el tamaño de cualquier control de su formulario. No necesita preparar su formulario para usar Form Designer. Simplemente suelte el componente TFormDesigner en cualquier formulario, establezca la propiedad Active en True y ¡disfrute! Para Delphi 4-7 y BCB 3-6. http://www.greatis.com/formdes.htm * Developer Information Library (DIL) CD - por UK Borland User Group Más de 17.000 trucos, consejos, FAQs y artículos técnicos · Parches y actualizaciones de las herramientas Borland · Más de 4.000 componentes y herramientas · Más de 4.000 bitmaps listos para usar con otros 20.000 comprimidos · Más de 350 JavaScripts listos para usar · Juego completo de HOWTOs de Linux · y mucho más... http://www.richplum.co.uk/html/dil.asp Finalmente, no quiero olvidarme de agradecer al Ing. Ernesto Cullen, ni a Dave Murray, quienes colaboraron para hacer esta edición posible. Espero que la disfruten. Saludos, Ernesto De Spirito eds2004 @ latiumsoftware.com ________________________________________________________________________ JfControls Lib. Multilenguaje. Multiapariencia. Skins. Privilegios. Más de 40 componentes integrados y personalizables. Múltiples problemas de programación resueltos. Administración centralizada de recursos. Para Delphi 3-7 y C++ Builder 3-6. http://www.jfactivesoft.com/spindex.htm ________________________________________________________________________ 2. En las noticias Delphi 7 está aquí! =================== Delphi 7 está entre nosotros, llamado Delphi 7 Studio, y viene en cuatro ediciones: * Delphi 7 Studio Architect ($3,499 - Upgrade desde Enterprise: $2,399) http://www.borland.com/delphi/architect/index.html * Delphi 7 Studio Enterprise ($2,999 - Upgrade: $1,899) http://www.borland.com/delphi/delphi_enterprise/index.html * Delphi 7 Studio Professional ($999 - Upgrade: $399) http://www.borland.com/delphi/delphi_professional/index.html * Delphi 7 Studio Personal ($99 - disponible para descarga gratuita) http://www.borland.com/delphi/delphi_personal/index.html La nueva edición Architect es como la edición Enterprise, pero viene con herramientas adicionales, incluyendo el nuevo Bold para Delphi de BoldSoft, que permite a los desarrolladores mantener menos código con verdadero MDA, y además viene con tecnología UML, soporte integrado para Rational Rose, ModelMaker, importación/exportación de información de modelos desde/hacia el Bold Model Editor, y generación automática de esquema de base de datos usando SQL. DataSnap (antes conocido como MIDAS) es ahora libre de regalías tanto en la edición Enterprise como en la Architect, y también se incluye en la edición Professional. Excepto en el caso de la edición Personal, todas las ediciones de Delphi 7 Studio incluyen el entorno Kylix 3 para Delphi (permitiendo a los desarrolladores usar una base de código para el desarrollo multiplataforma para Linux) y el Delphi 7 Studio Migration Kit (para migrar aplicaciones a Microsoft .NET). Enlaces Delphi 7: * Página principal http://www.borland.com/delphi/architect/index.html * Requerimientos de sistema http://www.borland.com/delphi/pdf/del7_sysreqs.pdf * Preguntas frecuentes http://www.borland.com/delphi/pdf/del7_faq.pdf * Matriz de características http://www.borland.com/delphi/pdf/del7_feamatrix.pdf * Delphi 7/.NET User Group Tour 2002 - US / Canada http://bdn.borland.com/article/0,1410,29089,00.html Anticipo del compilador Delphi para .NET ======================================== Incluido con Delphi 7, pueden encontrar una presentación preliminar del compilador Delphi para .NET, una utilidad en línea de órdenes llamada "dccil.exe", que produce aplicaciones CIL (Common Intermediate Language) que pueden correr en cualquier lugar donde el runtime de .NET esté disponible. Esto significa que las aplicaciones Delphi ahora pueden ir más allá de su tradicional plataforma Windows/Intel hacia otras plataformas que tengan un runtime .NET, como las .NET Compact Framework disponibles para Tablet PCs, teléfonos, y PDAs. * Delphi for .NET compiler preview - Por John Kaster Una primera mirada a las características del compilador Delphi para .NET y la nueva sintaxis del lenguaje Delphi http://bdn.borland.com/article/0,1410,28972,00.html * Delphi for .NET Preview: Samples Este sitio web provee aplicaciones de ejemplo para el compilador preliminar Delphi for .NET. Dichas aplicaciones son producidas por miembros de la comunidad Borland y del plantel de Borland. http://dotnet.borland.com * Usando Delphi como lenguaje para scripting con ASP.NET - por John Kaster Una vista previa del soporte para Delphi for .NET dentro de ASP.NET http://bdn.borland.com/article/0,1410,28974,00.html Kylix 3 obtiene 5 estrellas de LinuxPlanet ========================================== * Kylix 3: Borland's Linux Delphi and C++ RAD is a Winner - Por Steven J. Vaughan-Nichols "Ahora, sin embargo, Kylix responde las necesidades de la mayoría de los programadores Linux al soportar completamente C++ con el mismo entorno de desarrollo. El resultado es un RAD que rápidamente debería convertirse en el más popular entorno integrado de desarrollo (IDE) para Linux." http://www.linuxplanet.com/linuxplanet/reviews/4427/1/ * Taking Kylix 3 for a test drive - Por Joe Barr "En resumen, Kylix 3 me ha permitido desarrollar esta simple aplicación C++ GUI para X en tan sólo unos pocos días. Considerando la escasa experiencia en C++ y desarrollo para X que poseo, y el hecho que nunca trabajé antes con tuberías (pipes) excepto desde la línea de órdenes, es un tiempo muy bueno. Kylix me ha demostrado que merece su etiqueta de RAD." http://www.idg.net/go.cgi?id=738304 Eventos Borland que se se avecinan =================================== * Entwickler Konferenz (EKON6), Morfeldfen/Frankfurt (Alemania), 22-27 de septiembre de 2002 Deutsch - http://www.entwicklerkonferenz.de/ English - http://www.entwicklerkonferenz.com/ * BorCon Europe, Londres (Reino Unido), 28-29 de octubre de 2002 http://www.borconeurope2002.com/ * BorCon Japan, Tokyo (Japón), 19-20 de noviembre de 2002 http://www.borland.co.jp/ * BorCon France, París (Francia), 21-22 de noviembre de 2002 http://info.borland.fr/conference/2002/ ________________________________________________________________________ IBAdmin 3.22 - Complete Interbase SQL tool - Una poderosa herramienta de administración y desarrollo para manejar servidores y bases de datos Interbase. IBAdmin provee muchas capacidades para ayudarle en el diseño y gestión de su base de datos. Diseñe visualmente la estructura de su BD con el "Database Designer", administre usuarios y permisos con el "Grant Manager", o emplee el "SQL Debugger" para depurar procedimientos almacenados y triggers. Disfrute de una edición confortable de código con Code-Insight y Code Completion. >> http://www.sqlly.com/ibadmin2.htm ________________________________________________________________________ 3. Entendiendo VisualCLX ¿Que son los objetos de enganche (hook-objects) en una aplicación Qt? Por Max Kleiner <max @ kleiner.com> Kleiner Kommunikation http://max.kleiner.com/ Traducido por Ernesto Cullen VisualCLX es la parte de la librería CLX que representa los componentes visuales que normalmente residirían en la jerarquía de TWinControl en la VCL. El marco de trabajo VisualCLX (VisualCLX framework) es un conjunto de clases que representan controles visuales que tienen que trabajar (en la medida de lo posible) tanto en MS Windows como en el X de Linux. Los controles representados por los componentes VisualCLX son implementados por una librería de clases en C++ llamada Qt y "widgets" (N. de T.: los "widgets" en Linux son el equivalente a los controles en Windows), de la compañía de desarrollo noruega llamada Trolltech. Qt también está disponible para Windows. La clase VCL TWinControl se llama TWidgetControl ================================================ Qt es una librería de clases en C++, y debido a las diferencias entre C++ y OP (Object Pascal), un programa OP no puede manipular directamente widgets Qt. En cambio, VisualCLX hace uso de una librería adicional, llamada Librería de Interfaz Qt (Qt Interface Library), escrita en C++, como libqtintf.so, que exporta toda la funcionalidad de Qt en una forma que es accesible al código OP. La unidad de importación para esta librería de interfaz se llama Qt.pas, pero esto significa que en lugar de ser declarados como clases, los métodos de los widgets Qt son todos importados como métodos "planos": estrictamente hablando, procedimientos y funciones comunes. Definimos como método "plano" a un método de una clase que se declara como una subrutina o función independiente. No obstante, dado que del lado de C++ son realmente clases, casi todos los métodos planos toman un parámetro adicional que es la referencia al widget Qt. Ud. puede pensar que esto ralentizaría las aplicaciones, pero generalmente no percibirá diferencia alguna en el comportamiento en tiempo de ejecución. Entonces, ¿cuál es la diferencia en lo arquitectónico? En una aplicación OP, llamaríamos a los métodos a través de referencias de objetos, por ejemplo: myButton.setBounds(15, 15, 65, 35); Al convertir este método en un método plano, la referencia al objeto se pasa como el primer parámetro de tal manera que el código del método conozca la instancia que debería invocar. El siguiente es un ejemplo "es-casi-igual-a-esto" de un método plano, equivalente al método usado antes: QButton_SetBounds(myButton, 15, 15, 65, 35); o en una manipulación de Qt, en Kylix: uses Qt, QTypes; var Btn: QButtonH; Btn := QButton_create(Handle, PChar('Btn')); QButton_setGeometry(Btn, 15, 15, 65, 35); Por supuesto, normalmente Ud. no tendría necesidad de escribir código como éste ya que QButton lo hace por Ud., pero sirve como un ejemplo simplificado de como los componentes CLX hacen su trabajo usando la CLXDisplayAPI. Qué es la CLXDisplayAPI ------------------------ CLXDisplay API es el nombre oficial de la unidad Qt.pas que viene con Kylix y también con Delphi 6 y posteriores. Actúa como una unidad de importación para la librería de widgets Qt usada por VisualCLX. Pero en la vida real el tema es un poco más complicado. Qt es una librería de clases C++, y OP no puede manipular directamente clases C++. Debido a esto, Borland escribió una librería adicional para que intermedia entre una aplicación CLX y la librería Qt. Esta librería extra se llama libqtintf.so (librería de interfaz Qt), y Qt.pas es en realidad la unidad de importación para esta librería de interfaz. TWidgetControl ---> Qt.pas ---> libintf.so ---> Qt_Widget_Classes Entendiendo el mecanismo Señal/Ranura (Signal/Slot) --------------------------------------------------- Un objeto de enganche o enlace (hook object) es un objeto C++ que existe en la librería de interfaz Qt como un intermediario. De manera que si Ud. quiere modificar la reacción de un widget como lo haría en Windows con manejadores de eventos, las señales y ranuras juegan el siguiente papel: - Una señal (evento) llega desde un widget - Una ranura (manejador de evento) responde a una señal Como hemos aprendido, no es posible tener la ranura escrita directamente en OP, significando que la librería de interfaz Qt define una clase de enlace (hook class) para cada clase de widget. La clase de enlace implementa una ranura simple para cada señal disponible en un widget, cuyo único propósito es llamar algún código en nuestra aplicación Kylix. Más sobre señales/ranuras y la manera en que Kylix maneja eventos ----------------------------------------------------------------- Como hemos visto, los mensajes (funciones callback) no son la forma de hacer las cosas en CLX; pero esto no significa que CLX no provea soporte para mensajes, sólo que no es la manera que tiene Kylix de hacer las cosas. Sugerimos, por ejemplo para movimientos del ratón, que deje a Kylix responder al ratón y simplemente sobrescriba los métodos que CLX usa para esos eventos. Si Ud. crea un componente y necesita capturar los mensajes del ratón, puede usar el método siguiente: procedure MouseMove(shift: TShiftState; X, Y: integer); override; Debemos acostumbrarnos a pensar que en Qt los desarrolladores no responden directamente a los mensajes. En su lugar, trabajan con el mecanismo de señales/ranuras y una función de conexión como la siguiente: QObject::connect(timer, SIGNAL(timeout)), SLOT(timerSlot())); timer -> start(1000); U otro ejemplo para irse acostumbrando: QObject::connect(myslider, SIGNAL(sliderMoved(in)), mylcdNumber, SLOT(display(in))); No hay nada especial acerca de los métodos SliderMoved y Display. Son sólo métodos ordinarios de C++ que están marcados como señales y ranuras, tal como algunos métodos en Kylix se marcan como virtuales. QObject es la clase base en Qt, de la misma manera que TObject es la clase base en OP (Object Pascal). QObject tiene un método de clase llamado Connect. Un método de clase de OP es la misma cosa que un método estático en C++ o Java. En particular, se puede invocar un método de clase sin crear primero una instancia (objeto) de esa clase. ¿Y dónde está el bucle de eventos en Kylix? En el siguiente método se encuentra el bucle de eventos que yace en el centro de las aplicaciones CLX: procedure TApplication.HandleMessage; Enganches nuevamente, y resumen ------------------------------- Hecho: hemos aprendido que Qt usa un mecanismo de señales y ranuras, y CLX usa un mecanismo de eventos. No es muy importante cómo se conectan los dos, pero puede ser valioso en algún momento. Vaya aquí un resumen: Qt usa un mecanismo de señales y ranuras. CLX usa un mecanismo de eventos. Para traducir señales y ranuras Qt a eventos CLX, el equipo de Kylix creó un mecanismo conocido como "enganches" (hooks). Cada tipo de objeto CLX tiene un objeto de enganche. Este objeto de enganche convierte los eventos de señales y ranuras asociados con un objeto particular en eventos CLX, y luego envía estos eventos al control CLX apropiado. En particular, hay un método CLX en TWidgetControl llamado EventFilter que recibe la mayoría de estos eventos. Se puede encontrar más información sobre este tema en el CD de herramientas de Kylix (CompanionTools CD): sams_publishing/kdgch07.pdf capítulo 7 "CLX architecture & Visual Development", o en la entrada ID #1679 en la Code Central de Borland. A continuación, un extracto representativo: Si tiene grandes deseos de ir más allá de la API CLX habitual, entonces hete aquí uno de los métodos que querrá sobrescribir: function TWidgetControl.EventFilter(Sender: QObjectH; Event: QEventH): Boolean; Este es el principal. EventFilter recibe la mayoría de los eventos que envían Qt y el sistema operativo. Es suficiente abrir QControls y mirar las más de 500 líneas que forman la implementación de este método para enviar a cualquier programador sano a corriendo hacia la seguridad de las API estándar de CLX. No obstante, a algunos les gusta vivir en el límite. Ellos claman que el aire es más tenue pero más limpio allá arriba... function TWidgetControl.MainEventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl; var Form: TCustmForm; begin try if csDesigning in ComponentState then begin Form := GetParentForm(Self); if (Form <> nil) and (Form.DesignerHook <> nil) and Form.DesignerHook.IsDesignEvent(Self, Sender, Event) then begin Result := True; Exit; end; end; Result := EventFilter(Sender, Event); except Application.HandleException(Self); Result := False; end; end; __________________ Referencia: http://www.delphi3000.com/article.asp?ID=3311 ________________________________________________________________________ ¿Cuándo fue la última vez que votó por el Boletín Pascal? Por favor apoye esta iniciativa votándonos en "The Programming Top 100!" http://www.sandbrooksoftware.com/cgi-bin/TopSite2/rankem.cgi?id=latium ________________________________________________________________________ 4. Creando aplicaciones middleware de alto rendimiento con Indy Por Romeo Lefter <rombest @ hotmail.com> Rombest Software http://www.vreau.com Traducido por Ernesto Cullen y Ernesto De Spirito "Middleware" (capa intermedia) es una de las tecnologías de moda en el mercado hoy en día. Desafortunadamente, las herramientas listas para usar con esta tecnología son my costosas. Esta tecnología está asociada con bases de datos porque es intensamente utilizada en esta área, pero no está limitada a bases de datos. Usando esta tecnología Ud. puede crear una plétora de aplicaciones que uses clientes "livianos" (thin clients). Típicamente, un entorno middleware se ve como sigue: +--------+ +----------+ +--------+ |Clientes| <<-Conexión1->> | Servidor | <<-Conexión2->> |Servidor| | | |Middleware| | de BD | +--------+ +----------+ +--------+ En la imagen, [Clientes] representa sus clientes livianos, [Servidor Middleware] es su aplicación servidora y [Servidor de datos] es la base de datos. De acuerdo a este modelo, los clientes, el servidor de capa intermedia y el servidor de base de datos corren en máquinas diferentes (el servidor de datos y el servidor de capa intermedia pueden correr en la misma máquina). Conexión1 y Conexión2 son las conexiones entre las partes. La arquitectura de capa intermedia es la mejor manera de hacer economía en serio. Por ejemplo, MS SQLServer necesita una licencia adicional por cada cliente. Además, necesita algo llamado "Licencia de acceso de cliente" (creo). Todo esto cuesta dinero. Con una sola licencia de cliente (más la licencia de acceso de cliente) se puede construir un servidor intermedio y después trabajar con muchos clientes, sin pagar licencias adicionales. ¡Y esta solución funciona muy bien! Con relación a Middleware quisiera decir aquí que no me gustan Midas, COM, DCOM, COM+, etc. Hay varias soluciones Middleware en el mercado. Una pequeña parte de ellas representan soluciones realmente buenas, pero muy caras. Hay soluciones que son fáciles de usar pero, desafor- tunadamente, más lentas. Hablaré aquí de cómo crear una aplicación de capa intermedia gratis. Esto es posible y, créanme, es superior en prestaciones a otros competidores. Primero, veamos las herramientas que necesitamos para el trabajo. 1. Indy http://www.nevrona.com/indy Necesitará Indy. Porque es simple de usar y muy rápido. Hay otros paquetes comerciales en el mercado que son más veloces que Indy, pero trabajar con ellos no es tan fácil. Para mí, Indy es uno de los mejores paquetes de trabajo con redes del mercado. 2. KbmMemTable: http://www.onelist.com/community/memtable Esta es la mejor tabla en memoria que hay actualmente en el mercado. Es segura para usar en hilos independientes ("thread safe"), su contenido (registros y estructura) puede ser salvado a disco o a una corriente (stream), soporta transacciones, campos binarios largos (blob) comprimidos y mucho más. Y lo mejor de todo, es gratis y con código fuente. => Una breve descripción de las características de TKbmMemTable Como dije, el modelo de hilos (threading model) de kbmMemTable es uno de los mejores. Sólo hay que fijar unas pocas propiedades y la tabla puede trabajar en forma segura en un entorno multihilo. La primera propiedad es AttachedMaxCount. Es de tipo Integer y almacena el máximo número de tablas en memoria que pueden adjuntarse a esta tabla. El proceso de adjuntado es muy interesante. Cuando se adjunta una tabla de memoria (llamémosla A) a otra tabla (B) todos los datos contenidos en la tabla B estarán disponibles para la tabla A. Más que una simple vista, la tabla A puede agregar o actualizar registros y los resultados se reflejarán en la tabla B. En un entorno multihilo, este es el mejor modelo. Otra característica de kbmMemTable es su habilidad para guardar sus datos a corrientes (streams) o archivos. Esto nos viene muy bien para lo que queremos hacer. En su última versión, TkbmMemTable incluye dos componentes auxiliares: kbmBinaryStreamFormat y TkbmCsvStreamFormat que nos ayudan a establecer un "lenguaje común" para las corrientes del servidor y el cliente. Como puede ver, SaveToStreamViaFormat y LoadFromStreamViaFormat son los métodos más usados en nuestro entorno. Es tiempo ahora de discutir el protocolo. Primero, por razones de seguridad, se necesitará una parte de autenticación. Por lo tanto, tenemos que implementar dos comandos: Login y Logoff. El comando Login se envía al servidor con 2 parámetros, el nombre de usuario y la contraseña, como se muestra a continuación: login usuario contraseña Si el par [usuario,contraseña] se corresponde con los datos que están guardados en el servidor, el usuario está habilitado para trabajar, de lo contrario es desconectado. Cuando el usuario desea terminar su sesión, envía al servidor el comando Logoff sin parámetros. En ese momento, el servidor desconectará al cliente. Para hacer este ejemplo simple y portable, trabajaré aquí con tablas de Paradox, que emularán nuestro servidor de datos. También, por motivos de portabilidad, usaré consultas (queries). En esta aplicación usaré la tabla country.db que se puede acceder a través del alias DBDEMOS. Los clientes que conectarán a nuestro servidor de capa intermedia serán capaces de: - agregar registros a esta tabla - recuperar la tabla completa Para agregar registros a la tabla, implementaremos un comando (Add) con cinco parámetros: Nombre, Capital, Continente, Area, Poblacion. De esta manera, el comando lucirá como sigue: Add p1 p2 p3 p4 p5 Para obtener la tabla, solamente necesitamos un comando sin parámetros (Get). Es hora de trabajar, así que comencemos. Abra un nuevo proyecto, coloque una tabla de memoria y un TIdTcpServer en él. La tabla de memoria será usada para el proceso de verificación de identidad en el ingreso (login), por lo que tenemos que crear dos campos de tipo String en ella: User y Password. Tendrá que implementar algunos procedimientos para agregar, borrar y actualizar usuarios. De la misma manera, en los eventos FormCreate y FormClose tendrá que cargar/guardar los datos persistentes para esta tabla (usando los métodos LoadFromBinaryFile/ LoadFromCsvFile y SaveToBinaryFile/SaveToCsvFile). He decidido usar una tabla en memoria para la autenticación porque es lo mejor en velocidad y su mecanismo multihilo funciona perfectamente. He decidido tener la siguiente arquitectura: En la ventana principal: usrs: Un KbmMemTable usado para la autenticación (tabla de usuarios) Server: Un componente TIdTcpServer, nuestro servidor MThread: Un componente TIdThreadMgrPool (usaré en este ejemplo un reservorio (pool) hilado con un tamaño de 100) Para una mayor facilidad de entendimiento, usaré CommandHandlers habilitado en estos proyectos, por lo que tenemos que definir 4 comandos: -Login -Logoff -Get -Add Debido que el tamaño de nuestro reservorio es de 100, la propiedad AttachedMaxCount de AuthTable tiene que ser 100. Además, para hacerlo más fácilmente entendible, hemos puesto todos los componentes de interfaz con base de datos en un módulo de datos (DataModule). Así que cree un módulo de datos y coloque algunos componentes en él, como se detalla a continuación: Query1: Un componente TQuery que hará interfaz con la base de dates, en nuestro caso DBDEMOS Session1: Un componente TSession usado para transacciones seguras logintable: Una memTable que será adjuntada a AuthTable para verificar si el par [usuario,contraseña] es correcto buffertable: Otra memTable usada para intercambio de datos Quite el módulo de datos de la lista de formularios creados automáti- camente (en Project|Option|Forms). Ahora daremos una mirada profunda al modelo de servidor. Como dije, el usuario tiene que loguearse en el servidor. Cuando el usuario envía el comando LOGIN, el servidor seguirá los siguientes pasos: 1. Crear el módulo de datos; 2. Adjuntar la logintable (del datasource) a AuthTable (esto es en el MainForm); 3. Verificar si el par [usuario,contraseña] es válido; 4. Devolver al usuario el resultado de la autenticación: - Si el número de parámetros es menor que 2 (o sea, si el comando se parece a Login MyNombre), el servidor envía ('101 - Incorrecto número de parámetros! Adiós!') y desconecta al usuario; - Si el par [usuario,contraseña] es válido, el servidor envía un mensaje como ('201 - Ok, ahora está en el sistema!') y el cliente permanecerá conectado; - Si el par [usuario,contraseña] no es válido, el servidor envía un mensaje como ('102 - Lo siento, usuario o contraseña inválidos. Adiós!') y desconecta al usuario. Un poco de código será más explícito si no ha entendido lo que he dicho. Así que, mire aquí abajo: procedure TForm1.serverCommandHandlers0Command(ASender: TIdCommand); var ClientDataModule: TDatas; loginFlag: boolean; begin // Comando Login // Formato: login <<usuario>> <<contraseña>> if ASender.Params.Count < 2 then begin ASender.Thread.Connection.WriteLn( '101 - Incorrecto número de parámetros! Adiós!'); ASender.Thread.Connection.Disconnect; end; // Crear el módulo de datos... Su dueño será la misma conexión! ClientDataModule:=TDatas.Create(ASender.Thread.Connection); // Asigna un nombre único al componente TSession ClientDataModule.Session1.SessionName := 'ClientSession' + Inttostr(ASender.Thread.ThreadID); ClientDataModule.logintable.AttachedTo := usrs; ClientDataModule.logintable.Active := True; ClientDataModule.Query1.SessionName := ClientDataModule.Session1.SessionName; // Ok, ahora verificaremos si el [usuario,contraseña] es válido if not ClientDataModule.logintable.Locate('User', ASender.Params[0],[]) then loginflag := false else if ClientDataModule.logintable.FieldByName('Password').AsString = Asender.Params[1] then loginFlag := true else loginFlag := false; if loginFlag then Asender.Thread.Connection.WriteLn( '201 - Ok, ahora está en el sistema!') else begin Asender.Thread.Connection.WriteLn( '102 - Lo siento, usuario o contraseña inválidos. Adiós!'); ASender.Thread.Connection.Disconnect; end; end; A primera vista puede parecer un poco "extraño" el modo en el que hemos creado el módulo de datos (en mi proyecto se llama Datas). Como ha observado, lo he creado usando una variable local. El problema es "como lo accederemos en otros procedimientos". Y he aquí mi pequeña innovación. Usar variables globales no sería práctico pues no sabemos cuantas conexiones tendremos en un momento dado. No nos olvidemos que el dueño del módulo de datos es la conexión. Por cada conexión activa tendremos un módulo de datos creado. Por supuesto, está creado sólo si el usuario está logueado. Si el usuario no está logueado, el módulo de datos no existe. Para un mejor entendimiento, demos un vistazo al escenario que se presenta a continuación... El cliente se conecta al servidor usando el método Connect de TIdTcpClient. En este momento, el cliente puede enviar cualquier comando al servidor. Necesitamos saber si está logueado cuando envía un comando como Get o Add al servido. Usando el modelo que he descrito, la verifi- cación de usuarios es realmente fácil porque si por cada conexión cliente existe in módulo de datos, esto significa que el cliente está logueado, y si no, el cliente no está logueado. Ahora es tiempo de implementar una función "buscadora". Esta función es útil para encontrar si existe un módulo de datos para una conexión. Si el módulo de datos existe, la función devolverá una referencia al mismo. De lo contrario, devolverá Nil. function TForm1.FindModule(connection:TIdTCPServerConnection):TDatas; var i: integer; begin Result := nil; for i := 0 to Connection.ComponentCount-1 do if Connection.Components[i] is TDatas then Result := (Connection.Components[i] as TDatas); end; Como dijimos, estamos usando un "modelo de reservorio de hilos" para nuestro servidor. Esto significa que el hilo no se destruye cuando el usuario se desconecta del servidor, de modo que tenemos de destruir el módulo de datos manualmente cada vez que un usuario se desconecta de nuestro servidor: procedure TForm1.serverDisconnect(AThread: TIdPeerThread); var AData:TDatas; begin AData := FindModule(AThread.Connection); if AData <> nil then AData.Free; end; Esto significa que para un comando Logoff tenemos que hacer algo como lo que sigue: procedure TForm1.serverCommandHandlers1Command(ASender: TIdCommand); begin ASender.Thread.Connection.Disconnect; end; Ahora ha llegado el momento de la verdadera implementación. Tenemos que intercambiar datos entre nuestros clientes y el servidor, así que primero implementaremos el comando Get. Para hacer este ejemplo fácil de entender, este comando no tendrá ningún parámetro, pero usted puede añadir parámetros que puedan usarse para filtrar o para cualquier otra acción. Aquí abajo está la implementación del comando: procedure TmainFrm.serverTIdCommandHandler2Command(ASender: TIdCommand); var AData: TDatas; AStream: TStream; begin AData := FindModule(ASender.Thread.Connection); if Adata = nil then begin ASender.Thread.Connection.WriteLn( '103 - No está logueado! Adiós!'); Asender.Thread.Connection.Disconnect; end; // Crear la corriente (stream) AStream := TMemoryStream.Create; // Comenzar la consulta AData.Query1.sql.Clear; AData.Query1.sql.Add('select * from country'); AData.Query1.Active := true; // Cargar los datos de la consulta en buffertable Adata.buffertable.LoadFromDataSet(Adata.Query1,[mtcpostructure]); // Guardar BufferTable en la corriente Astream AData.buffertable.SaveToStreamViaFormat(Astream, adata.kbmBinaryStreamFormat1); // Poicionarse al comienzo de la corriente Astream.Seek(0, soFromBeginning); ASender.Thread.Connection.WriteLn( '202 - Ok! La corriente está llegando!'); // Enviar la corriente AStream a la aplicación cliente ASender.Thread.Connection.WriteStream(AStream,true,true); // Liberar la corriente AStream.Free; end; Para este comando, el cliente recibirá una corriente conteniendo todos los datos de la tabla. Esta corriente puede ser cargada en un TKbmMemTable y toda la tabla en el servidor será visible en el cliente. Sin la BDE o cualquier otra "solución de conectividad" de terceros. Dado que el comando Add se implementa de manera idéntica (tiene que leer los parámetros y crear una consulta que inserte los parámetros en la tabla), no voy a elaborar más en este aspecto. Además, dado que la implementación cliente es realmente fácil, no la describiré. Esta es toda la "tecnología". Es fácil de implementar, superior en rendimiento y no cuesta nada. Hay, por supuesto, muchos otros aspectos a considerar. Por ejemplo, puede usar corrientes comprimidas para reducir el tráfico entre servidores y clientes. Hay algunas cosas que usted debe saber antes de iniciar la creación de su siguiente "gran servidor middleware". Antes que comience, tiene que construir su protocolo y esto, en mi opinión, es la parte más importante del proyecto. Un buen protocolo lo ayudará en el proceso de desarrollo. Veamos el fragmento de código de arriba. Primero, note que hay un número al inicio de cada cadena que se envía al cliente. En el protocolo de ejemplo he usado un protocolo numérico combinado con un protocolo de cadena. Antes del texto que se envía el cliente, he usado un código numérico: 1XX representa las acciones con error y 2XX representa las acciones exitosas. Esto le ayudará al desarrollar aplicaciones clientes. Del lado del cliente puede crear una función de ayuda que extraiga este código numérico y, por cada cadena recibida por su cliente sabrá si ha ocurrido un error o si "todo está bien". Otra parte interesante es la sincronización. Cuando un servidor envía una corriente, tiene que leer una corriente del lado del cliente. Lo mismo con cadenas. Si espera por una cadena y se envía una corriente, su aplicación cliente quedará bloqueada. Por esta razón he insertado el mensaje '202 - Ok! La corriente está llegando!'. A primera vista es innecesario, pero sólo mire el comienzo del procedimiento. Si el cliente no está logueado, el servidor le envía el mensaje '103 - No está logueado! Adiós!'. Cuando un cliente envía un comando Get al servidor primero lee una cadena porque tiene que saber si el servidor devuelve un error. Otra cosa interesante es acerca de como se envían las corrientes. El procedimiento WriteStream tiene 3 parámetros. El primero es la corriente que será enviada. El segundo parámetro es un valor lógico, que si es verdadero, la corriente se enviará desde el inicio y si es falso se enviará desde la posición actual. El tercer parámetro también es lógico. Si es verdadero, el tamaño de la corriente se enviará al cliente, y si es falso, este valor no se enviará. Si el último parámetro es verdadero, el tamaño se envía como un valor entero, antes de la corriente. Los siguientes fragmentos de código son lo mismo: 1. => WriteStream con último parámetro False .... i := MyStream.Size; ASender.Thread.Connection.WriteInteger(i); ASender.Thread.connection.WriteStream(MyStream, true, false); .... es lo mismo que 2. => WriteStream con último parámetro True .... ASender.Thread.Connection.WriteStream(MyStream, true, true); .... Se adjunta una demo a este artículo, la que contiene una implementación completa de un cliente y un servidor. ¡Disfrútenlo! __________________ Referencia: http://www.delphi3000.com/member.asp?ID=806 ________________________________________________________________________ En Delphiladero estamos interesados en alentar la producción de material sobre Delphi escrito enteramente en español. Hay mucha gente capaz de escribir artículos, programas y componentes excelentes, pero, por alguna razón, no lo hacen. Este sitio puede ser el comienzo de un cambio... http://webs.sinectis.com.ar/alvadel E-mail: <casta_pablo@hotmail.com> ________________________________________________________________________ 5. Inline Assembler en Delphi (III) - Arreglos estáticos Por Ernesto De Spirito <eds2004 @ latiumsoftware.com> Pasando arreglos estáticos como parámetros ========================================== Los parámetros de este tipo se pasan como punteros al primer elemento del arreglo, independientemente de si el parámetro se pasa por valor o por referencia (ya sea como "var" o como "const"). Dadas las siguientes declaraciones... const ARRAY_MAX = 5; type TArrayOfInt = packed array [0..ARRAY_MAX] of longint; var a, b: TArrayOfInt; procedure InitializeArray(var a: TArrayOfInt); var i: integer; begin for i := 0 to ARRAY_MAX do a[i] := i; end; ...la llamada al procedimiento InitializeArray en ensamblador sería así: // En Object Pascal: // InitializeArray(a); // En Inline Assembler: asm mov eax, offset a // EAX := @a; call InitializeArray // InitializeArray; end; OFFSET es un operador unario del ensablador que devuelve la dirección de un símbolo. OFFSET no es aplicable a símbolos locales. Debemos usar el opcode LEA (ver más abajo), que es más "universal". Arreglos estáticos pasados por valor ------------------------------------ Si el arreglo de pasa por valor, es responsabilidad de la función llamada la de preservar el arreglo. Cuando una función necesite cambiar los valores de uno o más elementos de un arreglo pasado por valor, normalmente crea una copia local y trabaja sobre la copia. El compilador crea una copia por nosotros en el "begin" de procedimientos y funciones en Pascal, pero en procedimientos y funciones totalmente en ensamblador tenemos que hacerlo por nuestra cuenta. Una forma de hacerlo es de la siguiente manera: procedure OperateOnArrayPassedByValue(a: TArrayOfInt); var _a: TArrayOfInt; asm // Copia los elementos de "a" (parámetro) en "_a" (copia local) push esi // Salva ESI en la pila push edi // Salva EDI en la pila mov esi, eax // ESI := EAX; // @a lea edi, _a // EDI := @_a; mov eax, edi // EAX := EDI; // @_a mov ecx, type TArrayOfInt // ECX := sizeof(TArrayOfInt); rep movsb // Move(ESI^, EDI^, ECX); pop edi // Restaura EDI desde la pila pop esi // Restaura ESI desde la pila // Aquí va el resto de la función. Trabajaremos sobre "_a" (la // copia local), cuyo primer elemento es ahora apuntado por EAX. end; Las cosas nuevas aquí son los opcodes LEA y MOVSB, el prefijo REP y el operador TYPE, descritos a continuación. LEA (Load Effective Address) ----------------------------- Mueve al primer operando la dirección del segundo. Aquí comparamos LEA con MOV: Instrucción Traducidad como Efecto ------------------------------------------------------------------- lea eax, localvar lea eax, [ebp-$04] EAX := @localvar; EAX := EBP - $04; mov eax, localvar mov eax, [ebp-$04] EAX := localvar; EAX := (EBP - $04)^; MOVSB (MOVe String Byte) ------------------------ Copia el byte apuntado por ESI a la ubicación apuntada por EDI, e incrementa ESI y EDI de modo que apunten al siguiente byte. El trabajo de MOVSB se puede representar como sigue: ESI^ := EDI^; // Asumimos que ESI y EDI son de tipo PChar Inc(ESI); Inc(EDI); Notas: * MOVSW y MOVSD son las versiones Word (16 bits) y DWord (32 bits) respectivamente (ESI y EDI se incrementan en 2 y 4 respectivamente). * Los registros de decrementan si la bandera de dirección (Direction Flag) está encendida. REP --- El prefijo REP es usa en operaciones de cadenas para repetir la operación, decrementando ECX hasta que ECX sea cero. El trabajo de REP se podría representar así: // rep instrucción_de_cadenas @@rep: instrucción_de_cadenas loop @@rep Notas: * REP no es un atajo para un código como el de arriba. Funciona mucho más rápido. * El valor de ECX no es comprobado al inicio del ciclo (si ECX es cero, la instrucción sería repetida 2^32 veces, pero generará una AV mucho antes de ello, tan pronto como ESI o EDI apunten a una ubicación de memoria no válida). TYPE ---- El operador TYPE es un operador unario evaluado en tiempo de compilación que devuelve el tamaño en bytes del operando, el que debe ser un tipo de datos. Por ejemplo TYPE WORD devolverá 2 y TYPE INTEGER devolverá 4. Accediendo los elementos de un arreglo ====================================== Para acceder a un elemento a[i] necesitamos los valores de "@a[0]" e "i" en registros (como EDX y ECX, por ejemplo), y entonces podemos usar el direccionamiento de memoria como sigue: lea edx, a // EDX := @a; mov ecx, i // ECX := i; mov ax, [edx+ecx*type integer] // AX := EDX[ECX]; // a[i]; // PWord(EDX + ECX * SizeOf(integer))^ En el ejemplo, asumimos que los elementos tienen 2 bytes (movimos el valor de a[i] a AX, un registro de 16 bits ), que el arreglo no es "packed" (cada elemento en realidad ocupa 4 bytes, el tamaño de un Integer, así que ése fue el valor usado para calcular la posición del elemento), y que el arreglo de de base cero. Por ejemplo: var a: array [0..N] of word = (1, 2, 3, 6, ...); +------ EDX = @a | v +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+-- | 1 | 0 | | | 2 | 0 | | | 3 | 0 | | | 6 | 0 | | | +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+-- a[0] a[1] a[2] a[3] [edx] [edx+04] [edx+08] [edx+12] Si el arreglo no tiene base cero, tenemos que ajustar el valor del índice para hacerlo base cero antes de direccionar el elemento. Ejemplos: // a[1..100] : mov ecx, i // ECX := i; dec ecx // Dec(ECX); // Ajustar ECX : // a[-10..10] : mov ecx, i // ECX := i; add ecx, 10 // Inc(ECX, 10); // Ajustar ECX : El procedimiento InitializeArray (presentado arriba) puede implementarse en ensamblador de esta forma: procedure InitializeArray(var a: TArrayOfInt); asm // EAX = PByte(@a[0]); xor ecx, ecx // ECX := 0; @@loop: mov [eax+ecx*type integer], ecx // PInteger(EAX+ECX*4)^ := ECX; // ...o EAX[ECX] := ECX; inc ecx // ECX := ECX + 1; cmp ecx, ARRAY_MAX // if ECX <= ARRAY_MAX then jle @@loop // goto @@loop; end; O de esta otra: procedure InitializeArray(var a: TArrayOfInt); asm // EAX = @a[0]; xor ecx, ecx // ECX := 0; @@loop: mov [eax], ecx // EAX^ := ECX; inc ecx // Inc(ECX); add eax, type integer // Inc(EAX); // Apuntar al siguiente elemento cmp ecx, ARRAY_MAX // if ECX <= ARRAY_MAX then jle @@loop // goto @@loop; end; Devolviendo valores array ========================= Las funciones que devuelven arreglos reciben un último parámetro adicional que es un puntero a la ubicación de memoria donde deben dejar su valor de retorno (la memoria es asignada y liberada si es necesario por el llamador). Por ejemplo, consideremos la siguiente función: function ReverseArray(const a: TArrayOfInt): TArrayOfInt; var i: integer; begin for i := 0 to ARRAY_MAX do Result[i] := a[ARRAY_MAX-i]; end; La función recibe dos parámetros: 1) EAX = la dirección del primer elemento del arreglo "a" 2) EDX = la dirección del primer elemento de Result La función puede ser rescrita en ensamblador como sigue: function ReverseArray(const a: TArrayOfInt): TArrayOfInt; asm // EAX = @a[0]; EDX = @Result[0]; push ebx // Salvar EBX mov ebx, eax // EBX := EAX; xor ecx, ecx // ECX := 0; @@loop: mov eax, ARRAY_MAX sub eax, ecx // EAX := ARRAY_MAX-ECX; mov eax, [ebx+eax*type integer] // EAX := EBX[EAX]; mov [edx+ecx*type integer], eax // EDX[ECX] := EAX; inc ecx // ECX := ECX + 1; cmp ecx, ARRAY_MAX // if ECX <= ARRAY_MAX then jle @@loop // goto @@loop; pop ebx // Restaurar EBX end; Bien, eso es todo por ahora. En la próxima edición veremos como trabajar con registros. ________________________________________________________________________ 6. Foros / listas de correo Para quienes son miembros de nuestros foros (grupos en Yahoo! Grupos), me gustaría recordarles que la participación en los mismos está sujeta a ciertas reglas, de las cuales me gustaría extractar algunas que son comunes a todos los foros: * El asunto de los mensajes tiene importancia capital. Por favor: . Provee un asunto representativo en tus preguntas. Trata que sea lo más específico posible y que incluya palabras clave que puedan facilitar la búsqueda posterior de un determinado tema. . Evita el uso de palabras como "duda", "problema", "socorro", "SOS", "ayuda" (excepto que estés hablando de archivos de ayuda), "consulta" (salvo que estés hablando de una consulta SQL), etc. . Evita usar de signos de exclamación y escribir todo en mayúsculas. . No modifiques la línea de asunto al responder un mensaje. * Elimina lo más posible del mensaje original al responder, para reducir así el tamaño de los mensajes. Como mínimo, al responder elimina las líneas innecesarias de arriba y de abajo del mensaje original: - Todo o parte de los encabezados. Mínimamente las líneas de: . Destinatario (es el foro, ya lo sabemos) . Asunto (se repite en la respuesta, ya lo sabemos) . Fecha de envío (opcional) - Las frases iniciales y finales como saludos, presentaciones, agrade- cimientos, firmas ("signatures"), publicidades de los servicios de webmail y de Yahoo!, direcciones del foro, etc. - Los mensajes anteriores del hilo de conversación * No envíes mensajes irrelevantes (como mensajes de agradecimiento, o respuestas del tipo "yo lo quiero" / "yo también" cuando alguien ofrece algo en el foro, y mucho menos mensajes fuera de tema como cartas cadena -o "pirámide"-, alertas de virus, publicidades, etc.) * No envíes ofrecimientos, solicitudes o apologías de cracks, warez, seriales y otras formas de piratería informática. * No envíes mensajes del tipo "¿Dónde puedo encontrar...?" (excepto en el caso del foro de Componentes, que está para ese fin). * Incluye abundante información sobre el problema que planteas (como por ejemplo versión del producto y sistema operativo que usas, etc.) * Todos los foristas y todos los mensajes tienen la misma prioridad, así que por favor no envíes mensajes urgentes, con prioridad o con su asunto todo en mayúsculas, y evita usar expresiones como "por favor ayúdenme", "mi empleo depende de esto", "estoy desesperado", "ya no sé que hacer", etc., así como cualquier otra forma de intentar obtener ventaja o resaltar tu mensaje sobre los demás. * No escribas todo en mayúsculas (parece que estuvieras gritando). Como siempre, recordamos a los suscriptores las direcciones de nuestros foros. Para unirse a algún foro, lo más recomendable es hacerlo desde la web para así tener acceso a todas las áreas del foro y la configuración de las opciones de suscripción, pero también es posible suscribirse por email. Para suscribirse desde la web es necesario poseer un ID de Yahoo! (si no tienes el tuyo, puedes conseguirlo gratis registrándote como usuario de Yahoo!). * Delphi-abierto. Programación en Delphi (todos los niveles). Si estás en la etapa de aprendizaje o si no te agradan los foros discriminados por niveles, este foro es para ti. http://espanol.groups.yahoo.com/group/delphi-abierto Suscripción: http://espanol.groups.yahoo.com/group/delphi-abierto/join delphi-abierto-subscribe@gruposyahoo.com * Delphi-intermedio. Programación en Delphi (nivel intermedio). Si ya sabes mucho de Delphi, pero todavía te falta un largo trecho para ser un gurú (o no tanto), este foro es para ti. http://espanol.groups.yahoo.com/group/delphi-intermedio Suscripción: http://espanol.groups.yahoo.com/group/delphi-intermedio/join delphi-intermedio-subscribe@gruposyahoo.com * Delphi-avanzado. Programación en Delphi. Sólo para gurús. http://espanol.groups.yahoo.com/group/delphi-avanzado Suscripción: http://espanol.groups.yahoo.com/group/delphi-avanzado/join delphi-avanzado-subscribe@yahoogroups.com * GrupoKylix. Programación en Kylix. http://espanol.groups.yahoo.com/group/GrupoKylix Suscripción: http://espanol.groups.yahoo.com/group/GrupoKylix/join GrupoKylix-subscribe@yahoogroups.com * FreePascal-es. Programación en Free Pascal (freepascal.org). http://espanol.groups.yahoo.com/group/freepascal-es Suscripción: http://espanol.groups.yahoo.com/group/freepascal-es/join freepascal-es-subscribe@yahoogroups.com * Desarrolladores-Software. Un lugar para tratar todos aquellos temas relacionados con el desarrollo de software y su comercialización, y para compartir experiencias en el ámbito laboral, profesional o comercial con otros. http://es.groups.yahoo.com/group/desarrolladores-software Suscripción: http://es.groups.yahoo.com/group/desarrolladores-software/join desarrolladores-software-subscribe@yahoogroups.com * Componentes. Un foro para buscar/recomendar componentes de software (componentes VCL y CLX, objetos ActiveX, librerías DLL, etc.), así como utilidades, tutoriales, información, etc. http://espanol.groups.yahoo.com/group/componentes Suscripción: http://espanol.groups.yahoo.com/group/componentes/join componentes-subscribe@yahoogroups.com ________________________________________________________________________ 7. Delphi en la Red Por Dave Murray <irongut @ vizzavi.net> Componentes, librerías y aplicaciones ===================================== Freeware -------- * Kylix 3 Open Edition available for download It's a whopping 300+ MB download, but worth every nibble! http://community.borland.com/article/0,1410,29010,00.html * Explorer Drop v1.1, FREEWARE with source - by Simon Grossenbacher TExplorerDrop component enables Drag&Drop with the Windows Explorer for all controls inherited from TWinControl. http://www.torry.net/vcl/system/draganddrop/swissexplorerdrop.zip * KACDO Proffesional v1.0, FREEWARE - by Kiril Antonov Delphi implementation of Microsoft's CDO for Win2k -a set of functions for composing and sending mail. Works only on Win2k/XP machines. Set of 3 powerful components: Message - Message, SMTP, NNTP, Encoding + Decoding Component; Manager - manages IIS SMTP Folders; TreeView - displays + modifies structure of complex messages. http://www.torry.net/vcl/internet/email/kacdopro.zip * TAdvFTP, FREEWARE with source - by Vadim Winebrand (KYLIX) An advanced FTP client component which supports resumes and gives the download rate every few seconds. Includes socks server support. http://www.torry.net/kylix/clxinternet/itools.zip Artículos, trucos y consejos ============================ * TJpegImage lets you transform BMPs to JPEGs - by Bob Swart Dr Bob shares a trick for transforming BMPs to JPEGs and vice versa. Thanks to a hidden component, it's not as hard as you might think. http://builder.com.com/article.jhtml?id=u00220020913swa01.htm * Using Delphi objects to store config information - by Sebastián Mayorá This article explains how to use objects as a substitute for INI files (and other similar techniques) to store configuration information. http://delphi.about.com/library/bluc/text/uc090302a.htm * Back to School with more Delphi knowledge - by Zarko Gajic Whether you're parent, student or teacher here are the topics you need to enhance your knowledge of Delphi programming. Go back to school in style with the right tutorials, code samples and Delphi quizzes. http://delphi.about.com/library/weekly/aa082702a.htm * ModelMaker tutorials - by Anders Ohlsson ModelMaker is included in D7 Enterprise & Architect - here are some tutorials to get you started. http://bdn.borland.com/article/0,1410,29006,00.html * How to install and uninstall fonts www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=169 * How to check if a string is a number www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=170 * How to get second title bar color www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=171 * BDE error list www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=173 * How to get the CPU speed www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=174 * How to write a correct date in SQL www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=175 * How to get around TQuery.Refresh if it doesn't work - by m3Rlin Sometimes TQuery.Refresh will not refresh as it's supposed to... www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=176 * How to read the serial number of an Audio CD - by m3Rlin Audio CDs, like almost every computer drive/media have a serial number too. Some programs use this number to recognize CDs. www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=177 * How to check is a character is a letter - by m3Rlin www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=178 * How to export a StringGrid to an Excel-File? http://www.swissdelphicenter.ch/en/showcode.php?id=379 * How to turn on/off Caps/Num/Scroll Lock? http://www.swissdelphicenter.ch/en/showcode.php?id=926 * How to synchronize DBGrid title alignments with field alignments? http://www.swissdelphicenter.ch/en/showcode.php?id=1074 * How to save memory with duplicate strings? http://www.swissdelphicenter.ch/en/showcode.php?id=1110 * How to draw a gradient on a canvas with an arbitrary number of colors? http://www.swissdelphicenter.ch/en/showcode.php?id=1162 * How to retrieve information about the TWebBrowser control? http://www.swissdelphicenter.ch/en/showcode.php?id=1191 * How to retrieve the network card addresses? http://www.swissdelphicenter.ch/en/showcode.php?id=1206 * How to convert C Types to Object Pascal Types? http://www.swissdelphicenter.ch/en/showcode.php?id=1217 * How to get an inverse color value to a color? http://www.swissdelphicenter.ch/en/showcode.php?id=1222 * How to show values in a hexadecimal representation? http://www.swissdelphicenter.ch/en/showcode.php?id=1312 * How to show values in binary representation? http://www.swissdelphicenter.ch/en/showcode.php?id=1313 * How to get the start command for a installed Mail-Client? http://www.swissdelphicenter.ch/en/showcode.php?id=1320 * How to execute a document and wait for it to finish? http://www.swissdelphicenter.ch/en/showcode.php?id=1333 * How to do bit-wise manipulation? http://www.swissdelphicenter.ch/en/showcode.php?id=1341 * How to Draw on a Form's Caption bar? http://www.swissdelphicenter.ch/en/showcode.php?id=1345 * How to access Paradox tables on CD or read-only drives? http://www.swissdelphicenter.ch/en/showcode.php?id=1351 * How to define BDE aliases in code? http://www.swissdelphicenter.ch/en/showcode.php?id=1353 * How to multiply big integer values? http://www.swissdelphicenter.ch/en/showcode.php?id=1363 * How to calculate the logarithm for a variable base? http://www.swissdelphicenter.ch/en/showcode.php?id=1371 * How to auto hide IDE windows when coding/designing? http://www.swissdelphicenter.ch/en/showcode.php?id=1382 * How to get the length of wav file (in second)? http://www.swissdelphicenter.ch/en/showcode.php?id=1383 * How to Clone the Controls Properties? http://www.swissdelphicenter.ch/en/showcode.php?id=1392 * How to set system evrionment variable? http://www.swissdelphicenter.ch/en/showcode.php?id=1394 * How to Set a new Index to TToolButton of a TToolbar? http://www.swissdelphicenter.ch/en/showcode.php?id=1395 * How to include the mouse-cursor in a screen shot? http://www.swissdelphicenter.ch/en/showcode.php?id=1396 * How to send data to another program by auto-drag&drop? http://www.swissdelphicenter.ch/en/showcode.php?id=1398 * How to empty all StringGrid cells? http://www.swissdelphicenter.ch/en/showcode.php?id=1399 * How to get the width and height of a Gif-File? http://www.swissdelphicenter.ch/en/showcode.php?id=1400 * How to transition the system to the standby/ hibernate state? http://www.swissdelphicenter.ch/en/showcode.php?id=1401 * How to know if the form is modal? http://www.swissdelphicenter.ch/en/showcode.php?id=1402 * How to prevent copy/paste/cut in TEdit? http://www.swissdelphicenter.ch/en/showcode.php?id=1403 * How to use regular expressions in Delphi? http://www.swissdelphicenter.ch/en/showcode.php?id=1406 * How to save a QuickReport to stream? http://www.swissdelphicenter.ch/en/showcode.php?id=1410 * How to build a Multi Screen Emulator? http://www.swissdelphicenter.ch/en/showcode.php?id=1418 * How to use the DrawAnimatedRects API? http://www.swissdelphicenter.ch/en/showcode.php?id=1419 * How to get the caret-position systemwide? http://www.swissdelphicenter.ch/en/showcode.php?id=1420 * How to invoke the 'find' dialog in a TWebBrowser? http://www.swissdelphicenter.ch/en/showcode.php?id=1421 * How to determine if the current session is remotely controlled? http://www.swissdelphicenter.ch/en/showcode.php?id=1424 * How to translate a virtual-key to ASCII code? http://www.swissdelphicenter.ch/en/showcode.php?id=1425 * How to convert a bitmap to RTF code? http://www.swissdelphicenter.ch/en/showcode.php?id=1426 * How to export a TDBGrid to excel without OLE? http://www.swissdelphicenter.ch/en/showcode.php?id=1427 * How to read a REG_MULTI_SZ value From the Registry? http://www.swissdelphicenter.ch/en/showcode.php?id=1431 * How to restore the default positions of the IDE Toolbars? http://www.swissdelphicenter.ch/en/showcode.php?id=1432 * How to retrieve all database tables with ADO? http://www.swissdelphicenter.ch/en/showcode.php?id=1433 * How to add items to the Application's Windows System Menu? http://www.swissdelphicenter.ch/en/showcode.php?id=1435 * How to get the number of Files in the Recycle Bin + their total size? http://www.swissdelphicenter.ch/en/showcode.php?id=1436 * How to change Background Color in TRichEdit for selected characters? http://www.swissdelphicenter.ch/en/showcode.php?id=1438 * How to show/hide the ActiveDesktop? http://www.swissdelphicenter.ch/en/showcode.php?id=1439 * How to copy formated Rtf-Text from one TRichedit to an other? http://www.swissdelphicenter.ch/en/showcode.php?id=1440 * How to use different underline styles for Text in TRichEdit? http://www.swissdelphicenter.ch/en/showcode.php?id=1441 * How to put the TWebbrowser into Edit Mode? http://www.swissdelphicenter.ch/en/showcode.php?id=1442 * How to set the paragraph line spacing in a TRichedit? http://www.swissdelphicenter.ch/en/showcode.php?id=1444 * Speed up connection to Oracle 8i - by Mark Halter http://www.delphi3000.com/articles/article_3344.asp * How do we store Graphics/Shapes like an Object? - max kleiner Designing a diagram editor or a graphic-tool raises the problem of storing all the painted shapes in a file without get lost in too much overhead. http://www.delphi3000.com/articles/article_3348.asp * Simulate a Web Form POST Request - by Clever Components Discusses the automation of the upload process via HTTP protocol by the POST method using the components from Clever Internet Suite. http://www.delphi3000.com/articles/article_3351.asp * Threaded Brute Forcing Class - by Stewart Moss http://www.delphi3000.com/articles/article_3352.asp * Simple useful Irc routines - by Stewart Moss http://www.delphi3000.com/articles/article_3353.asp * Generic File Importer Base Class - by Stewart Moss Here is a useful base class to create derived classes to import data from any flat file format you can think of. http://www.delphi3000.com/articles/article_3354.asp * ADO Dataset -> CSV file How to export a ADO Dataset to a Comma Separated Values file with a few lines of code. http://www.delphi3000.com/articles/article_3355.asp * Send E-Mails with Indy Components (Easy) http://www.delphi3000.com/articles/article_3356.asp * Show message in OnEnter event Do you ever needed to display a message using the OnEnter event? This example shows how to correctly display a message by using the ShowMessage (or an equivalent function) in OnEnter event. http://www.delphi3000.com/articles/article_3357.asp * EventLog change notification in real-time I needed a way to be notified in real-time when someone acceded my computer inside an intranet. After doing some research, the solution would pass by using the Security event log that is used when you activate any audit option. http://www.delphi3000.com/articles/article_3358.asp * SQL-DMO part 1: The SQL-DMO API This is the first part of a serie of articles about the SQL Distributed Management Objects known as SQL-DMO API. In this first article I'll talk about SQL-DMO, whats the purpose of it and what you'll gain if you use it. I will also show how to install it, so you can use it within our Delphi projects http://www.delphi3000.com/articles/article_3359.asp * Multi Column ListBox with Column Sorting and Resizing This is a VCL that allows multiple columns in a list box. The columns may be sorted (if the AllowSorting property is set to true) by clicking on the column header title. The column headers are set up in the Sections property. They are of type THeaderSections from the THeader component and thus may also display images from an associated image list. The items in the ListBox are semi-colon delimited fields. The fields are lined up in accordance to the Section headers and may be resized by the user at run-time. http://www.delphi3000.com/articles/article_3360.asp * Capture Output of a Console Application - Revised How do you start a DOS or Console Application and capture the output while it is running ? For example, how do you capture the output of the FileCompare (FC) Command ? http://www.delphi3000.com/articles/article_3361.asp * Retrieve Multiple Recordsets from ORACLE 8i Stored Procedure A faster and more resource efficient way to get data from the Database server (in this case - Oracle) http://www.delphi3000.com/articles/article_3363.asp Tutoriales ========== * Defining a ClientDataSet's Structure Using TFields - by Cary Jensen This article demonstrates how to define a ClientDataSet's structure at both design-time and runtime using TFields. How to create virtual and nested dataset fields is also demonstrated. http://community.borland.com/article/0,1410,29001,00.html * Understanding ClientDataSet Indexes - by Cary Jensen A ClientDataSet does not obtain its indexes from the data it loads. Indexes, if you want them, must be explicitly defined. This article shows you how to do this at design-time or runtime. http://community.borland.com/article/0,1410,29056,00.html * Improve application design with Prototyping, Modeling, + Storyboarding - by Ronald Anthony Lewis Meeting client expectations is the number-one goal of application development. Here's how one developer uses three approaches to handle different aspects of this critical objective. http://builder.com.com/article.jhtml?id=u00320020909RAL01.htm * An introduction to XML grammar - by Philip Page Document Type Definitions (DTDs) are an optional but useful part of XML. This article shows you how to declare a grammar in a DTD. http://builder.com.com/article.jhtml?id=u00320020906ppg01.htm * Unified Modeling Language simplifies software design - by Shelley Doll UML is the industry standard for modeling software architecture. It combines best practices, platform independence, and extensibility into a common language for describing solutions. This overview of UML describes why it's useful and outlines the major concepts. http://builder.com.com/article.jhtml?id=u00420020903dol01.htm * To be or not to be normal: That is the database question - Eric Roland There are advantages + disadvantages to normalizing database schemas. This article provides specific examples of when and why you should normalize or denormalize your final database design based on performance requirements. http://builder.com.com/article.jhtml?id=u00320020819ero01.htm * Transition from Logical to Physical Data Model - S Harkins + A Fuller Moving from a logical to physical design is not as straightforward as it appears. Use these tips to make the process as smooth as possible. http://builder.com.com/article.jhtml?id=u00320020826gcn01.htm Otros enlaces ============= * Delphi Fireworks Component Contest Basically, you have to make a self-contained Delphi visual component. There are no prizes, but you will receive awe and recognition from your peers, just for entering. Also it makes a great resume entry. http://chuckr.freeshell.org/index.php * ModelMaker is available for Delphi 7 Professional - by John Kaster Borland provides a license to ModelMaker for Delphi 7 Professional. http://community.borland.com/article/0,1410,29090,00.html * Borland to wield tools against Microsoft - by Wylie Wong After nearly being knocked out for good by Microsoft, software maker Borland is back on its feet and eager for a rematch. http://news.com.com/2100-1001-954958.html * Borland has a bead on Visual Studio - By Mark Driver (from Gartner) Borland plans to offer an alternative to Microsoft's Visual Studio .NET development environment. Such a product could suit application developers that want to leverage .NET and the best applications from many vendors. techupdate.zdnet.com/techupdate/stories/main/0,14179,2879601,00.html * Now all we need are celebrity endorsements - by Lamont Adams Humourous article about the possibility of celebrity endorsements in programming. Use the official IDE of the World Cup! http://builder.com.com/article.jhtml?id=u00220020904adm01.htm * SharpDevelop lets you jump into C# Programming for FREE! - Tony Patton You're dying to start programming in C#, but Visual Studio .NET is just too expensive. Help is on the way with this free .NET IDE. http://builder.com.com/article.jhtml?id=u00220020821ton01.htm ________________________________________________________________________ ¡Tú puedes ayudarnos! Por favor danos una mano y ayúdanos a llegar a los 10.000 suscriptores en los próximos meses. Una forma en que puedes ayudarnos es enviando este enlace a tus amigos: http://www.latiumsoftware.com/es/pascal/index.php boletin-pascal-subscribe@gruposyahoo.com Otra forma es votándonos en alguno de estos rankings para darle más visibilidad a nuestro sitio web y aumentar así el número de suscrip- ciones al boletín: http://www.sandbrooksoftware.com/cgi-bin/TopSite2/rankem.cgi?id=latium http://news.optimax.com/topdelphi/links.exe/click?id=70C517ECAE6E http://www.programmingpages.com/?r=latiumsoftwarecomenpascal http://www.top219.org/cgi-bin/vote.cgi?delphi&83 http://top100borland.com/in.php?who=20 http://top200.jazarsoft.com/delphi/rank.php3?id=latium http://213.65.224.200/cgi-bin/toplist.cgi/hits?Id=80 http://www.programacion.net/votar-enlace.php?id=474 http://www.lawebdelprogramador.com/buscar/enlace.php?id=615 Por favor vota. Son sólo unos segundos para ti que REALMENTE pueden hacer la diferencia. Necesitamos tu ayuda para poder continuar. ________________________________________________________________________ Si no has recibido el archivo con el código fuente completo de los ejemplos que se presentan en este boletín, puedes descargarlo de la siguiente dirección: http://www.latiumsoftware.com/descarga/p0039.zip ________________________________________________________________________ Página principal: http://www.latiumsoftware.com/es/pascal/index.php Página del grupo: http://espanol.groups.yahoo.com/group/boletin-pascal/ Para suscribirse / apuntarse: boletin-pascal-subscribe@gruposyahoo.com Para cancelar / removerse: boletin-pascal-unsubscribe@gruposyahoo.com Para reportar problemas con la suscripción: eds2004 @ latiumsoftware.com ________________________________________________________________________ Este boletín se provee "TAL Y COMO ESTA", sin garantía de ninguna clase. Su uso implica la aceptación de nuestros términos de licencia y de la ausencia de garantía que puedes leer en nuestro sitio web. Allí también encontrarás una nota sobre marcas registradas. Te animamos a que redis- tribuyas este boletín, siempre y cuando lo hagas en forma completa (incluyendo la información de copyright), sin modificaciones y de manera gratuita. Los artículos son copyright de sus respectivos autores y se reproducen aquí con el permiso de los mismos. ________________________________________________________________________ Latium Software http://www.latiumsoftware.com/es/index.php Copyright (c) 2002 por Ernesto De Spirito. Todos los derechos reservados ________________________________________________________________________ |
Los ejemplos completos de código fuente de este número están disponibles para descargar.
![]() |
¿Errores? ¿Omisiones? ¿Comentarios? Por favor contáctanos!






