Boletín Pascal #40
Los ejemplos completos de código fuente de este número están disponibles para descargar.
![]() |
![]() |
Boletín Pascal #40- 30-OCT-2002 Índice 1. Unas palabras del editor 2. Ganchos (hooks) de Windows (o "¿Cómo trabajan esos programas espía?") 3. Codificar y decodificar Base64 (MIME) 4. Ejemplo de un servicio Windows, con un hilo 5. Capturando la salida de una aplicación de consola 6. Creación de Objetos - Introducción (0 de 3) 7. Inline Assembler en Delphi (IV) - Registros 8. Foros / listas de correo 9. Delphi en la Red - Componentes, librerías y aplicaciones . 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 Tenía la intención de publicar esta edición hace un par de semanas como había prometido, pero en circunstancias muy particulares un nuevo virus no identificado entró en mi PC y sobrescribió el primer cilindro de mi disco duro (el sector de arranque maestro, y el sector de arranque y parte de la tabla de asignación de archivos -FAT- de la primera partición), así que imagínense... (Todavía estoy instalando todos los componentes Delphi que solía tener). Lamento mucho la demora. Para disipar dudas, los nombres de dos de nuestros foros/listas de correo (grupos en Yahoo! Grupos) han cambiado: delphi-es --> delphi-intermedio Delphi --> delphi-avanzado Por lo tanto, han cambiado todas sus direcciones, por lo que se deberán realizar las sustituciones correspondientes. Por ejemplo, para publicar mensajes en el foro Delphi de nivel intermedio: Antes: <delphi-es@gruposyahoo.com> Ahora: <delphi-intermedio@gruposyahoo.com> Quisiera agradecer a los autores que contribuyeron artículos para este número, y me complace entregarles los siguientes premios: * Florin Sabau ("Ganchos (hooks) de Windows") · 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/ * Jochen Fromm ("Capturando la salida de una aplicación de consola") · 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 * Kim Sandell ("Ejemplo de un servicio Windows, con un hilo") · 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 Para la próxima edición, tenemos disponible el siguiente premio para el autor de uno de los artículos contribuidos al boletín: * TSDBGridFooter v2.0 por Jovan Sedlan, Shareware ($74.50) Este componente es una poderosa herramienta que provee cálculos auto- máticos para su DBGrid y muestra información en un pie configurable debajo de la grilla. Ha sido diseñado para trabajar con TSDBGrid (también incluido), aunque puede usarse con cualquier descendiente de TCustomDBGrid. http://www.sedlan.com/dbgrid_footer.php Cambiando de tema, he sido lanzado el primer update pack para Delphi 7: * Delphi 7 Update Pack 1 http://community.borland.com/article/0,1410,29209,00.html Espero que disfruten esta edición. Saludos, Ernesto De Spirito eds2004 @ latiumsoftware.com __________________ Colaboraron en esta edición: Dave Murray y Charl Linssen ________________________________________________________________________ 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. Ganchos (hooks) de Windows (o "¿Cómo trabajan esos programas espía?") Por Florin Sabau <aaa111@go.ro> ¿Alguna vez se preguntó cómo obtienen esos programas espía todo lo que se escribe en la computadora en la que están instalados? Bueno, no sé exactamente como ELLOS lo hacen :), pero les voy a mostrar una forma posible usando ganchos (hooks) de Windows. Este artículo le mostrará cómo Ud. puede crear un programa que "escuche" cierta combinación de teclas y cuando sea activado que haga algo significativo (abrir la bandeja de CDROM). Técnicamente, un gancho es simplemente otra subrutina ("procedimiento gancho" o "procedimiento de gancho") que "se me mete en el camino" del mecanismo normal de administración de mensajes de Windows. El proce- dimiento gancho puede ser instalado en el sistema de modo que reciba ciertos mensajes de Windows ANTES que estos sean despachados a su procedimiento de ventana asignado. Windows contiene muchos tipos diferentes de ganchos; cada tipo provee acceso a aspectos diferentes del mecanismo de administración de mensajes de manejo de Windows. He aquí algunos de ellos (en realidad las constantes que los identifican han sido tomadas de windows.pas) con una breve descripción: WH_KEYBOARD: Instala un procedimiento gancho que monitorea los mensajes de teclado. Usaremos este en nuestro programa. WH_MOUSE: Instala un procedimiento gancho que monitorea los mensajes del ratón. WH_CBT: Instala un procedimiento gancho que recibe notificaciones útiles para una aplicación de entrenamiento basado en computadora (CBT, computer-based training) WH_JOURNALRECORD: Instala un procedimiento gancho que registra mensajes de entrada en la cola de mensajes del sistema. Este gancho es útil para registrar macros. WH_JOURNALPLAYBACK: Instala un procedimiento gancho que emite mensajes previamente registrados por un procedimiento gancho WH_JOURNALRECORD. Puesto que más de un programa puede instalar un gancho en el sistema al mismo tiempo, Windows mantiene internamente una "cadena de ganchos" (hook chain), que es simplemente una lista de punteros a los procedi- mientos ganchos que tiene instalados. Cuando ocurre un mensaje en el sistema, Windows primero se lo pasa a cada procedimiento en la cadena de ganchos, uno tras otro. Luego, si el mensaje no fue "bloqueado" por ninguno de los procedimientos gancho, Windows lo despacha al proce- dimiento de ventana designado. Una cosa más antes de entrar en la siguiente sección: los ganchos pueden ser clasificados de otra forma. Hay ganchos de sistema (globales) que reciben mensajes para todos los hilos en el sistema, y ganchos específicos de un hilo (locales), que reciben mensajes sólo designados para un hilo individual. Puesto que un procedimiento de gancho global puede ser llamado en el contexto de cualquier aplicación (para capturar mensajes de todas las aplicaciones), debe estar localizado en una DLL (Dynamic Link Library). Esta restricción no se aplica a los ganchos específicos de un hilo, así que el procedimiento gancho puede estar ubicado en cualquier parte de la aplicación que es dueña del hilo a ser enganchado En este artículo trataremos solamente con ganchos globales. Instalando un procedimiento gancho WH_KEYBOARD en la cadena de ganchos ---------------------------------------------------------------------- La API de ganchos contiene 3 funciones muy importantes: SetWindowsHookEx (que instala un procedimiento gancho), UnhookWindowsHookEx (que desins- tala un procedimiento gancho) y CallNextHookEx (que llama al siguiente procedimiento gancho en la cadena de ganchos). Los parámetros que toman estas funciones se muestran abajo (de windows.pas): function SetWindowsHookEx(idHook: Integer; lpfn: TFNHookProc; hmod: HINST; dwThreadId: DWORD): HHOOK; stdcall; "idHook": tipo de gancho a instalar (por ejemplo WH_KEYBOARD); "lpfn": puntero la procedimiento gancho al que deben enviarse los mensajes; "hmod": manejador (handle) de la DLL que instala el gancho, general- mente hInstance para ganchos globales o 0 para ganchos locales; "HINST": identificador del hilo al que se asociará el gancho. Si es 0, el procedimiento de gancho se asociará con todos los hilos. Devuelve un valor usado para identificar el gancho. function UnhookWindowsHookEx(hhk: HHOOK): BOOL; stdcall; "hhk": identificador del gancho a desinstalar. Devuelve True si tiene éxito, False si fracasa. function CallNextHookEx(hhk: HHOOK; nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; "hhk": identificador del gancho actual; "nCode","wParam","lParam": parámetros que deberían ser enviados al siguiente procedimiento en la cadena de ganchos. Devuelve el valor retornado por el siguiente procedimiento en la cadena. Más adelante veremos en el ejemplo lo que significa. El procedimiento gancho ----------------------- El procedimiento gancho para un gancho de teclado tiene un formato estándar que y para que el gancho funcione, el programador debe proveer este formato exacto: function HookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; "nCode": = HC_ACTION - los parámetros wParam y lParam contiene información acerca del mensaje de teclado. = HC_NOREMOVE - los parámetros wParam y lParam contiene información acerca del mensaje de teclado, y el mensaje de teclado no ha sido removido de la cola de mensajes (una aplicación llamó la función PeekMessage especificando la bandera PM_NOREMOVE). "wParam": especifica el código de tecla virtual de la tecla que generó el mensaje (por ejemplo VK_F9 para la tecla de función F9). "lParam": especifica información adicional (como la cantidad de repeticiones, el código de exploración, ...); no usado en nuestro programa (ver Win32SDK para detalles). HookProc debería devolver un valor no nulo para impedir que Windows pase el mensaje al resto de la cadena de ganchos o al procedimiento de ventana destino, o cero para permitir que Windows pase el mensaje al procedimiento de ventana destino. Ejemplo ------- Este ejemplo crea un gancho global sobre el teclado y cuando ocurre una cierta combinación de teclas realiza algo significativo: WinKey + F9: Muestra la ventana principal si está oculta; WinKey + F10: Eyecta la bandeja de CDROM; WinKey + F12: Termina la aplicación. La comunicación entre la DLL que implementa el gancho y la aplicación se realiza con la función API SendMessage, la que envía un mensaje HOOK_MSG (definido en constants.inc) a la aplicación principal, con el comando (SHOW, EJECT, QUIT) en wParam (ver más abajo). Dado que no queremos ser molestados por el formulario siendo mostrado todo el tiempo, al hacer clic en el botón Minimizar se oculta (incluso de la lista de tareas), pero puede ser mostrado más tarde con la combinación Winkey+F9. Para el código fuente completo ver el archivo adjunto. Aquí sólo mostraré las partes más importantes de la aplicación: 1. HookDll.dpr function KeyboardProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var Handled: Boolean; KeyState: TKeyboardState; Han: HWND; function WinKeyPressed: boolean; begin Result := (KeyState[VK_LWIN] and $80 <> 0) or (KeyState[VK_RWIN] and $80 <> 0); end; begin Handled := False; Result := 1; if nCode = HC_ACTION then begin GetKeyboardState(KeyState); Han:=FindWindow('TForm1', APP_CAPTION); if (IsWindow(Han)) and (KeyState[wParam] and $80 <> 0) and WinKeyPressed then begin Handled := True; case wParam of VK_F9: SendMessage(Han,HOOK_MSG, APP_SHOW, 0); VK_F10: SendMessage(Han,HOOK_MSG, EJECT_CDROM, 0); VK_F12: SendMessage(Han,HOOK_MSG, APP_QUIT, 0); else Handled := False; end; end; end; if not Handled then Result := CallNextHookEx(hhk, nCode, wParam, lParam); end; Al entrar el procedimiento gancho comprobamos la bandera HC_ACTION en nCode (así sabemos si tenemos una acción de teclado), y luego guardamos en KeyState el estado (si está presionada o levantada, invertida con CapsLock, etc.) para todas las teclas virtuales usando GetKeyboardState. También encontramos el manejador de ventana (window handle) de la apli- cación principal a la que enviaremos los comandos (APP_SHOW, EJECTCDROM y APP_QUIT). Si la encontramos (IsWindow(han)) y tenemos un mensaje de teclado PRESSED (KeyState[wParam] and $80 <> 0) y la tecla Winkey también está presionada, entonces enviamos un comando al formulario principal de acuerdo a la tecla que ha sido presionada. Si no podemos manejar el mensaje de teclado (Handled=False), entonces se lo pasamos al siguiente gancho en la cadena. 2. Hooks.Dpr y Unit1.pas La función más importante aquí es HOOK_MSG_PROC, que es la que recibe los comandos enviados desde la DLL: type TForm1=class(TForm) ... procedure HOOK_MSG_PROC(var Msg: TMessage); message HOOK_MSG; ... end; ... procedure TForm1.HOOK_MSG_PROC(var Msg: TMessage); begin case Msg.WParam of APP_SHOW: begin Application.ShowMainForm := True; Visible:=True; end; EJECT_CDROM: mciSendString('set CDAudio door open',nil,0,0); APP_QUIT: Close; end; end; La característica "ocultar al minimizar" se logra capturando el mensaje WM_SYSCOMMAND que envía Windows cuando ocurre un mensaje de sistema (como cerrar, minimizar, maximizar). Entonces ocultamos el formulario si tenemos un comando SC_MINIMIZE: procedure TForm1.OnMinimize(var Msg: TMessage); begin if Msg.WParam = SC_MINIMIZE then begin if not IsHookInstalled then begin ShowMessage('Primero instale el gancho o no'#13#10 + 'podrá acceder al programa'); Exit; end; Application.ShowMainForm := False; Visible := False; end else Inherited; end; To hide the program from the tasks list we use: function RegisterServiceProcess(dwProcessID, dwType: integer): integer; stdcall; external 'KERNEL32.DLL'; NOTE: The above hiding technique works only on Windows 9x. Of course this is only a very simple application of hooks, but the possibilities are numerous. A small spy program, perhaps! :) Anyway, if you have any questions about this article feel free to send me a note to <aaa111@go.ro>. __________________ NOTA: Se adjunta el código fuente completo. ________________________________________________________________________ ¿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 ________________________________________________________________________ 3. Codificar y decodificar Base64 (MIME) Por Daniel Wischnewski delphi3000@wischnewski.tv Escribí la siguiente unidad para reemplazar los componentes INDY TIdEncoderMIME y TIdDecoderMIME. Este "Codec" se usa principalmente en software de email. La razón principal fue la carencia de velocidad de estos componentes. La segunda razón fue que son componentes y consiguientemente requieran la VCL - una pesada carga adicional para sistemas no-VCL. Ambas rutinas están escritas en ensamblador y sobrecargadas en distintas versiones para fácil acceso. Estoy seguro que muchos de ustedes pueden incrementar la velocidad aún más. Por favor háganmelo saber (en inglés). Gracias. __________________ NOTA: Se adjunta el código fuente completo. ________________________________________________________________________ AnyShape Transpack v2.0 - por MindBlast Software (DELPHI + KYLIX) ¿Cansado de las aburridas ventanas rectangulares? AnyShape Transpack es un componente multiplataforma (Delphi/Kylix) que facilita la creación de ventanas transparentes y de formas extrañas con edición WYSIWYG, vista previa en tiempo de diseño, arrastre automático, verdaderos formularios en primer plano, combinación de regiones, y más. Shareware ($30). http://www.mindblastsoftware.com/?page=transpack&ref=PascalNL ________________________________________________________________________ 4. Ejemplo de un servicio Windows, con un hilo Por Kim Sandell - kim.sandell@nsftele.com www.nsftele.com Delphi 5 y 6 tienen una plantilla de proyectos para servicios, pero está incompleta. Este ejemplo se construye sobre esa plantilla y completa el servicio. También muestra cómo comenzar un hilo que emite un pitido cada dos segundos. Puede usarlo como base al desarrollar servidores y servicios. El ejemplo ha sido diseñada para Delphi 5-7 y funciona en Windows NT/2000/XP. La opción de inicio del servicio ha sido establecida a MANUAL. Si quiere hacer un servicio que se inicie automáticamente con Windows, entonces necesita cambias esto. ¡SEA CUIDADOSO! Si su aplica- ción se cuelga cuando está corriendo como un servicio, NO HAY FORMA de terminarla. __________________ NOTA: Se adjunta el código fuente completo. __________________ Author's Profile Summary: Name : Kim Sandell Born : 1973 Helsinki, Finland Skills : VB, Delphi (1-6), C/C++, SQL, Interbase, IP Networks. Special areas: System Service, Protocols, Security (VPN), Authentication, Servers (Deamons) + More Company: NSF Telecom Ab Title: CTO WWW : http://www.nsftele.com EMail: kim.sandell@nsftele.com ________________________________________________________________________ 5. Capturando la salida de una aplicación de consola Por Jochen Fromm <Jochen.Fromm@manserv.de> ¿Cómo ejecuta una aplicación de consola o DOS y captura su salida mientras está corriendo? ¿Por ejemplo, cómo captura la salida del comando FileCompare (FC)? Ya hay dos artículos acerca de este problema, http://www.delphi3000.com/articles/article_2112.asp http://www.delphi3000.com/articles/article_2298.asp pero obtienen la salida cuando el proceso ha finalizado. También hay dos artículos de Microsoft acerca de redireccionamiento de aplicaciones DOS: * Microsoft Knowledge Base Article - Q190351 HOWTO: Spawn Console Processes with Redirected Standard Handles http://support.microsoft.com/default.aspx?scid=kb;en-us;Q190351 * Microsoft Knowledge Base Article - Q150956 INFO: Redirection Issues on Windows 95 MS-DOS Applications http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q150956 La idea básica es ejecutar la aplicación de consola con CreateProcess y redirigir la salida con tuberías (pipes), permitiendo al proceso llamador acceder a la salida de la aplicación de consola. Es importante capturar la salida mientras el proceso se encuentra aún en ejecución. Si la tubería de salida se bloquea por un sobreflujo, la nueva información no podrá ser escrita desde la aplicación de consola a la tubería de salida, y el programa se detendrá. En este caso tenemos situación de "abrazo mortal" (deadlock): el usuario (proceso padre) está esperando que el proceso hijo termine, y el proceso hijo está esperando que el padre limpie el buffer. __________________ NOTA: Se adjunta el código fuente completo. ________________________________________________________________________ 6. Creación de Objetos - Introducción (0 de 3) Por Oscar A. Esqueda Cortes Antecedentes OOP ================ Antes de entrar a la programación de componentes, debemos recordar conceptos básicos de la programación orientada a objetos. Nota: En el boletín 36 se encuentra un articulo mío sobre POO (OOP por sus siglas en inglés), más extenso que esta parte. Considere leerlo. * ¿Que es POO? Básicamente no es un lenguaje, y tampoco es una técnica para hacer ventanitas y usar el Mouse, sino más bien es un conjunto de técnicas y metodologías (filosofías si quieren decirlo) para incrementar nuestra productividad al desarrollar software. El aumento de productividad significa tanto crear nuestros programas en poco tiempo, como también poder darles mantenimiento de una manera más rápida y eficaz. Las partes vitales de la POO son las clases y objetos, pero la piedra filosofal son: la Herencia, el Polimorfismo y la Encapsulación. * Definición de Clase Una clase, es simplemente una abstracción que hacemos de nuestra experiencia sensible. * Definición de Objeto Un objeto es un conjunto de datos y métodos que se comporta de acuerdo a las reglas de su clase. * Herencia Crear una clase a partir de otra, pero tomando todas sus caracte- rísticas y funcionamiento es heredar una clase. * Encapsulación El concepto de encapsulación consiste en implementar el comportamiento de una clase dentro de ella, sin que terceros ojos sepan como funciona. * Polimorfismo La idea del polimorfismo consiste en crear una clase base de la cual dependerán varias clases, por herencia claro, pero el comportamiento de una clase hija no tiene porque ser igual a otra, aunque tengan los mismos métodos. * Sobrecarga La sobrecarga no es estrictamente una característica OOP, pero la mencionamos aquí porque muchas veces se la asocia erróneamente con ella (posiblemente debido a su casi simultaneidad de aparición y porque es en la OOP donde más se observa se uso). La sobrecarga nos brinda versatilidad al permitirnos declarar más de una vez un mismo procedimiento o función con distintos parámetros (y opcionalmente distinto tipo de valor de retorno, en el caso de las funciones). Arquitectura VCL ================ La herencia es la piedra angular de la VCL de Delphi. Todo está basado en Clases y Objetos, desde la primera clase TObject que está declarada en la unidad System.pas. De esta clase base derivan todas las demás clases y componentes/controles con los que jugamos en tiempo de diseño. Diagrama de la VCL ------------------ Este es un diagrama muy simple y resumido, pero cumple los requisitos que necesitamos. (Por lo regular al comprar el Delphi, se entrega un mapa de las clases, péguenlo en la pared junto al poster de Cameron Díaz o quien tengan en la pared, JE). --------- | TOBJECT | --------- | |------------------| ----------- ------------- | EXCEPTION | | TPERSISTENT | ----------- ------------- | ------------ | TCOMPONENT | ------------ | ---------- | TCONTROL | ---------- | |----------------------| ----------------- ------------- | TGRAPHICCONTROL | | TWINCONTROL | ----------------- ------------- Veamos un poco de las características de las clases principales de Delphi. TObject ------- Esta clase es la clase principal en la VCL de Delphi. Todas las clases (u objetos) derivan de esta clase principal. Esta clase implementa información RTTI o de clases para identificación de las mismas. Es decir, mantiene métodos que identifican a cada clase. Por ejemplo vea algunos de ellos: - ClassInfo : Puntero a información del objeto. - ClassName : Nombre de la clase devuelta como string (útil para comparaciones). - ClassParent: Clase de la que heredamos el objeto, nil si es TObject. - ClassType : Clase actual, devuelve un tipo TClass. Esta clase base solamente da opciones de identificación de clases, construcción y destrucción de objetos básica. Para mas información busque TObject en la ayuda de Delphi. Los objetos que derivan de TObject son Exception, TIniFile y TRegistry entre otros, además de la siguiente clase en la escala jerárquica: TPersistent. TPersistent ----------- Como su nombre lo indica es útil para mantenerse, es decir, todas las clases que deseemos que se guarden en el archivo DFM de una forma deben heredar de TPersistent. Básicamente, contiene métodos para guardar información de la clase en Streams o conjunto de datos permanentes. Útil para objetos dentro de objetos, por ejemplo las propiedades HorzScrollBar y VertScrollBar de un TForm o las columnas de un DBGrid. Los objetos que derivan de esta clase son por ejemplo las colecciones como las columnas de un DBGrid o de un ListView. TComponent ---------- La clase TObject es la principal de toda la VCL, pero la TComponent es la principal para el diseño visual en Delphi. Todos los componentes no visuales (TTable, TDatasource, TTimer, TActionList) heredan de esta clase. Si vamos a crear un componente no visual, lo tendremos que derivar de TComponent. PROPIEDAD La clase TComponent introduce un concepto de propiedad, es decir, cuando uno crea componentes, digamos TLabel u otro, la llamada a su constructor es así: := TLabel.Create(Form1); donde decimos que el propietario del objeto es Form1. O sea que al destruirse Form1, se encarga de destruir sus objetos designados. Esto es útil para mantener una forma limpia de destrucción de objetos y liberación de memoria. NOTA: Aun así, si construye objetos en tiempo de ejecución, use un Try/Finally para destruirlos. Hay propiedades para el control de sus objetos designados, como: - ComponentCount: Total de componentes dependientes. - Componentes : Arreglo iniciando de 0 de los componentes designados al TComponent. EJEMPLO Viene un ejemplo llamado lstComp, para Delphi 5, donde muestra cómo funciona esto. Es una lista que se llena con todos los componentes de la forma. Además introduce el concepto de nombrado de objetos con su propiedad Name, concepto que no tienen las clases anteriores, para identificar a los componentes y sus descendientes. Existen dos propiedades que merecen un poco de tiempo: - ComponentState, que indica el estado del componente. Veamos algunas de sus propiedades. · csDesigning : El componente esta en tiempo de diseño. · csDestroying: El componente se esta destruyendo. - ComponentStyle, para asignar el comportamiento del componente, estos son algunos de sus valores: · csInheritable: puede ser heredado. Para la creación de componentes es útil el saber si estamos en tiempo de diseño o alguna otra situación. Los componentes derivados de TComponent son: TDatasource, TTable, TQuery, TTimer, y todos los no visuales que sólo se ven en diseño. TControl -------- Los componentes visuales derivan de TControl. Es raro que creen un componente de éste; lo mejor es de sus descendientes. La función de éste es definir la finalidad del componente Padre. A excepción del TForm, todo componente tiene un padre, que es su componente contenedor, los componentes como TPanel y TGroupBox entre otros, permiten agrupar componentes dentro de ellos. Además, el TControl introduce propiedades que controlan su visibilidad, como Top, Left, Width, Height y Visible, así como Fonts, Color, Anchors, entre otras, pero hay dos que merece la pena verlas con calma (parecidas al TComponent): - ControlState: indica el estado del control, veamos algunos de sus valores: · csCreating : El control se esta creando. · csLButtonDown : se capturo un evento de botón de Mouse. · csFocusing : el control trata de obtener el foco. - ControlStyle: la cual determina las características del control, el cual puede tener los siguientes valores: · csAcceptsControls : es un control contenedor. · csCaptureMouse : captura los eventos del Mouse. · csSetCaption : tiene titulo. · csMenuEvents : responde a eventos del menú del sistema. · csFixedWidth y csFixedHeight : Tamaño fijo. De nuevo pido al lector que se de una vuelta por la ayuda en el tema "TControl, ControlStyle" para mas información. Estas dos son útiles en el caso de querer comprobar el estado del control o el estilo del control nuevo, si es contenedor, aceptar controles de Mouse u otros casos. No hay objetos derivados de TControl que se usen directamente en la VCL. Más bien se heredan dos para los cuales se crean todos los objetos visuales: TGraphicControl y TWinControl. TGraphicControl --------------- Esta clase es la base para todos los objetos visuales que no reciben el foco. Implementa una clase llamada TCanvas en una propiedad llamada Canvas, la cual permite procedimientos de dibujo en ella. Los objetos que reciben un foco, deben llevar un manejador o Handle de ventana y requiere más recursos. Los GraphicControls usan los recursos de su Parent para dibujarse y no gastar más recursos de los que requeriría, por lo que un descendiente de TGraphicControl no tiene Handle o manejador y no puede ser manipulado con API's, pero sí puede recibir mensajes Windows o notificaciones. No recibe mensajes del teclado sino sólo del Mouse, por el motivo de no recibir el foco. Los controles que derivan de esta clase son: TBevel, TCustomLabel (TLabel y TDBText), TImage, TPaintBox, TShape, TSpeedButton, TSplitter y TToolButton (colección de TToolBar). TWinControl ----------- Los objetos TWinControl (TWidgetControl en Linux) encapsulan los objetos Windows. En realidad todos los controles visuales Windows son Ventanas, desde un punto de vista técnico, ya que todos tienen un Handle o Manejador, que es un identificador único en todo el sistema operativo, útil para las funciones API de Windows. Las características que implementa la clase son: - Poder recibir el foco y por lo tanto manejar eventos relacionados con el teclado. - Ser contenedor de otros controles, vea las propiedades mas útiles. Las propiedades más útiles son: - ControlsCount : Total de componentes dentro del contenedor. - Controls : Arreglo iniciando de 0 con los componentes contenidos, devuelve un TControl. - Handle : Manejador de ventana asignado por Windows. - ParentWindow : Manejador de su Parent (padre). - TabOrder y TabStop: Propiedades para el tab. EJEMPLO: El ejemplo que viene en el archivo adjunto muestra un TTreeView en el cual se llenan, en el orden que están, los Parent (padre) de los controles visuales. En realidad, sólo pocos objetos son creados directamente de TWinControl (TAnimate, THeaderControl, TProgressBar, TScrollBar), pero todos los controles Windows, heredan de esta. Las clases TCustomX ------------------- Ahora, casi todos los controles derivan de alguna clase base que inicia con TCustom, por ejemplo: TLabel = Class(TCustomLabel) TEdit = Class(TCustomEdit) TForm = Class(TCustomForm) Estas clases fueron creadas para poder crear componentes nuevos a partir de esos, es decir. Las clases como TLabel no traen nada distinto a la clase TCustomLabel, solo el hecho de publicar ciertas propiedades y métodos, para eso están las clases base TCustom. Veamos la clase TCustomLabel (tomada del código VCL de Delphi 6): TCustomLabel = class(TGraphicControl) private FFocusControl: TWinControl; FAlignment: TAlignment; FAutoSize: Boolean; FLayout: TTextLayout; FWordWrap: Boolean; FShowAccelChar: Boolean; FOnMouseLeave: TNotifyEvent; FOnMouseEnter: TNotifyEvent; function GetTransparent: Boolean; procedure SetAlignment(Value: TAlignment); procedure SetFocusControl(Value: TWinControl); procedure SetShowAccelChar(Value: Boolean); procedure SetTransparent(Value: Boolean); procedure SetLayout(Value: TTextLayout); procedure SetWordWrap(Value: Boolean); procedure CMTextChanged(var Message: TMessage); message CM TEXTCHANGED; procedure CMFontChanged(var Message: TMessage); message CM FONTCHANGED; procedure CMDialogChar(var Message: TCMDialogChar); message CM DIALOGCHAR; procedure CMMouseEnter(var Message: TMessage); message CM MOUSEENTER; procedure CMMouseLeave(var Message: TMessage); message CM MOUSELEAVE; protected procedure AdjustBounds; dynamic; procedure DoDrawText(var Rect: TRect; Flags: Longint); dynamic; function GetLabelText: string; virtual; procedure Loaded; override; procedure Notification(AComponent: TComponent; Operation: TOperation); override; procedure Paint; override; procedure SetAutoSize(Value: Boolean); override; property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify; property AutoSize: Boolean read FAutoSize write SetAutoSize default True; property FocusControl: TWinControl read FFocusControl write SetFocusControl; property ShowAccelChar: Boolean read FShowAccelChar write SetShowAccelChar default True; property Transparent: Boolean read GetTransparent write SetTransparent default False; property Layout: TTextLayout read FLayout write SetLayout default tlTop; property WordWrap: Boolean read FWordWrap write SetWordWrap default False; public constructor Create(AOwner: TComponent); override; property Caption; property Canvas; property OnMouseEnter: TNotifyEvent read FOnMouseEnter write FOnMouseEnter; property OnMouseLeave: TNotifyEvent read FOnMouseLeave write FOnMouseLeave; end; Todas las propiedades están en Protected y la clase TLabel, lo que hace es pasarlas a published, esto lo veremos en la siguiente parte de este articulo. TLabel = class(TCustomLabel) published property Align; property Alignment; property Anchors; property AutoSize; property BiDiMode; property Caption; property Color; property Constraints; property DragCursor; property DragKind; property DragMode; property Enabled; property FocusControl; property Font; property ParentBiDiMode; property ParentColor; property ParentFont; property ParentShowHint; property PopupMenu; property ShowAccelChar; property ShowHint; property Transparent; property Layout; property Visible; property WordWrap; property OnClick; property OnContextPopup; property OnDblClick; property OnDragDrop; property OnDragOver; property OnEndDock; property OnEndDrag; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnMouseEnter; property OnMouseLeave; property OnStartDock; property OnStartDrag; end; Reglas para escribir componentes -------------------------------- Para terminar, les paso unos cuantos tips para escribir componentes, los tome "prestados" de Marco Cantu (http://www.marcocantu.com, ya le tome esto de su libro, pues les paso la dirección de su pagina), espero sirva de orientación. * Estudiar el Lenguaje de Pascal Orientado a Objetos: Herencia, Sobrescritura y sobrecarga de métodos, la diferencia entra las partes publicas y privadas de una clase y la diferencia entra propiedades y eventos. (NOTA: lean mi artículo de OOP y también varios de estos conceptos los veremos en el próximo artículo). * Estudiar la jerarquía de las estructuras VCL (Nota: aquí tienen una pista en este artículo). * Crear componentes sencillos, imitar a otros componentes y evitar dependencias. * Usar excepciones. (bloques, try except, finally y el uso del raise con excepciones personalizadas). * Identificar a cada componente con un mapa de bits para la paleta de componentes, además de nombrar lo mas significativamente el componente, ponerle una notación al principio para identificar de quien son y diferenciarlos de otros ya existente (ToecLabel, por ejemplo). * Prepararnos para escribir código real, es decir, al escribir componentes por lo regular no se usara el aspecto Visual. Estas son reglas muy básicas, mas bien para orientarnos, en las siguientes ediciones haremos componentes, este fue el único artículo teórico, en el siguiente haremos 5 componentes y explicaremos un poco de ellos, además de darles el código fuente de ellos claro. Hasta la próxima Ing. Oscar A. Esqueda Cortes Information Technology Consulting http://www14.brinkster.com/itcmx oesqueda@att.net.mx ________________________________________________________________________ 7. Inline Assembler en Delphi (IV) - Registros Por Ernesto De Spirito <eds2004 @ latiumsoftware.com> Pasando registros como parámetros ================================= Al igual que los arreglos estáticos, los registros se pasan internamente como punteros a los datos, independientemente de si el parámetro se pasa por valor o por referencia (ya sea como "var" o como "const"). Dadas las siguientes declaraciones... type TRecord = record Id: integer; Name: string; end; var a, b: TRecord; procedure InitRecord(var r: TRecord; Id: integer; const Name: string); begin r.Id := Id; r.Name := Name; end; ...una llamada al procedimiento InitRecord en ensamblador sería así: // En Object Pascal: // InitRecord(a, n, s); // En Inline Assembler: asm lea eax, a // EAX := @a; // 1er parámetro en EAX mov edx, n // EDX := n; // 2do parámetro en EDX mov ecx, s // ECX := s; // 3er parámetro en ECX call InitRecord // InitRecord; end; Accediendo los campos de un registro ==================================== Los campos de un registro se encuentran a un cierto desplazamiento de la dirección del registro (la dirección del primer campo). En el ejemplo, asumiendo que tenemos la dirección de un registro de tipo TRecord en el registro EAX, el campo Id está ubicado en [EAX+0] (o simplemente [EAX]), y el campo Name está ubicado en [EAX+4], pero normalmente no escribimos "números mágicos". En vez de ello, para producir un código autoexplica- tivo y mantenible tenemos cinco formas alternativas: mov edx, [eax + TRecord.Name] mov edx, (TRecord PTR [eax]).Name mov edx, (TRecord [eax]).Name mov edx, TRecord[eax].Name mov edx, [eax].TRecord.Name Las cinco sentencias de arriba se ensamblarían como: mov edx, [eax + 4] En vez de un registro (como EAX), las sintaxis también se aplican a nombres de variables locales. Se puede inferir de la primer sintaxis que en inline assembler la expresión TipoRegistro.Campo se evalúa en tiempo de compilación como una constante representando el desplazamiento en el que se encuentra el Campo en el TipoRegistro. Por ejemplo, la siguiente sentencia es válida: mov ecx, TRecord.Name // mov ecx, 4 Volviendo al tema, el procedimiento InitRecord (introducido arriba) se puede implementar en ensamblador de esta forma: procedure InitRecord(var r: TRecord; Id: integer; const Name: string); asm // EAX = @r; EDX = Id; ECX = @Name[1] mov (TRecord PTR [eax]).Id, edx // EAX^.Id := EDX; // Id // _LStrAsg(@EAX^.Name, @Name) --> EAX^.Name := Name lea eax, (TRecord PTR [eax]).Name // EAX := @(EAX^.Name); mov edx, ecx // EDX := @Name[1]; call System.@LStrAsg // _LStrAsg(EAX, EDX) end; Al entrar al procedimiento tenemos EAX apuntando al registro (primer parámetro), EDX conteniendo el Id (segundo parámetro), y ECX apuntando a los datos de la cadena Name (tercer parámetro). Asignar un entero es bastante simple, pero asignar una cadena es un poco más complicado: If la cadena destino no es la cadena nula then begin Decrementar la cuenta de referencias de la cadena destino; If la la cuenta de referencias de la cadena destino es cero then Liberar la cadena destino; end; If la cadena origen no es la cadena nula then Incrementar la cuenta de referencias de la cadena origen; Asignar origen a destino; El procedimiento _LStrAsg (en la unidad System) implementa esta lógica por nosotros. El procedimiento recibe dos parámetros: el primero (en EAX) es la cadena destino pasada por referencia, y el segundo (en EDX) es la cadena origen pasada por valor (lo que en realidad se pasa es el puntero, pues las cadenas son punteros a los verdaderos caracteres). Consiguientemente, en nuestro caso, EAX debe apuntar a la dirección de la variable string que será asignada assigned (es decir, EAX debe contener la dirección de r.Name), mientras que EDX debe ser el valor a asignar: EAX --> r.Name --> r.Name[1] ==> EAX = @r.Name EDX --> Name[1] ==> EDX = @Name[1] Ref.: "-->" significa "apunta a" (o "contiene la dirección de") Así que establecemos EAX y EDX y luego llamamos a _LStrAsg: lea eax, (TRecord PTR [eax]).Name // EAX := @(EAX^.Name); mov edx, ecx // EDX := @Name[1]; call System.@LStrAsg // _LStrAsg(EAX, EDX) Funciones de bajo nivel para trabajar con registros =================================================== Al igual que con los arreglos estáticos, si un registro se pasa por valor entonces es responsabilidad de la función llamada preservar el registro. Cuando una función necesita cambiar los valor de uno o más campos de un registro pasado por valor, normalmente crea una copia local y trabaja sobre la copia. El compilador crea una copia por nosotros en el "begin" de funciones Pascal, pero en funciones totalmente en ensamblador tenemos que hacerlo por nosotros mismos. Una forma de hacerlo es como mostramos en la parte III con los arreglos estáticos. Aquí tenemos otra forma: procedure OperateOnRecordPassedByValue(r: TRecord); var _r: TRecord; asm // Copiar los elementos de "r" (parámetro) en "_r" (copia local) // Move(r, _r, sizeof(TRecord)); lea edx, _r // EDX := @_r; mov ecx, type TRecord // ECX := sizeof(TRecord); call Move // Move(EAX^, EDX^, ECX); lea eax, _r // EAX := @_r; mov edx, TRecord_TypeInfo // EDX := TRecord_TypeInfo; call System.@AddRefRecord // System._AddRefRecord(EAX,EDX); lea eax, _r // EAX := @_r; // opcional // Aquí va el resto de la función. Trabajaremos sobre el registro // "_r" (la copia local), ahora apuntado por EAX. end; En esta oportunidad hemos llamado al procedimiento Move en vez de copiar los datos allí mismo con REP MOVSB. De esta manera escribimos menos código. IMPORTANTE: Copiar los valores de memoria sólo funciona con registros que no contienen campos de tipos que cuentan referencia como las cadenas, arreglos dinámicos o variantes de tipo cadena o arreglo dinámico. Si tenemos uno o más campos de tipo cadena, o campos de cualquier otro tipo con conteo de referencias, después de copiar los valores de memoria debemos incrementar sus respectivas cuentas de referencias. El procedi- miento _AddRefRecord (en la unidad System) hace eso. Recibe dos pará- metros: un puntero al registro (en EAX) y un puntero a los datos de información de tipo para el registro generada por el compilador (en EDX). La información de tipo (type information) para un registro es básica- mente una estructura de datos que contiene las posiciones y tipos de los campos con conteo de referencias en el registro. Los procedimientos que trabajan con registros declarados en la unidad System (específicamente _InitializeRecord, _AddRefRecord, _CopyRecord y _FinalizeRecord) requieren un puntero a los datos de información de tipo como su último parámetro. Pero, ¿dónde están esos datos? Bueno, desafortunadamente no hay un símbolo para acceder su ubicación directamente. Tenemos que obtener su dirección llamando a la función TypeInfo, pero ésta no es una función que podemos llamar desde código en ensamblador porque no es una verda- dera función, sino una función incorporada (built-in) que el compilador resuelve en tiempo de compilación. Una solución posible es inicializar una variable global llamando a la función TypeInfo desde nuestro código Pascal: var TRecord_TypeInfo: pointer; : initialization TRecord_TypeInfo := TypeInfo(TRecord); Y luego podemos usar esta variable así: procedure OperateOnRecordPassedByValue(r: TRecord); var _r: TRecord; asm // Copiar los elementos de "r" (parámetro) en "_r" (copia local) // Move(r, _r, sizeof(TRecord)); lea edx, _r // EDX := @_r; mov ecx, TYPE TRecord // ECX := sizeof(TRecord); call Move // Move(EAX^, EDX^, ECX); // System._AddRefRecord(@_r, TypeInfo(TRecord)); lea eax, _r // EAX := @_r; mov edx, TRecord_TypeInfo // EDX := TypeInfo(TRecord); call System.@AddRefRecord // System._AddRefRecord(EAX, EDX); lea eax, _r // EAX := @_r; // opcional // Aquí va el resto de la función. Trabajaremos sobre el registro // "_r" (la copia local), ahora apuntado por EAX. // Tenemos que finalizar la copia local antes de regresar // System._FinalizeRecord(@_r, TypeInfo(TRecord)); lea eax, _r // EAX := @_r; mov edx, TRecord_TypeInfo // EDX := TypeInfo(TRecord); call System.@FinalizeRecord // System._FinalizeRecord(EAX, EDX); end; Notomos que antes de que la función retorne debemos hacer una llamada a _FinalizeRecord para destruir la copia local (por ejemplo, esto decre- mentará las cuentas de referencia de las cadenas apuntadas por campos de cadena). Llamar a Move y luego a _AddRefRecord es una forma válida de copiar registros si y sólo si el registro destino no ha sido inicializados (después de llamar a _AddRefRecord el registro queda inicializado). Si el registro destino ya estuviera inicializado, entonces tenemos que llamar a _CopyRecord en su lugar. Por ejemplo: procedure proc(const r: TRecord); var _r: TRecord; begin // _r := r; asm mov edx, eax // EDX := @r; lea eax, _r // EAX := @_r; mov ecx, TRecord_TypeInfo // ECX := TypeInfo(TRecord); call System.@CopyRecord // System._CopyRecord(EAX, EDX, ECX); end; end; Notemos que puesto que ésta es una función Pascal normal (no una función enteramente en ensamblador), el compilador automáticamente genera código para inicializar y finalizar la variable de registro local (en el "begin" y el "end" del procedimiento respectivamente). La combinación Move más _AddRefRecord es idéntica en efecto a la combinación _InitializeRecord más _CopyRecord: procedure OperateOnRecordPassedByValue(r: TRecord); var _r: TRecord; asm // Copiar los elementos de "r" (parámetro) en "_r" (copia local) // System._InitializeRecord(@_r, TypeInfo(TRecord)); push eax // Push(EAX); // @r lea eax, _r // EAX := @_r; mov edx, TRecord_TypeInfo // EDX := TypeInfo(TRecord); call System.@InitializeRecord // System._InitializeRecord(EAX, EDX); // _r := r; lea eax, _r // EAX := @_r; pop edx // EDX := Pop(); // @r mov ecx, TRecord_TypeInfo // EDX := TypeInfo(TRecord); call System.@CopyRecord // System._CopyRecord(EAX, EDX, ECX); lea eax, _r // EAX := @_r; // opcional // Aquí va el resto de la función. Trabajaremos sobre el registro // "_r" (la copia local), ahora apuntado por EAX. // Tenemos que finalizar la copia local antes de regresar // System._FinalizeRecord(@_r, TypeInfo(TRecord)); lea eax, _r // EAX := @_r; mov edx, TRecord_TypeInfo // EDX := TypeInfo(TRecord); call System.@FinalizeRecord // System._FinalizeRecord(EAX, EDX); end; Al igual que _AddRefRecord, el procedimiento _InitializeRecord es sólo para ser usado con registros no inicializados. Devolviendo valores registro ============================ Devolver registros es exactamente lo mismo que devolver arreglos estáticos. Las funciones que devuelven registros reciben un último parámetro adicional que es el puntero a la ubicación de memoria donde deben colocar su valor de retorno, es decir, el valor del último parámetro es @Result. La memoria para el resultado debe ser asignada, inicializada, y liberada por el llamador (no es responsabilidad de la función llamada). Por ejemplo, consideremos la siguiente función: function MakeRecord(Id: integer; const Name: string): TRecord; begin Result.Id := Id; Result.Name := Name; end; La función se declara para recibir dos parámetros y devolver un registro, pero internamente es como un procedimiento que recibe tres parámetros: 1) EAX = el Id para el nuevo registro 2) EDX = el nombre para el campo Name del nuevo registro 3) ECX = la dirección del registro Result (@Result) La función puede ser rescrita en ensamblador como sigue: function MakeRecord(Id: integer; const Name: string): TRecord; asm // EAX = Id; EDX = @Name[1]; ECX = @Result mov (TRecord PTR [ecx]).Id, eax // ECX^.Id := EAX; // Id // (@Result)^.Id := EAX; // Result.Id := EAX; // Result.Name := Name; // System.@LStrAsg(@(Result.Name), @Name[1]) // System.@LStrAsg(@(ECX^.Name), @Name[1]) lea eax, (TRecord PTR [ecx]).Name // EAX := @(ECX^.Name); call System.@LStrAsg // _LStrAsg(EAX, EDX) end; NOTA: No asignamos el valor de EDX antes de llamar a _LStrAsg porque EDX ya contiene el valor deseado (pasado como parámetro). Llamando a funciones que devuelven registros ============================================ Consideremos el siguiente código: a := MakeRecord(n, s); Uno estaría tentado a pensar que el compilador lo traducirá como: asm mov eax, n mov edx, s lea ecx, a // ECX := @a; // @Result call MakeRecord end; Pero las cosas no suceden de esta forma, por lo menos no en Delphi 5. El compilador asigna e inicializa una variable local para alojar el resul- tado, y luego copia el registro resultado al registro destino. No sólo que tenemos una ineficiencia por realizar una copia que sería innece- saria, sino que -como vimos arriba- la copia misma no es tan inocente como una llamada al procedimiento Move (_CopyRecord comprueba los datos de la información de tipo en tiempo de ejecución para localizar los campos que requieren tratamiento especial). Desde luego, esa variable local invisible primero es inicializada y eventualmente es finalizada. Esta forma de hacer las cosas es terriblemente ineficiente. Si alguien necesita velocidad, mejor llame funciones que devuelven registros usando ensamblador como mostré arriba, pasando directamente la dirección de la variable que recibirá el registro resultado como último parámetro (@Result). Bien, esto es todo por ahora. En la siguiente parte veremos algunos conceptos básicos sobre trabajar con objetos. __________________ NOTA: Se adjunta el código fuente completo. ________________________________________________________________________ 8. 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. Estas reglas han sido tildadas por algunos de infantiles y déspotas, por decir lo menos. Para los que tienen buena experiencia en foros y listas de correo, estas reglas prácticamente no aportan nada nuevo, pero para otros admito que pueden resultar molestas y algo chocantes. Realmente lo siento, pero si he decidido establecerlas, no ha sido porque sí. Los foros son para profesionales, y no para quienes desean publicar mensajes como se les da la gana simplemente porque es gratis, sino que esperamos un mínimo de seriedad y consideración hacia los demás. He aquí el extracto de las reglas comunes a todos los foros: * El asunto de los mensajes tiene importancia capital. Es lo primero y a veces lo único que se ve de un mensaje. 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). Los foros no son un motor de búsqueda humano. * Incluye abundante información sobre el problema que planteas (como por ejemplo versión del producto y sistema operativo que usas, etc.) para no hacerle perder el tiempo a alguien preparando una respuesta que después no te sirva porque no se aplica a tu plataforma. * 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). * Los archivos adjuntos en los mensajes son descartados. Si tienes algo para compartir, contacta directamente al interesado, u ofrécelo en el foro aclarando que las peticiones deben enviarse a tu cuenta de email, y no a la dirección del foro. * Por cualquier cuestión administrativa del foro (como por ejemplo problemas con tu suscripción, reportar casos de spam, etc.) no escribas al foro sino a su/s moderador/es. 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 ________________________________________________________________________ 9. Delphi en la Red Por Dave Murray <irongut @ vizzavi.net> Componentes, librerías y aplicaciones ===================================== Freeware -------- * Copernic Agent 6.0 - Freeware (adware, but not spyware) *NEW* It's the successor of Copernic 2001 5.0, the top metasearch software for the Internet ("Top Ten Internet Tools" by USA Today, 5-star rating from ZDNet, and "Best For 2001 - Top Five Software" by PC Magazine). Are you tired of wasting your time with meaningless results from search engines? Try searching with Copernic. It will surprise you! http://www.copernic.com/desktop/products/agent/index.html * MathX 2D and 3D graphics of one- and two-variables functions using OpenGL. Full source code is included. http://www.opensource.as.ro/public/MathX.zip Artículos, trucos y consejos ============================ * Migrating BDE Applications to dbExpress - by Bill Todd This white paper discusses the migration of BDE-based applications to dbExpress. http://community.borland.com/article/0,1410,29106,00.html * Cross-platform Development with Borland RAD Tools A white paper on native cross-platform development with Borland tools. http://community.borland.com/article/0,1410,29139,00.html * Report to the Delphi Community on Project JEDI - by Alan C. Moore Alan C. Moore, the Project JEDI director, provides an update on the many projects under development with the Project JEDI team. http://community.borland.com/article/0,1410,29157,00.html * Borland Kylix 3 versus Linux GCC Development - by William Roetzheim http://community.borland.com/article/0,1410,29171,00.html * Using the .NET Preview compiler in the Delphi 7 IDE - by John Kaster An Open Tool for using the preview compiler with the Delphi 7 IDE is available for download. http://community.borland.com/article/0,1410,29159,00.html * Top Windows API Books for Delphi Developers - by Zarko Gajic Recommended selection of top books on programming Delphi with Windows API, with links to book reviews. Books cover all of the most common Windows API functions, and each function has the syntax and an example of its use in Delphi Pascal. http://delphi.about.com/library/toppicks/aatpdelphiapibook.htm * How to validate an IBAN? http://www.swissdelphicenter.ch/en/showcode.php?id=1470 * How to get the installed keyboard layouts? http://www.swissdelphicenter.ch/en/showcode.php?id=1471 * How to get/set the caret blink time? http://www.swissdelphicenter.ch/en/showcode.php?id=1472 * How to encrypt/decrypt files with Windows NTFS functions? http://www.swissdelphicenter.ch/en/showcode.php?id=1473 * How to get mouse wheel line count? http://www.swissdelphicenter.ch/en/showcode.php?id=1474 * How to obtain all characters in Delphi 4+ IDE - by m3Rlin www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=179 * How to obtain object property list - by m3Rlin www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=180 * How to refresh Windows desktop - by m3Rlin www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=181 * How to draw rotated text - by m3Rlin www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=182 * How to swap two numbers without a third variable - by m3Rlin www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=183 * How to turn numlock on by code - by m3Rlin www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=184 * Access a MySQL database from Delphi Standard or Personal - TheSaviour How to access a MySQL database from Delphi Standard or Personal using the TMySQL component. www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=185 * How to sort a TList - by m3Rlin www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=186 * How to set the width of a TComboBox - by m3Rlin www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=187 * How to access a remote registry - by m3Rlin www.delphifaq.net/modules.php?op=modload&name=FAQ&op=view&id=188 * How to change a property of all components at one time - by M. Suesens How to change a special property of all components that own this property at one time. http://www.delphi3000.com/articles/article_3365.asp * CPU ID unit - by Mironescu Tony http://www.delphi3000.com/articles/article_3367.asp * How to implement a Sequential List in a database - by Adesh Jain http://www.delphi3000.com/articles/article_3372.asp * Export ALL tables from MS jet to CSV via ADO - by John Pears http://www.delphi3000.com/articles/article_3373.asp * High speed parser V1.5 - by Yuriy Pisarev Component is intended for some mathematics and logical calculations. Works at high speed - about 10000000 operations per second for simple mathematics formulas and a little more for logical formulas. http://www.delphi3000.com/articles/article_3374.asp * Safety Design with a Static Instance - by Max Kleiner How to build a real Singleton? http://www.delphi3000.com/articles/article_3376.asp * Interbase Backup on the Fly in a thread - by Kim Sandell Make interbase database backups on the fly, in a background thread. http://www.delphi3000.com/articles/article_3378.asp * Example of a Windows Service, with a thread - by Kim Sandell Delphi 5&6 has a template project for services, but it is incomplete. This example builds on that template and completes the service. It also shows how to start a thread that beeps every 2 seconds. You can use this as a base when developing servers as services. http://www.delphi3000.com/articles/article_3379.asp * Interbase Sweep on the Fly in a thread - by Kim Sandell In the Interbase Admin components there is a IBValidationService but is hard to use as it is. Sweeping is just one of the functions of the validation service. This component makes doing sweeps of databases alot easier, and also works in a thread. http://www.delphi3000.com/articles/article_3380.asp * How to write a TCP Redirector - by Kim Sandell Many people ask how to write servers in Indy, this primer goes through how a TCP server is created, and how to redirect all traffic to another remote server. This is the same as port-mapping in firewalls. http://www.delphi3000.com/articles/article_3381.asp * ENTER instead of TAB key - by Léo Souza A simple alternative to allow form navigation with the ENTER key. http://www.delphi3000.com/articles/article_3382.asp * How to create a animated (rotating) hourglass - Henk Schreij http://www.delphi3000.com/articles/article_3383.asp * How to implement an Array Property - Max Kleiner In an interface we can't use fields so when you declare a class that implements one or more interfaces, you must provide an implementation of all the methods declared in the interface and the fields too. http://www.delphi3000.com/articles/article_3387.asp * Change the color of a Listview or TreeView - by LExter LExter http://www.delphi3000.com/articles/article_3388.asp * SQL without bureaucracy - by Josir Gomes How to quickly run SQL without dropping components on your form. http://www.delphi3000.com/articles/article_3389.asp * Keyboard Hook - by William Egge Creating a keyboard hook in your application. http://www.delphi3000.com/articles/article_3390.asp * Converting a SID to a string - by Bryan Ashby Convert a Security Identifier (SID) into a human-readable string. http://www.delphi3000.com/articles/article_3391.asp * Changing Creation and Last accessed date/time for files - David Bolton http://www.delphi3000.com/articles/article_3392.asp * How to check if an OLE object is installed - by Mike Shkolnik http://www.delphi3000.com/articles/article_3394.asp * How to read contact list from MS Outlook - by Mike Shkolnik http://www.delphi3000.com/articles/article_3395.asp * Fast data transfer to MS Excel - by Mike Shkolnik http://www.delphi3000.com/articles/article_3396.asp * Multi Lingual BoolToStr() and SexToStr() - by Mike Heydon http://www.delphi3000.com/articles/article_3398.asp Tutoriales ========== * Introducción a las aplicaciones MDI - por Pablo Castagnino Introduce al programador al mundo de las aplicaciones MDI en Delphi y aporta soluciones a problemas típicos que se presentan al programar este tipo de interfaz. http://webs.sinectis.com.ar/alvadel/docs/mdi.htm * Breve introducción a la programación multihilo - por Enrique Gonzalez Algunos conceptos básicos obre programación multihilo, y ejemplo. http://webs.sinectis.com.ar/alvadel/docs/multihilo.htm * Navigating and Editing a ClientDataSet - by Cary Jensen You navigate and edit a ClientDataSet in a manner similar to how you navigate and edit almost another other dataset. This article provides an introductory look at basic ClientDataSet navigation and editing. http://community.borland.com/article/0,1410,29122,00.html * Sophisticated Delphi Pascal techniques - by Zarko Gajic A Beginner's Guide to Delphi Programming: Chapter 7. Time to extend your Delphi Pascal knowledge to the max. Here are some intermediate Delphi problems and articles for everyday development tasks. http://delphi.about.com/library/weekly/aa091702a.htm * Designing an XML Grammar with DTDs - by Philip Page XML is a great medium for data transfer and definition, but it must be consistent to make it consumable. Learn more about creating a DTD to determine consistent XML. http://builder.com.com/article.jhtml?id=u00320021004ppg01.htm * SQL Basics: Creating and Altering Tables - by Shelley Doll Learn the basic DDL commands to add, alter, and remove tables and databases with this article from the Builder.com SQL basics series. http://builder.com.com/article.jhtml?id=u00320020902dol01.htm * SQL Basics: Number Data Types - by Shelley Doll Failing to understand number data types poses a DBA's greatest risk of compromised data. The SQL92 standard dictates how database manufacturers define number behaviors, such as length and truncation. http://builder.com.com/article.jhtml?id=u00320020924dol01.htm * SQL Basics: String Data Types - by Shelley Doll Data type implementations vary from database to database but a working knowledge of the SQL specification will always give you a good idea of what's going on. This article breaks down the basic rules of deploying string data types. http://builder.com.com/article.jhtml?id=u00320020918dol01.htm * A Guide to Automatic Garbage Collection Systems - by Paul Tyma Java and .NET feature automatic garbage collection, which allows you to worry about programming instead of system cleanup. Learn more about the approaches often used to add this feature to applications. http://builder.com.com/article.jhtml?id=u00320020930gcn01.htm Otros enlaces ============= * GLScene en español La primera página sobre GLScene, OpenGL y Delphi en español. Demos, manuales y artículos. http://glscene.tripod.com * Delphi 7 Update 1 - by Anders Ohlsson This update for Delphi 7 contains an updated MSSQL driver that fixes the problem with empty user names and passwords. It also fixes an issue with extra NULL characters being added to VARCHAR columns. The update also contains several documentation updates. http://community.borland.com/article/0,1410,29209,00.html * Delphi 7/.NET User Group Tour 2002, US / Canada - by David Intersimone Borland is taking Delphi 7 and the Delphi Preview for Microsoft .Net on the road in the US and Canada. http://community.borland.com/article/0,1410,29089,00.html * The Delphi Bug List http://buglist.jrsoftware.org/ * Pascal and its Successors - by Niklaus Wirth Pascal was designed in 1969 in the spirit of Algol 60 with a concisely defined syntax representing the paradigm of structured programming. With the advent of the micro computer it became widely known and was adopted in many schools and universities. In 1979 it was followed by Modula-2 which catered for the needs of modular programming in teams. In an effort to reduce language complexity and to accommodate object- oriented programming, Oberon was designed in 1988. This article presents some aspects of the evolution of this family of languages. http://www.swissdelphicenter.ch/en/niklauswirth.php * Pascal IRC channel There is a very nice IRC channel about Pascal on DalNet (http://www.dal.net). The channel is just about Pascal (not Delphi). You can find it on irc.dal.net at #turbopascal. The channel also has a nice page with lots of sample codes. You can find their homepage at http://www.pastcow.org - As you can imagine, a channel for Delphi users can also be found there: #delphi. * BorCon Europe London UK, October 28-29 2002 http://www.borconeurope2002.com/ * BorCon Japan Tokyo Japan, November 19-20 2002 http://www.borland.co.jp/ * BorCon France Paris France, November 21-22 2002 http://info.borland.fr/conference/2002/ ________________________________________________________________________ ¡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/p0040.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!






