Boletín Pascal #49
Los ejemplos completos de código fuente de este número están disponibles para descargar.
![]() |
![]() |
Boletín Pascal #49 - 30-SEP-2003 Índice 1. Unas palabras del editor 2. Atributos de clase al estilo Delphi 3. Creando un Experto de Delphi La forma más simple de crear un Experto de Delphi 4. Dentro de las Clases e Interfaces de Delphi (I) 5. Notas de un desarrollador (III) Abrir un archivo con la aplicación predeterminada 6. Validando números de CBU 7. Foros / listas de correo 8. Delphi en la Red - Componentes, librerías y aplicaciones · Shareware · Freeware · Actualizaciones de Delphi y otros productos Borland - Artículos, trucos y consejos - Tutoriales y capacitación - Otros enlaces - Noticias ________________________________________________________________________ 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 Estoy muy contento de poder anunciar que el boletín alcanzó los 10.000 suscriptores. Muchas gracias a todos los suscriptores que hicieron esto posible refiriendo el boletín a sus colegas, y también a los webmasters que publicaron un enlace a nuestro sitio, permitiendo que el sitio web sea conocido en la comunidad Delphi. En esta edición tenemos un artículo de Demian Lessa mostrándonos cómo implementar atributos de clase en Object Pascal, un artículo de Daniel Wischnewski explicando cómo crear un Experto Delphi sencillo, un artículo de Ezra Hoch revelando el funcionamiento interno de clases e interfaces, un artículo de Alirio Gavidia sobre asociaciones de archivos y uno breve mío mostrando cómo validar número de CBU. Gracias a los autores por contribuir sus artículos para esta edición, y los premios disponibles para esta edición son para: * Demian Lessa ("Atributos de clase al estilo Delphi") · NTTools 7 For Delphi - por i-tivity (USD 39.95) ¡Basta de batallar con la API de Seguridad de Windows NT! Obtenga su copia de NTTools 7 para Delphi 4/5/6/7 ahora y ahórrese incontables horas con esta colección de 40 componentes VCL escritos específica- mente para tratar con las funciones de Seguridad de Windows NT. Se incluye código fuente completo. http://www.i-tivity.biz/nttools.htm * Daniel Wischnewski ("Creando un Experto de Delphi") · LMD SearchPack 2.0 - por LMD Innovative (EUR 39) LMD SearchPack incluye 3 controles para integrar capacidades avanzadas de búsqueda de textos en su proyecto, incluyendo soporte de operadores AND, OR, NEAR y NOT. Viene con código fuente y extensivos ejemplos. http://www.ceberus.com/lmd/products/index.php3#P6 Para la próxima edición tenemos disponibles los siguientes premios para para dos de los autores que colaboren artículos (en inglés): * EurekaLog v4.1.1 - por Fabio Dell'Aria (Std $24, Pro $49, Ent $99) EurekaLog le confiere a su aplicación (GUI, consola, Web, etc.) la habilidad de capturar cada excepción que se produzca, generar un registro detallado (con unidad, clase, método y número de línea) y enviarlo por email. Se integra completamente en el IDE, y Ud. sólo tiene tiene que hacer un simple "build" para añadir EurekaLog a sus aplicaciones. No disminuye el rendimiento de las aplicaciones e incrementa el tamaño del archivo compilado en sólo un 0.5% - 4%. Compatible con Delphi 3 - 7 y todas las plataformas de Windows. http://www.eurekalog.com/bannerclick.php?id=15 * SMExport v4.30 - por Scalabium Software ($20 estándar, $35 c/fuentes) Conjunto de componentes VCL nativos para exportar datos de distintos orígenes (datasets, grids, cubos de decisión, memoria, árboles DevExp, etc.). Exporta a MS Excel, MS Access, MS Word, PDF, Text/CSV, HTML, XML, dBase, RTF, SQL, Lotus 1-2-3, QuattroPro y más. http://www.scalabium.com/ Bien, eso es todo por ahora. Espero que disfruten esta edición. Saludos, Ernesto De Spirito eds2004 @ latiumsoftware.com __________________ Colaboraron en esta edición: Dave Murray ________________________________________________________________________ Help & Manual 3, por EC Software · Shareware ($ 279) - Una herramienta visual de autoría de ayuda para generar archivos WinHelp (.HLP), Adobe PDF, páginas HTML y los nuevos archivos HTML HELP (.CHM) introducidos en Windows 98, así como otros formatos de archivo y documentación impresa, todo desde una misma fuente. Una herramienta imprescindible para cualquier desarrollador de software. http://www.helpandmanual.com/ ________________________________________________________________________ 2. Atributos de clase al estilo Delphi Por Demian Lessa <demian @ knowhow-online.com.br> En una reciente discusión sobre atributos de clase en el foro delphi-br en Yahoo! Grupos, tuve la chance de aprender una nueva técnica que permite la implementación práctica de las atributos de clase en Delphi. Pero, ¿qué son estos atributos de clase? Las atributos de clase son valores asociados a una clase y no sus instancias. Es decir el valor del atributo de clase es el mismo para todas las instancias de la clase. ¿Y para qué son útiles los atributos de clase? Puedo sugerir dos utilidades muy obvias: conteo de instancias de clase y asociación de una instancia objeto a una clase como un todo (para propósitos de gestión). Cuando uno necesita llevar la pista del número de instancias de una clase, puede hacerlo usando una variable global a la unidad en la sección Implementation. Esto garantiza que la variable no sea cambiada por código fuera de la unidad, pero otras porciones del código dentro de la unidad (incluso fuera de la clase) todavía pueden cambiar el valor de esa variable. Encapsulando este valor en un atributo de clase se resuelve el problema y la cuenta de instancias sólo puede ser modificada mediante llamadas apropiadas a los métodos de la clase. Otro uso importante de las atributos de clase se relaciona con el uso de objetos de gestión o de apoyo. Imagínese, por ejemplo, que en vez de contar las instancias de una clase deseamos guardar una lista de las instancias de nuestra clase que están corriendo. Todo lo que tenemos que hacer es definir un atributo de clase para mantener una lista de las instancias de la clase. Este objeto lista puede ser instanciado cuando sea necesario, y destruido por ejemplo en la sección Finalization de la unidad. ¡Esto puede incluso utilizarse como base para un mecanismo simple de colección de basura! La implementación de los atributos de clase en Delphi se presenta abajo. Los valores de los atributos de clase se ocultan dentro de la clase y sólo se pueden cambiar con llamadas a los métodos apropiados. El truco de cómo encapsular el valor me fue presentado por Marcelo Almeida, uno de los moderadores del foro delphi-br en Yahoo! Grupos. type TMiClase = class private class function Attribute: PInteger; class function InstanceList: Pointer; class procedure DestroyInstanceList; public constructor Create; class function GetAttribute: Integer; class function GetInstanceList: TObjectList; class procedure SetAttribute(Value: Integer); end; class function TMiClase.Attribute: PInteger; {$J+} const placeholder: Integer = 0; {$J-} begin Result := @placeholder; end; class function TMiClase.InstanceList: Pointer; {$J+} const placeholder: TObjectList = nil; {$J-} begin if (TObjectList(Pointer(@placeholder)^) = nil) then // destruyamos nuestros objetos placeholder := TObjectList.Create(false); Result := @placeholder; end; class procedure TMiClase.DestroyInstanceList; begin if (GetInstanceList <> nil) then begin GetInstanceList.Free; TObjectList(InstanceList^) := nil; end; end; class function TMiClase.GetAttribute: Integer; begin Result := Attribute^; end; class function TMiClase.GetInstanceList: TObjectList; begin Result := TObjectList(InstanceList^); end; class procedure TMiClase.SetAttribute(Value: Integer); begin Attribute^ := Value; end; constructor TMiClase.Create; begin inherited Create; SetAttribute(GetAttribute + 1); GetInstanceList.Add(Self); end; destructor TMiClase.Destroy; begin SetAttribute(GetAttribute - 1); GetInstanceList.Remove(Self); if (GetInstanceList.Count = 0) then DestroyInstanceList; inherited Destroy; end; En TMiClase, los métodos de clase Attribute e InstanceList son los responsables de encapsular los valores de los atributos de clase. En estos métodos se usan constantes tipadas locales (directiva $J+) para alojar los atributos de clase. Las constantes tipadas pueden cambiar su valor en tiempo de ejecución igual que las variables. Pero las constantes que usamos son locales, así que, ¿cómo pueden almacenar valores globales para la clase? La respuesta es bastante simple: no utilizamos los valores de las constantes. Las constantes se declaran para que el compilador reserve la memoria apropiada para sus tipos de valores. Y, aunque declaradas como locales, la memoria que el compilador reserva para ellas (representado por un simple puntero) no se cambia a través de la ejecución del programa y, por lo tanto, podemos utilizar esta memoria para implementar nuestros atributos de clase. Astuto, ¿no? Los métodos Attribute e InstanceList devuelven punteros a la memoria reservada por el compilador para las constantes tipadas locales. ¡Éste es el gran truco! En el código adjunto encontrarán los fuentes completos para TMiClase y una pequeña aplicación mostrando el uso de los atributos de clase de TMiClase. ________________________________________________________________________ ¡Vote por el Boletín Pascal en el DPSC Top 100 Programming web sites! (sólo cliquea "here" donde dice "Click here to vote!", y eso es todo) http://www.sandbrooksoftware.com/cgi-bin/TopSite2/rankem.cgi?id=latium ________________________________________________________________________ 3. Creando un Experto de Delphi La forma más simple de crear un Experto de Delphi Copyright © 2003 Daniel Wischnewski. Visite mi empresa http://www.gatenetwork.com Versión en alemán de este artículo disponible en http://www.delphipraxis.net/referenzen.php Introducción ============ A veces uno desea definir algunas rutinas para hacer su vida más fácil mientras usa Delphi. Una manera simple de hacer esto es creando un Experto. Este primer artículo le muestra los fundamentos. Este artículo lo introduce al mundo de los Expertos de Delphi. Los Expertos de Delphi son DLLs que serán cargadas durante la secuencia de inicialización de Delphi. Este artículo apareció primero en alemán en Delphi-PRAXiS: http://www.delphipraxis.net/viewtopic.php?t=5300 NOTA: Las técnicas mostradas en este artículo son válidas comenzando con Delphi 3 o 4 y son desaprobadas desde Delphi 7, aunque todavía siguen siendo completamente soportadas por el IDE de Delphi. Instalación de un Experto para el IDE de Delphi =============================================== Cada Experto Delphi debe ser registrado en el Registro de Windows. Para cada versión de Delphi instalada en una máquina, así como para cada usuario usando la máquina, el Experto Delphi debe registrarse separada- mente. En el Registro, el Experto Delphi debe registrarse bajo la clave: HKCU\Software\Borland\Delphi\X.0\Experts donde X tiene que ser substituido por la versión apropiada de Delphi que se soporta. Puede suceder que la clave Experts no esté instalada, y en tal caso debe ser creada. Bajo la clave Experts usted tiene que crear un valor de cadena para el Experto de Delphi. El nombre debe ser único y el valor debe apuntar a la DLL del Experto, incluyendo tanto el camino completo como el nombre del archivo del Experto de Delphi. La vez próxima que Delphi levante, el Experto será cargado automáticamente. La interfaz del Experto de Delphi ================================= A fin de que el Experto de Delphi interactúe con el IDE de Delphi tiene que exportar una función con el nombre ExpertEntryPoint, usando los siguientes parámetros: function InitExpert( ToolServices: TIToolServices; RegisterProc: TExpertRegisterProc; var Terminate: TExpertTerminateProc): Boolean; export; stdcall; El primer parámetro, ToolServices, ofrece todas los interfaces "documentadas" al IDE de Delphi. El segundo parámetro, RegisterProc, se utiliza para cargar el Experto en el IDE de Delphi. El último parámetro, Terminate, se emplea para notificar a la DLL del Experto cuando esté a punto de ser descargada por el IDE de Delphi. El método InitExpert devuelve True si el Experto ha sido cargado con éxito; de lo contrario devuelve Falso o bien genera una excepción para descargar la DLL del IDE de Delphi (véase la muestra de código para la solución). La clase PlugIn TIExpert ======================== Cualquier experto de Delphi debe ser derivado de la clase TIExpert que está declarada en la unidad ExptIntf. Esta clase define algunos métodos abstractos que deben ser implementados por cada PlugIn: GetName, GetAuthor, GetComment, GetPage, GetGlyph (diferente para Windows y Linux), GetStyle, GetState, GetIDString, GetMenuText y Execute. El propósito de cada método se explica en el código fuente que se adjunta. El más simple Experto de Delphi =============================== Este Experto de Delphi no hará demasiado, pero sirve para mostrar la forma básica de hacer el trabajo. Mostrará una entrada en el menú Help (comportamiento predeterminado). Una vez que el usuario cliquea el elemento de menú se llamará el método Execute del Experto. Se deben respetar los siguientes puntos a fin de tener el Experto trabajando: * El método GetState debe devolver [esEnabled] * El método GetStyle debe devolver esStandard * El método GetMenuText devuelve el texto a mostrar en el menú Help * El método Execute define la acción del experto al activarse El código fuente completo de este experto simple se encuentra adjunto. ________________________________________________________________________ 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 ________________________________________________________________________ 4. Dentro de las Clases e Interfaces de Delphi (I) Por Ezra Hoch Algunas palabras antes de comenzar: - Primero, deseo comenzar este artículo diciendo que todo el conoci- miento en este artículo se deriva de ver el desensamblador de Delphi 5. Por lo tanto todo lo escrito aquí es válido solamente para Delphi 5 y pudo cambiar por cualquier actualización o versión diferente. - Segundo, para entender completamente lo que se escribe en este artículo, usted tendrá que zambullirse en algo de código ensamblador. Explicaré lo que hace el código ensamblador, pero esté preparado, puede ser bastante complicado. Y ahora, a la substancia. En Delphi, una instancia de una clase es un simple puntero. Esto puede parecer extraño a algunas personas puesto que han usamos instancias en Delphi muchas veces y nunca tuvieron que tratarlos como punteros. Eso es correcto, pero sólo porque Borland fue bastante amable de envolver bellamente los punteros. Estos punteros en realidad apuntan a una estructura complicada en memoria, la que intentaremos comprender. Primero, demos un vistazo a la definición de una clase simple: TBoo1 = class FDataA, FDataB : Integer; end; var Boo1 : TBoo1; begin Boo1 := TBoo1.Create; end; Ahora miremos a lo que Boo1 apunta (Boo1 es un puntero , ¿recuerda?). Boo1 apunta a los siguientes valores, cada uno de 4 bytes de tamaño: Un puntero a la VMT de TBoo1 FDataA FDataB N. de T.: VMT = Virtual Methods Table = Tabla de métodos virtuales Ahora examinemos un descendiente de TBoo1: TBoo2 = class(TBoo1) FDataC, FDataD : Integer; end; var Boo2 : TBoo2; begin Boo2 := TBoo2.Create; end; Boo2 apuntará a los siguientes valores en memoria: un puntero a la VMT de TBoo2 FDataA FDataB FDataC FDataD Nótese que los valores a los que apunta Boo2 incluyen algunos de los valores a los que apunta Boo1. Eso es muy fácil de explicar - TBoo2 hereda de TBoo1 y por consiguiente debe incluir todos los campos que tiene TBoo1. Como regla general, podemos indicar que cada instancia de la clase apunta a los siguientes valores: un puntero a la VMT de la clase una lista de los campos de la clase madre una lista de los campos de la clase Ahora es tiempo de investigar las interfaces. Antes que podamos entender completamente las interfaces debemos entender la manera en que Delphi hace una llamada de método a una instancia de una clase. Lo que Delphi hace realmente es llamar a la función (o procedimiento) con un parámetro más aparte de los declarados, y ese parámetro es la misma instancia. Veamos un ejemplo: TMoo = class FData: Integer; procedure Act(Value: Integer); end; procedure TMoo.Act(Value: Integer); begin if Self.FData = Value then Self.FData := FData + 1 else Self.FData := Value; end; var Moo: TMoo; begin Moo := TMoo.Create; Moo.Act(15); end; ¿Cómo hace Delphi para implementar esto? Simple, 'TMoo.Act' en realidad se compila como un procedimiento que acepta dos(!) parámetros. Uno es el parámetro definido -'Value', de tipo entero- y el otro es una instancia de la clase TMoo. Cada vez que Delphi llama a 'Moo.Act' efectúa un cierto preprocesamiento de antemano, es decir, pasa la instancia de TMoo que está haciendo la llamada. Básicamente usted podría decir que cualquier llamada a un método de un objeto es traducida a una llamada regular a un procedimiento o función que acepte el objeto que hace la llamada como parámetro. En el ejemplo anterior, 'TMoo.Act' en realidad se compila a algo como esto: procedure TMoo_Act(Self: TMoo; Value: Integer); begin if Self.FData = Value then Self.FData := FData + 1 else Self.FData := Value; end; Es hora de volver a las interfaces. Considere el siguiente código: IKoo = interface function Calculate(Value: Integer): Double; end; function Evaluate(Koo: IKoo; Value: Integer): Double; begin Result := Koo.Calculate(Value); end; TKooA = class(TInterfacedObject, IKoo) function Calculate(Value: Integer) : Double; end; TKooB = class(TInterfacedObject, IKoo) procedure DoNothing; function Calculate(Value: Integer): Double; end; Cualquier clase que soporte IKoo puede ser pasada como una variable a la función 'Evaluate'. Cuando pasamos una instancia de TKooA a 'Evaluate' necesitamos llamar al primer método de TKooA, pero cuando pasamos una instancia de TKooB, necesitamos llamar al segundo método de TKooB! ¿Cómo sabrá Delphi qué función llamar cada vez?! Para comprender la respuesta, debemos repasar qué es realmente una interfaz (y cómo se implementa en Delphi). Una interfaz es simplemente una lista de métodos que una clase declara que implementa. Es decir, cada método en el interfaz se implementa en la clase. La manera que Delphi pone en práctica esto es como sigue: Cada interfaz que una clase soporta es realmente una lista de punteros a los métodos. Por lo tanto, cada vez que se hace una llamada a un método de una interfaz, la interfaz en realidad traslada esa llamada a uno de sus punteros a método, así dando la ocasión de actuar al objeto que en realidad implementa la interfaz. Explicaré esto vía el ejemplo de 'Koo' arriba: Cada vez que la función 'Evaluate' obtiene un parámetro del tipo IKoo, lo que realmente obtiene es una lista (con 4 elementos - IKoo hereda de IUnknown) de punteros a métodos. Si obtuviera una interfaz de IKoo que fue implementada por por TKooA, entonces el cuarto elemento en la lista de punteros-a-métodos apuntaría a 'TKooA.Calcualte'. Si no, apuntaría 'TKooB.Calcualte'. Por lo tanto, cuando se hace una llamada a 'IKoo.Calculate', en realidad se llamará al método al que apunta 'IKoo.Calculate' (ya sea 'TKooA.Calculate' o 'TKooB.Calculate'). Ésta es la manera en que Delphi implementa las interfaces. Y ahora veamos cómo Delphi almacena interfaces en memoria. Para cada instancia de una clase que soporte 'N' interfaces, necesitamos 'N' diferentes listas de punteros-a-método (una por cada interfaz). Pero estas listas son las misma dentro del ámbito de una misma clase, por lo tanto, para ahorrar memoria, mantenemos solamente 'N' punteros a estas listas por cada instancia (en vez de las listas mismas). Considere el siguiente código: ILooA = interface end; ILooB = interface end; TLoo = class(TInterfacedObject, ILooA, ILooB) FLooA, FLooB: Integer; end; Así es como se vería una instancia de TLoo en memoria: un puntero a la VMT de TLoo FRefcount IUnknown FLooA FLooB ILooB ILooA En general, cualquier instancia se varía así: un puntero a la VMT de la clase la estructura de la clase madre (excepto por el puntero a la VMT) el primer miembro de datos de la clase . . el último miembro de datos de la clase última interfaz en la lista de interfaces de la clase . . primera interfaz en la lista de interfaces de la clase Como dije al comienzo de este artículo, para realmente captar la manera en que Delphi instrumenta las clases y las interfaces debemos mirar el código ensamblador que Delphi produce. Primero aprenderemos un poco de ensamblador para entender el código que seguirá. En ensamblador hay una cosa llamada 'registro'. Un registro es un lugar en la CPU que puede alojar un valor de 32 bits. En una CPU Pentium hay 8 registros principales (EAX, EBX, ECX, EDX, ESI, EDI, EBP, ESP). La mayoría de las acciones que se realizan en ensamblador se hacen sobre registros. Aquí están algunos comandos en ensamblador: (Mueve el valor en un registro) Mov Registro, Valor (Mueve el valor en Registro2 a Registro1) Mov Registro1, Registro2 (Mueve el valor apuntado por Registro2 a Registro1. Esto es lo mismo que el siguiente código: "Registro1 := Registro2^;") Mov Registro1, [Registro2] (Mueve el valor al que apunta Registro2+Valor a Registro1. Lo mismo que: "Registro1 := Pointer(Integer(Registro2) + Valor)^;") Mov Registro1, [Registro2 + Valor] Ejemplos: MOV EAX, 10 MOV EBX, EAX MOV EAX, [EBX + 6] EBX tendrá el valor 10 y EAX tendrá el valor que está en la dirección 16 ($10). Apenas para cerciorarse de que usted entendió esta parte, daré un ejemplo de cómo Delphi asigna un valor al miembro de los datos de una instancia. TGoo = class FDataA, FDataB: Integer; end; var Goo: TGoo; begin Goo := TGoo.Create; Goo.FDataA := 5; Goo.FDataB := 7; end; Si abre el desensamblador de Delphi, verá el siguiente código: // Goo.FDataA := 5; mov eax, [ebp-$08] mov [eax + $04], $00000005 // Goo.FDataB := 7; mov eax, [ebp-$08] mov [eax + $08], $00000007 ¿Por qué el valor apuntado por "ebp-$08"? Simple, allí es donde se almacena la variable Goo. Note que acceder a FDataA es lo mismo que acceder a la dirección "eax+$04" y que acceder a FDataB es lo mismo que acceder a la dirección "eax+$08". Esto es porque la dirección a la que apunta "eax" es el puntero a la VMT de TGoo, y (como mencioné antes) los siguientes valores en memoria son los miembros de dato de TGoo. Volvamos a las interfaces. Mire el siguiente código: IRoo = interface end; TRoo = class(TInterfacedObject, IRoo) end; var Roo: TRoo; RooIntf: IRoo; begin Roo := TRoo.Create; RooIntf := Roo; RooIntf._AddRef; end; El siguiente código ensamblador no es exactamente lo que produce Delphi pero hace lo mismo y sirve al propósito: // RooIntf := Roo; // eax contiene el valor devuelto por TRoo.Create, es decir, la // variable Roo // ecx contiene el valor que más tarde debería ser asignado a RooIntf mov ecx, eax // Esto es lo mismo que: "ecx := ecx + $0C;" add ecx, $0C // RooIntf._AddRef // Empujar "ecx" en la pila de la CPU push ecx mov ecx, [ecx] // "call ecx" le dice a la CPU que salte a la dirección guardada como // un valor en "ecx" call ecx Miremos el código al que nos lleva "call ecx": // obtener (POP) en "ecx" el valor que empujamos en la pila pop ecx // Lo mismo que: "ecx := ecx - $0c;" sub ecx, $0C // Llamar al método "_AddRef" con "ecx" como variable. call TInterfacedObject._AddRef(ecx) Se impone una pequeña explicación. ¿Por qué Delphi sumó "$0C" a "ecx"? Recuerde cómo Roo se almacena en la memoria (un indicador a la VMT, FRefCount (de InterfacedObject), IUnknown (de TInterfacedObject), IRoo). IRoo es el cuarto valor en la lista a la cual el "ecx" señala. Cada valor tiene 4 bytes de largo, así que IRoo está 12 bytes (4*4) después de "ecx", y "$0C" es 12 en notación hexadecimal. Así pues, básicamente, sumando "$0C" a "ecx" hizo que "ecx" apunte al valor correcto, es decir, que apunte a IRoo de Roo (una instancia de TRoo). ¿Por qué empujamos ecx en la pila? Esto es porque necesitaremos usarlo más tarde, al llamar al verdadero método "_AddRef". Recuerde, "ecx" es la dirección de Roo + 12. Después de eso, movemos en "ecx" el valor al que "ecx" apunta. ¿Recuerda cuándo dije que en vez de contener las listas de punteros-a-método Delphi almacena sólo los punteros a los mismos (para ahorrar memoria)? Esto es por qué "ecx" era en realidad un puntero, pero ahora contiene el valor al cual apuntaba antes. El siguiente comando es llamar al método al que "ecx" apunta. Ahora observemos ese método. Es muy corto. Lo único que hace es modificar el valor de "ecx" (después de restaurarlo de la pila) de modo que sea igual que el valor de Roo (es decir, apunta a la variable Roo). Entonces el método 'TInterfacedObject._AddRef' se llama con "ecx" (Roo) como parámetro. Éste es igual que cuando he escrito que Delphi en realidad compila un método de clase como una función o un procedimiento regular que acepta un parámetro adicional - la instancia de la clase. ¿Para qué es bueno esto? Sumamos un valor a un indicador, luego hicimos ese salto por la memoria, luego restamos el mismo valor del puntero y ¡finalmente llamamos a la función a la que apunta el puntero! ¿Por qué molestarse? ¡Podríamos simplemente llamar la función sin sumar y restar valores! Aquí es donde el poder de la indirección entra en juego. Note que la llamada a 'RooIntf._AddRef' no sabía que RooIntf era realmente de una instancia de TRoo. Simplemente llamó al método que estaba allí para llamar. La implementación de este método es donde se hizo la reasig- nación del valor del puntero. Es decir, solamente la implementación a la que RooIntf apunta (IRoo de TRoo) sabía cuánto fue sumado o restado del puntero salvado en la pila. Si tuviéramos otra variable de tipo TRoo2, que también implementara IRoo, y hubiésemos hecho la asignación 'RooIntf := variable de tipo TRoo2' y luego llamado el método 'RooIntf._AddRef', entonces se hubiera restado un valor diferente del valor salvado en la pila, así haciendo que la llamada del método vaya al lugar correcto en la clase TRoo2. __________________ El autor puede ser encontrado en ezra.hoch@saad.org.il ________________________________________________________________________ 5. Notas de un desarrollador (III) Abrir un archivo con la aplicación predeterminada Por Alirio A. Gavidia La presente es parte de una serie de pequeños artículos narrando expe- riencias en el desarrollo de una aplicación. El menú contextual o "cómo con un par de clics convertir un archivo de un formato a otro" ============================================== Lo que refiero aquí como Menú Contextual es la facilidad del Explorador de Windows (y similares ventanas de Windows) de mostrarnos un menú con el botón derecho que es diferente para cada archivo seleccionado. Para que quede claro ejecute el Explorador busque un archivo cualquiera y haga clic con el botón derecho. En mi caso he seleccionado un MP3 y la primera opción del menú es "Play in Winamp". Tengo más abajo una opción que dice "Agregar en ZIP" entre otras. Recientemente en RentACoder solicitaron un programa para conversión de archivos BMP/JPG y BMP/GIF. Me pareció que esto se puede combinar con el uso de menúes contextuales (originalmente los uso en HalZip imitando WinZip). Del artículo anterior de esta serie tenemos como convertir archivos de distintos formatos. Ahora vamos a concentrarnos en el manejo del menú contextual como extensión del Explorador de Windows. Abrir un archivo con una aplicación predeterminada ================================================== Esto es simple comparativamente, tomando el ejemplo de Wimamp sólo tenemos que manipular el Registro de Windows. Comencemos con REGEDIT y vamos a HKEY_CLASSES_ROOT desde allí buscamos '.mp3'. Por lo pronto sólo nos interesa el valor "Default" contenido. Esto programáticamente sería así: Registry es de tipo TRegistry, lo asumo ya creado. Registry.RootKey := HKEY_CLASSES_ROOT; if Registry.OpenKey('\.mp3',True) then appasoc := Registry.ReadString(''); Nota: Para leer el valor "default" o por defecto de una clave ("key") simplemente use el método de lectura que corresponda sobre un identificador en blanco. Obtenido 'appasoc' (que debe ser 'Winamp3.File') buscamos este valor en HKEY_CLASSES_ROOT y encontramos información interesante como la descrip- ción del tipo dada en el valor por defecto, el icono por defecto tomado del archivo que señalemos, y las opciones relativas al "Shell", en este caso nos interesa "Play", dentro de Play hallamos el comando que queremos asociar. Si siguieron todo esto usando Regedit verán que es bastante simple. El ejemplo anexo a este artículo ('test03') permite revisar las defini- ciones presentes en la máquina y adicionalmente crear algunas nuevas. En el segundo ejemplo anexo a este artículo ('gconvert') usamos la aso- ciación a BMP, JPG, WMF, EMF, ICO y GIF para conversiones. Simplemente creamos la entrada "Convertir a .." esto sin dañar el valor "Open" por defecto. "Gconvert" es casi una aplicación de consola (sin interfaz Windows) que acepta un parámetro. El parámetro aceptado se asume como un archivo de tipo jpg, gif, ico, wmf, emf. Para probarlo simplemente suelte un archivo de cualquiera de estos tipos sobre el programa y... voila. Obtendrá un archivo bmp. Además "gconvert" opera con los parámetros /r y /u el primero asocia los archivos convertibles, el segundo parámetro elimina esta asociación. Compile "gconvert" y obtenga el ejecutable correspondiente. Ciertamente al soltar un archivo jpg o gif o de cualquiera de los tipos convertibles obtendrá un bmp. Ejecute el archivo registro.bat para asociar los archivos convertibles al menú de contexto, busque un archivo de los tipos convertibles y revise el menú que despliega con el botón derecho del ratón. Sensitivo a contexto ==================== Ni WinZip y HalZip usan este enfoque más allá de las opciones "abrir" e "imprimir". La razón es poder manejar múltiples archivos con una llamada. Con el esquema dado hasta ahora si se selecciona tres archivos "txt" y con el menú derecho se opta por "Abrir" tendremos tres instancias del programa. El otro problema es la interactividad de los menúes. Para ello basta ver que WinZip y HalZip generan entradas de menú de forma dinámica. Verán que Winzip genera un menú de tipo e-mail <nombre archivo>. Donde <nombre archivo> cambia según el menú seleccionado. Delphi trae un ejemplo de esto en ...\Borland\Delphi5\Demos\Activex\Shellext Revísenlo si quieren. Será analizado con más propiedad próximamente en esta serie de artículos. Este tema será analizado más profundamente en el próximo artículo. Alirio A. Gavidia. desde www.gavidia.org __________________ Próximo tema: DLL y su registro ________________________________________________________________________ ¡Vote por el Boletín Pascal en el DPSC Top 100 Programming web sites! http://www.sandbrooksoftware.com/cgi-bin/TopSite2/rankem.cgi?id=latium ________________________________________________________________________ 6. Validando números de CBU Por Ernesto De Spirito Las cuentas bancarias en Argentina se identifican por un número de CBU (Clave Bancaria Uniforme), formado por 22 dígitos, divididos en dos bloques. El primer bloque, formado por 8 dígitos, identifica al banco y sucursal, mientras que el segundo bloque, formado por los restantes 13 dígitos, identifica la cuenta bancaria. El último dígito de cada bloque es el dígito verificador del mismo según el algoritmo clave 10 con ponderador 9713. Para validar un número de CBU se deberán computar los dígitos verifica- dores de ambos bloques y compararlos con los respectivos valores para ver si coinciden o no. La siguiente función realiza ese trabajo: function CBU_Valido(const CBU: string): boolean; { Copyright (c) 2003 Ernesto De Spirito http://www.latiumsoftware.com/es/index.php Determina si un número de CBU (Clave Bancaria Uniforme) es válido. La cadena que se pasa como parámetro debe estar formada por 22 dígitos numéricos (no se admiten guiones, barras ni espacios como parte de la cadena con el CBU). } var i: integer; function Verificador(const s: string; i1, i2: integer): char; // Devuelve el dígito verificador para los dígitos // de las posiciones "i1" a "i2" de la cadena "s" // usando clave 10 con ponderador 9713 const ponderador: array[0..3] of integer = (3,1,7,9); // 9713 var i: integer; // subíndice para recorrer la cadena j: integer; // subíndice del ponderador (módulo 4) suma: integer; // sumatoria de los productos parciales digito: integer; // dígito verificador begin suma := 0; j := 0; for i := i2 downto i1 do begin inc(suma, (Ord(s[i])-Ord('0')) * ponderador[j mod 4]); inc(j); end; digito := (10 - suma mod 10) mod 10; Result := Chr(digito + Ord('0')); end; begin Result := False; // Comprueba la longitud de la clave if Length(CBU) <> 22 then exit; // Comprueba que esté integrada sólo por dígitos numéricos for i := 1 to 22 do if not (CBU[i] in ['0'..'9']) then exit; // Comprueba el primer dígito verificador if CBU[8] <> Verificador(CBU, 1, 7) then exit; // Comprueba el segundo dígito verificador if CBU[22] <> Verificador(CBU, 9, 21) then exit; // Pasó todas las pruebas. Es válido. Result := True; end; Llamada de ejemplo: procedure TForm1.btnValidarClick(Sender: TObject); begin if CBU_Valido(edtCBU.Text) then ShowMessage('El CBU ingresado es válido') else ShowMessage('El CBU ingresado no es válido'); end; ________________________________________________________________________ ¡Vote por el Boletín Pascal en The Programming Pages! http://www.programmingpages.com/?r=latiumsoftwarecomenpascal ________________________________________________________________________ Delphi BUGS? Catch & Log every BUG showing Unit, Class, Method, Line #. Now with support for IntraWeb applications and Anti-Freeze feature. http://www.eurekalog.com/bannerclick.php?id=15 ________________________________________________________________________ 7. Foros / listas de correo 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 ________________________________________________________________________ Merlin's Delphi Forge Delphi and Kylix news, FAQ, downloads, links, forums and more. Accepting uploads and submissions. http://www.delphifaq.net/ ________________________________________________________________________ 8. Delphi en la Red Por Dave Murray <irongut @ vodafone.net> Componentes, librerías y aplicaciones ===================================== Shareware/Comercial ------------------- * LMD SearchPack 2.0 - by LMD Innovative (EUR 39) LMD SearchPack includes 3 controls for integrating advanced text search capabilities into your projects including support of AND, OR, NEAR and NOT operators. Full source code and extensive demo projects included. http://www.ceberus.com/lmd/products/index.php3#P6 * EurekaLog v4.2 - by Fabio Dell'Aria (Std $24, Pro $49, Ent $99) Gives your application the ability to catch every exception, generate a detailed log and send it via email. Integrated with Delphi 3 - 7, a single rebuild adds EurekaLog to your app. NEW: save modified files on exception; detailed Log when the application freezes; customizable email for every exception; speed and stability improvements. http://www.eurekalog.com/bannerclick.php?id=15 Freeware -------- * WinDowse v5.1 - by Greatis Software (free for non-commercial use) Unique windows analyzer, best Borland's WinSight replacement. Greatis WinDowse is an extremely convenient tool for obtaining necessary technical information about any window. Place a mouse cursor on a window, and WinDowse will show all parameters of the window and window class. Full Delphi 3-7 source code available after 100 Euro donation. http://www.greatis.com/windowse.htm * Inno Setup v4.0.8 - by JR Software (with source) A free installer for Windows that rivals commercial installers in features and stability. Features include: all 32-bit Windows versions; create a single EXE or disk spanning; standard interface; customizable setup types; complete uninstall capabilities; zip / bzip2 compression; create shortcuts, registry + .INI entries; silent install / uninstall; register DLL, OCX and type libraries; install fonts; Pascal Script. http://www.jrsoftware.org/isinfo.php * TPages v1.2 - by Angus Johnson (with source) Visual component for simple, non-data-aware reports. Features include: text wrapped between margins, in columns or at specific offsets; multiple alignment options; multi-line page headers, footers and column headers; angled text; bitmaps, lines, boxes and arrows; page numbering; prevent blocks of text spanning across pages. http://www.users.on.net/johnson/delphi/ Actualizaciones de Delphi y otros productos Borland --------------------------------------------------- * Fixes for Kylix 3 Issues on Newer Distros (updated) - Andrés Colubri Kylix 3 (particularly C++) on newer Linux distros (eg. RedHat 8+, Madrake 9+, SuSE 8.2) has a number of bugs: compilation errors with STL, unresolved references when linking, installer and IDE hangs, etc. This package contains a collection of fixes to address these issues. http://codecentral.borland.com/codecentral/ccweb.exe/listing?id=20136 Artículos, trucos y consejos ============================ * Come learn about Octane! Sneak peeks around the world! - by A Ohlsson First Octane sighting at Entwickler Konferenz in Frankfurt, Germany. http://bdn.borland.com/article/0,1410,30387,00.html * Using D7 to Consume Web Services and Transform XML - by Anders Ohlsson In this BDNtv episode, Anders shows how you can consume web services that return XML data. Anders uses Delphi 7 Enterprise to create a simple application that consumes an XML web service, transforms the result and displays custom picked data in a regular DBGrid. Format(s): Flash, Duration: 9:34. http://community.borland.com/article/0,1410,30379,00.html * Customizing the DBNavigator Enhancing the TDBNavigator component with modified graphics (glyphs), custom button captions, and more. Exposing the OnMouseUp/Down event for every button. http://delphi.about.com/library/weekly/aa090203a.htm * Accessing and managing MS Excel sheets with Delphi - by Zarko Gajic How to retrieve, display and edit Microsoft Excel spreadsheets with ADO (dbGO) and Delphi. This step-by-step article describes how to connect to Excel, retrieve sheet data, and enable editing of data (using the DBGrid). You'll also find a list of most common errors (and how to deal with them) that might pop up in the process. http://delphi.about.com/library/weekly/aa090903a.htm * Delphi History: from Pascal to Octane - by Zarko Gajic Concise descriptions of Delphi's versions and its history, along with a brief list of features and notes. Find out how Delphi evolved from Pascal to a RAD tool that can help you solve development problems not only for Windows but also for Linux and .NET. http://delphi.about.com/cs/azindex/a/dhistory.htm * Drop Down List Inside a DBGrid: Part 1 - by Zarko Gajic Here's how to place a drop down pick list into a DBGrid. Create visually more attractive user interfaces for editing lookup fields inside a DBGrid - using the PickList property of a DBGrid column. http://delphi.about.com/library/weekly/aa092703a.htm * How to Darken or Lighten TColor? http://www.swissdelphicenter.ch/en/showcode.php?id=1411 * How to execute a Javascript function in a Webbrowser / IE Document? http://www.swissdelphicenter.ch/en/showcode.php?id=1732 * How to display the items in a listview control as a group? (WinXP) http://www.swissdelphicenter.ch/en/showcode.php?id=1782 * How to detect if an Application is running within VMware? http://www.swissdelphicenter.ch/en/showcode.php?id=1819 * How to mix two colors using transparency coefficient? http://www.swissdelphicenter.ch/en/showcode.php?id=1832 * THvHQuery for exporting query to CSV file - by Henk van Hoek Export a query to a Comma Separated CSV File. http://www.delphi3000.com/articles/article_3763.asp * TEdit and EConvertError - by Andrew Kennaugh Checking TEdit for StrToFloat using OnKeyPress not OnChange. http://www.delphi3000.com/articles/article_3765.asp * Inline Assembler in Delphi (I): Introduction - by Ernesto De Spirito Reprinted from this newsletter, Ernesto's Assembler tutorial. http://www.delphi3000.com/articles/article_3766.asp * Inline Assembler in Delphi (II): ANSI strings - by Ernesto De Spirito http://www.delphi3000.com/articles/article_3767.asp * Inline Assembler in Delphi (III): Static Arrays - Ernesto De Spirito http://www.delphi3000.com/articles/article_3768.asp * Inline Assembler in Delphi (IV): Records - by Ernesto De Spirito http://www.delphi3000.com/articles/article_3769.asp * Inline Assembler in Delphi (V): Objects - by Ernesto De Spirito http://www.delphi3000.com/articles/article_3770.asp * Inline Assembler in Delphi (VI): Calling External Procedures - by Ernesto De Spirito http://www.delphi3000.com/articles/article_3771.asp * Inline Assembler in Delphi (VII): 128-bit Integer Arithmetic - by Ernesto De Spirito http://www.delphi3000.com/articles/article_3772.asp * Playing Sounds Thru The Built-In PC Speaker - by Ernesto De Spirito Using inline assembler to play sounds with the built-in PC speaker. http://www.delphi3000.com/article.asp?id=3773 * Determining if a Logical Drive Exists - by Ernesto De Spirito How to know if there is a drive assigned to a letter. http://www.delphi3000.com/articles/article_3774.asp * Using TList's and Pointers in delphi (Part II) - by Stewart Moss Demonstration of how to create records on a TList object. http://www.delphi3000.com/articles/article_3775.asp * Adding HTML Resources to DLL/EXE that IE can Reference - Matt Harrison Creating an RC file to store HTML and Images as resources that works with IE's res:// format. http://www.delphi3000.com/articles/article_3776.asp * Horizontal Modularization - by Hang Liu This article introduces a modular approach to building large applications. http://www.delphi3000.com/articles/article_3777.asp * Borland DataSnap vs Microsof ADO.NET - by Pablo Reyes A comparison between the tools provided by these technologies for building data aware applications. http://www.delphi3000.com/articles/article_3778.asp * Simple Winsock Component for Console App - by J3N7iL Jones How can I create a TCP/IP internet connection in a console application using winsock? http://www.delphi3000.com/articles/article_3779.asp * PageControl Without Border - by Tommy Andersen http://www.delphi3000.com/articles/article_3783.asp * Adding new Standard Actions - by Andreas Schmidt http://www.delphi3000.com/articles/article_3784.asp * Create a Sizeable Dialog - by Terrance Hui How to create a sizable dialog (with sizegrip) without using any 3rd party components. http://www.delphi3000.com/articles/article_3785.asp * Selecting Files - by Teun Spaans In which ways can you let your user choose a file or directory? http://www.delphi3000.com/articles/article_3786.asp * Debugging Tricks - by Andreas Schmidt How to read the content of a TStrings in the integrated debugger. http://www.delphi3000.com/articles/article_3787.asp Tutoriales y capacitación ========================= * BorCon 2003 to be be held in San Jose, California November 1-5, 2003 http://info.borland.com/conf2003/ Otros enlaces ============= * Public Beta: QualityCentral Java Client - by John Kaster Use a smart client for Borland QualityCentral from wherever you can run JDK 1.4.x. http://community.borland.com/article/0,1410,30348,00.html * San Francisco East Bay Delphi User Group Our goal is to connect the Delphi developers in the Bay Area. We meet the 1st Wednesday of every month and have great speakers and sessions. We organize Delphi events with the help of eBig - the East Bay IT Group (www.ebig.org). The group will explore Delphi and how Borland's Delphi 7-8 Studio provides a migration path to Microsoft .NET for developers as well as Delphi and Linux (Kylix). http://www.ebig.org/sig/sig.aspx?SIGid=20 Noticias ======== * Altova XMLSPY to be Included in Borland Development Tools Special Edition of Altova XMLSPY Available in Borland Delphi Studio, C++ Builder, and C# Builder for the Microsoft .NET Framework. http://www.altova.com/press/2003-08-28_borland.pdf ________________________________________________________________________ ¿Cómo calificaría al boletín? ¡Califique al Boletín Pascal en el ranking Top 200 Delphi! · http://top200.jazarsoft.com/delphi/rank.php3?id=latium ________________________________________________________________________ ¡Tú puedes ayudarnos! Por favor danos una mano y ayúdanos a llegar a los 20.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/p0049.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) 2003 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!






