jueves, marzo 07, 2019

Imagenes y campos memo, guia de supervivencia con ADS

Mis chicos favoritos, como casi todo el mundo sabe, es la gente de Sanrom's Software de México, con quien me une algo mas que una amistad de muchos años.

Hace un par de años, por estas fechas, concluíamos la migración a 32 bits de sus productos de control escolar, con la promesa de que la nueva versión estaría hecha en Xailer, desafortunadamente nos ha ganado el tiempo, ha llegado el momento de lanzar una nueva versión, que aunque no será en Xailer, si tendrá mejoras significativas a la versión de 32 bits y aunque ya casi está terminado el primer producto Sanroms hecho con Xailer, aún no ha sido probado a conciencia, con esto en mente, la prudencia aconseja seguir por el mismo camino que a la fecha nos ha dado resultado.

En el proceso de migración cambiamos de tabla de datos, de DBF/CDX, se decidió cambiar al formato nativo de Advantage Database Server: ADT/ADI por varias razones, primero por la tecnología cliente/servidor, segundo por la seguridad de la información y tercero por desempeño de la aplicación, hoy, a 2 años de haber lanzado la primera versión con ADS, yo creo que la mas estable hasta el momento en cuanto a manejo de tablas, no hemos tenido ningún "susto" ya se que los usuarios trabajen con el servidor local o bien tengan un servidor remoto instalado.

Uno de los grandes atractivos de esta nueva revisión, es la capacidad de tener acceso a los datos vía Internet, esta mejora se hizo por la necesidad de algunos colegios con varios planteles remotos de acceder a los datos centralizados, en esta nueva revisión se hizo la adaptación al software para que hiciera uso del Advantage Internet Server.

La implementación del acceso remoto no fue complicada, en realidad a parte del diccionario de datos, poco mas se tuvo que mover del programa original, el verdadero problema se presentó cuando hubo que manipular imágenes.

Los sistemas Sanrom's tienen ya muchos años en el mercado, programados originalmente en FiveWin 2.0 a 16 bits y con Clipper 5.3 e índices CDX, la manipulación de las imágenes, en este caso las fotografías de alumnos y maestros, se hacia mediante un campo cadena de caracteres que hacía referencia a un archivo de imagen (.bmp, jpg, gif, etc) dentro del disco duro del servidor, esto no planteaba problema alguno en la red de área local, porque la imagen se lee por referencia al archivo, pero para Internet si que presenta un problema, ya que usando el AIS, no es posible acceder al disco duro remoto, únicamente a los archivos de datos ADS.

Para que el sistema funcionara eficientemente sobre Internet, había que añadir la imagen un registro de alguna tabla, ya no por referencia, es decir, ya no como una ruta a un archivo, sino que había que poner el archivo de imagen completo dentro de un campo de la base de datos, a fin de que la imagen estuviera disponible en el equipo cliente tanto si estuviera conectado en la red de área local, como si estuviera conectado por Internet, el mecanismo de despliegue en pantalla se explicará mas adelante.

Bien, la primera aproximación fue trabajar en un campo memo, en ADS, al igual que con DBF, el campo memo se almacena en un archivo independiente a la tabla de datos, con la extensión ADM, en nuestro primer intento tratamos de hacer algo como esto

field->campomemo := MemoRead("\\servidor\recurso\directorio\imagen.jpg")

Es decir, directamente, leer el archivo como si se tratara de un texto y guardarlo en el campo memo correspondiente, mala idea, mas adelante veremos porqué.

Para el despliegue de la imagen en pantalla, había que generar un archivo de imagen a partir del dato almacenado, ya que la clase TIMAGE de FiveWin, solo puede hacer visualización de una imagen que esté almacenada en un recurso, o bien de un archivo de imagen que exista en disco (nota: Xailer puede visualizar las imágenes leídas directamente del campo, sin necesidad de crear un archivo a disco.), para lo cual, la ruta mas práctica aparentemente era:

MemoWrit("imagentemp.jpg",field->campomemo)

Sin embargo, al hacer el despliegue en pantalla del archivo "imagentemp.jpg", esta aparecía cortada, solo aparecía aproximadamente una tercera parte de la imagen, ya que el proceso de MemoRead() no marcaba ningún error, y aparecía un valor en el campo, no pensamos que la lectura y guardado de la imagen, como un texto, en un campo memo, pudiera estar causando problemas, antes bien, pensábamos equivocadamente que el proceso de escritura era el que estaba dañando la imagen.

Después de darle mucho la vuelta (toda una tarde) y buscar por el lado equivocado, el de la escritura, decidimos hacer un "back to the basics" y analizar el proceso de lectura, ¡ oh sorpresa !, nos pusimos a comparar los tamaños en bytes del archivo original, contra el LEN(MemoRead(...)) y ambos valores eran el mismo, por decir algo, 90 kbytes, el problema venía en la asignación al campo memo, cosa que descubrimos cuando al hacer un LEN(field->campomemo), nos devolvió 30 kbytes, cuando, si el proceso de guardado hubiese hecho bien todo, este valor tendría que ser 90 kbytes, por esta razón al hacer el MemoWrit(), solo aparecía una tercera parte de la imagen.

Dependiendo de la imagen, algunas veces lo hacía bien, y otras lo hacia mal, cuando la imagen media menos de 30 kbytes, hacía el guardado y el despliegue en pantalla perfectamente, pero cuando era mayor de este tamaño, la imagen quedaba truncada a 30 kbytes.

Evidentemente el formato de almacenamiento estaba fallando, así que Israel y yo nos pusimos a estudiar un poco el tema y encontramos que dentro de ADS, para el tipo de tabla ADT, los campos memo puede ser de 3 tipos:

Memo - para almacenar solo texto, igual que en un DBF
Binary - para almacenar cualquier cosa binaria, por ejemplo un documento de word
Image - para almacenar, como su nombre lo indica, una imagen, el formato es lo de menos.

Con esto en mente, procedimos a hacer el cambio de tipo de campo, modificando la estructura de la tabla, y cambiando el campo tipo MEMO por IMAGE, una cosa que descubrimos fue que cuando se define un campo del tipo Binary ó Image dentro de la estructra del archivo ADT, al momento de crear la estructura nueva, los campos se "renombran" como de tipo "BLOB" (Binary Large OBject), así que para efectos de definición se pueden declarar de 3 formas, como IMAGE, como BINARY o bien directamente como BLOB, que es otro tipo válido de campo en una tabla ADT de Advantage.

Una vez redefinido el tipo, procedimos a hacer lo que estábamos haciendo anteriormente, es decir, field->campoblob := Memoread().... otro error, cuando intentábamos hacer esta asignación el sistema marcaba un error de Field type mismatch, es decir, el tipo de campo no coincide con el tipo de variable que se le está asignando, lo cual es entendible, el campo es tipo BLOB, y le estabamos tratando de meter una cadena de caracteres, es como si trataras de meter una cadena en un campo numerico o fecha o lógico, sin embargo, el tipo BLOB no existe en (x)Harbour, ¿ que podíamos hacer entonces ? ¿ como transformar una cadena de caracteres para que sea reconocida como BLOB ?.

De vuelta al manual de ADS, y encontramos que en ADS existen un par de funciones que quizá nos podía ayudar: AdsBinaryToFile() y AdsFileToBinary(), así que vimos sus parámetros, las metimos en el código fuente, y nos llevamos una desliusión cuando vimos aparecer el temido "Unresolved external HB_FUNC_ADSFILETOBINARY()", que indica que dichas funciones no estaban definidas dentro del RDDADS.LIB, ¿ que acaso nadie había trabajado con blobs antes con ADS ?

Antes de ponernos a pegarle la "C" para hacer wrappers para llamar a las funciones que nos faltaban, se nos ocurrió revisar el código fuente del RDDADS, mismo que se puede encontrar dentro de las contribuciones de xHarbour, y en el archivo ADSFUNC.C encontramos 2 funciones que nos salvaron de estar perdiendo el tiempo con código en "C": AdsBlob2File() y AdsFile2Blob(), estas funciones son wrappers muy elaborados para las funciones AdsFileToBinary() y AdsBinaryToFile(), solo que sus parámetros son mas simples de manejar.

La sintaxis es:

AdsFile2Blob(,,)

Donde:

es el nombre del archivo que deseamos leer
es el nombre del campo blob donde se guardará el archivo leido
es el tipo de campo (imagen o binario) que esta definido en una constante predefinida dentro del archivo ACE.H y que es:

#define ADS_BINARY 6 /* BLOB - any data */
#define ADS_IMAGE 7 /* BLOB - bitmap */


Con lo cual, en vez de estar haciendo experimentos con el MemoRead() un simple:

AdsFile2Blob("nombredelaimagen.jpg",campoblob,ADS_IMAGE)

Se encargaron de todo, la imagen se lee perfectamente y se guarda en el campo sin perder un solo byte, lo anterior es válido no importa que tipo de campo blob tengas, solo tienes que cambiar el tercer parámetro, lo mismo puede ser una imagen, en cuyo caso usaremos ADS_IMAGE, que un documento de word o una hoja de excel, para los cuales usaremos ADS_BINARY.

Para la operación contraria, es decir, crear un archivo de imagen a partir del campo blob, utilizamos la función contraria cuya sintaxis es:

AdsBlob2File(, )

De tal forma que un simple

AdsBlob2File("imagen.jpg",campoblob)

Crea el archivo que necesitaremos para visualizar con FiveWin, sin necesidad de estar enrredando con MemoWrit().

Una vez descubiertas estas 2 funciones, el resto fue fácil, para cargar todas las imagenes dentro del campo de la base de datos hicimos:

USE alumnos
GO TOP
DO WHILE ! EOF()
AdsFile2Blob(alumnos->foto, alumnos->imagen, ADS_IMAGE)
SKIP
ENDDO

Donde el campo alumnos->foto era el que contenía una cadena de caracteres con la dirección del archivo de foto, y alumnos->imagen es el campo blob que contendrá la imagen dentro de la tabla.

Eso si, después de hacer la importación de foto de un colegio de 2,500 alumnos, el archivo memo ADM quedó de 170 megas de tamaño, mas grande que el archivo ADT, que contiene los datos, tal ves pudieras pensar que con ese tamaño la tabla sería lentísima de acceder a los datos, pues va a ser que no, la tabla tiene el mismo rendimiento que si no tuviera las imágenes pegadas, los indices se generan a la velocidad de ADS, vamos que no perdemos nada de performance por tener las imágenes como parte de la tabla de datos.

Para el acceso via internet tampoco tenemos problema, porque la imagen se genera dentro del disco duro de los clientes y se borra cuando se ha dejado de utilizar, con lo cual podemos enviar esos archivos de imagenes a los equipos clientes sin necesidad de que tengan acceso al disco del servidor, cosa que por internet puede ser lentisima.

Eso nos abre nuevas posiblidades de trabajo, ahora podemos añadir practicamente cualquier tipo de archivo como un campo de la base de datos, eso me esta dando nuevas ideas.....

martes, septiembre 12, 2017

Usando SQL con Advantage de la manera fácil


Una de las grandes carencias del lenguaje XBase es la capacidad de hacer queries (búsquedas) sobre una o varias tablas DBF extraer los resultados y mostarlos todos en una "vista", en XBase hay que hacer ese trabajo a mano, mediante índices, SET RELATION, SCOPES incluso SET FILTER y otras cosas mas. El resultado no siempre se obtiene de la manera mas rápida ni con la menor cantidad de tiempo invertida en la programación, si tuviéramos un SQL, la cosa resultaría mucho mas rápida.

Desafortunadamente el modelo XBase tal cual como lo conocemos ha sacrificado el modelo "relacional" por el modelo "navegacional", dando preferencia a mostrar las tablas en listados en vez de tratar de obtener la menor cantidad de información posible para mostrar en la pantalla, como lo hace SQL.

Si pudieramos tener el poder del modelo navegacional del XBase, de la mano del poder relacional del SQL, sobre nuestros veteranos archivos DBFs, pues otro gallo nos cantaría podríamos trabajar y obtener resultados en menos tiempo y realizar complejísimas búsquedas sobre uno o mas archivos DBF, relacionar sus campos y obtener un resultado rápido y ordenado de un criterio de búsqueda dado.

¿ La solución ?, ADS de la mano del RDDADS de xHarbour.

Lo que vamos a analizar a continuación está disponible tanto con el servidor local como con el servidor remoto de ADS, pero solo puede usarse con el RDDADS de (x)Harbour a 32 bits, lo siento chicos de Clipper, el cliente ADS para Clipper no soporta el uso de SQL. (En los próximos días publicaré un artículo para que todo el mundo le pierda el miedo a (x)Harbour, de la mano con una sorpresa por parte del Equipo Xailer).

Manos a la obra, ¿ qué necesitamos ?:

1) Un (x)Harbour cualquier versión (también funciona con cualquier interfaz grafica: Xailer, FiveWin, VisualxHarbour o Harbour MiniGUI)
2) El RDDADS.LIB y el ACE32.LIB para linkear a nuestro EXE
3) Las DLLs del cliente ADS (ACE32.DLL, AXCWS32.DLL y ADSLOC32.DLL para el servidor local)
4) Un código fuente .PRG con las instrucciones correspondientes.

Modo de preparación:

Antes de meternos en el mundillo del SQL con ADS, tenemos que analizar un poco como es que funciona un motor de datos SQL.

En un sistema gestor de bases datos relacional, como MySQL, SQL Server, y el mismo ADS, el concepto de "BASE DE DATOS" cambia con respecto a lo que conocemos como "BASE DE DATOS" en el modelo XBase. Mientras que en el modelo XBase tradicional erroneamente le llamamos "base de datos" a UN archivo o tabla .DBF, en el modelo relacional una base de datos es una COLECCION de tablas, indices, usuarios, esquemas de seguridad, vistas, procesos almacenados, etc.

En todos los productos basados en SQL, es necesario realizar una CONEXION a la base de datos, esto se hace comúnmente mediante un Middleware como ODBC ó ADO y mediante una serie de instrucciones desde el lenguaje de programación que realizan la conexión primero con el servidor de base de datos y segundo con la propia base de datos, para tener acceso a los datos almacenados en sus tablas.

El modelo cambia un poco dentro de ADS, ya que ADS soporta 2 tipos de conexiones, lo que conocemos como TABLAS LIBRES, es decir archivos DBF o ADTs individuales que manipulamos usando nuestro lenguaje XBase tradicional, o bien un modelo de conexión mas aproximado a lo que es el modelo relacional, que es el modelo basado en DICCIONARIO DE DATOS.

Un DICCIONARIO DE DATOS para ADS es similar a una base de datos de un SQL, es decir, un DD (Diccionario de Datos) guarda referencia a las tablas DBF o ADT individuales, y al mismo tiempo guarda el esquema de seguridad de los usuarios, procesos almacenados, integridad referencial, triggers, replicación y en general todo lo que puedes esperar de un verdadero sistema gestor de base de datos relacional.

Usar DDs con ADS tiene grandes ventajas contra el modelo de tabla libre, como por ejemplo el poder mover la seguridad de la base de datos a ser controlada por propio servidor, en vez de tener que controlarla por programa, el evitarte tener que abrir todos las tablas individualmente una a una, ya que en el modelo tradicional XBase hay que hacer un "USE" por cada tabla que quieras usar, con un diccionario no, simplemente conectas desde tu programa con tu diccionario de datos, y listo, todas tus tablas están disponibles sin necesidad de tener que saber en que directorio las tienes, el DD se encarga de todo.

Pues bien, siguiendo el modelo relacional, para poder utilizar un querys con ADS, lo primero que tenemos que hacer es realizar una CONEXION con la base de datos, si tengo un diccionario de datos no tengo ningún problema, el RDDADS provee de la función ADSConnect60() que me permite "conectar" a un DD desde mi programa xHarbour....

¿ Pero que pasa si no tengo DD y estoy trabajando con tablas libres ?

No hay ningún problema ADS reconocerá como "base de datos" al contenedor de dichas tablas libres, y el "contendor" de las tablas libres es, simplemente la carpeta o directorio del disco duro donde se encuentran alojados los DBFs con sus NTX o CDX o bien los ADTs con sus respectivos ADIs.

¿ Cómo hacemos entonces para "conectar" con una carpeta del disco duro ?

El RDDADS de (x)Harbour provee de la función ADSConnect() mediante la cual podremos "conectarnos" con un directorio del disco duro, simplemente indicando la ruta donde se encuentran nuestros DBF o ADTs dentro del disco duro:

ADSConnect("C:\programas\datos\")

Si queremos saber si ya hay una conexión previamente establecida , utilizamos la función ADSConnection(), de tal forma que podríamos hacer algo como esto:

IF ADSConnection() == 0
ADSConnect("C:\programas\datos")
ENDIF

Ya "conectamos" con nuestra "base de datos" (directorio donde están los archivos), ¿ que sigue ahora ?

El siguiente paso es "preparar" la ejecución del query SQL, para ello vamos a utilizar la función ADSCreateSQLStatement() a la cual pasaremos 2 parametros: el primero es el nombre de un "alias" (si si, a lo Xbase, un alias) para el resultado del query (lo que en SQL se llama "cursor") y el segundo parámetro es el tipo de tabla sobre el cual estamos trabajando, siendo los valores válidos : 1 = DBFNTX, 2 = DBFCDX, 3 = ADTADI, así que la preparación de nuestro query quedaría así:

ADSCreateSQLStatement("mialias",2) // 1= DBFNTX 2 = DBFCDX 3=ADTADI

Y ahora si, podemos ejecutar el Query que nosotros queramos, de acuerdo a las instrucciones y funciones SQL soportadas por el motor SQL de ADS llamado Xtremeline SQL, esto lo haremos mediante la función ADSExecuteSQLDirect():

ADSExecuteSQLDirect("Select nombre, dire, tel from clientes order by nombre where nombre like '%Juan%'")

Ahora viene lo sorprendente: El resultado de este query ¡¡¡¡ SE COMPORTA EXACTAMENTE IGUAL QUE SI FUERA UN DBF !!!!!, de tal forma que tu podrías hacer algo como esto:

mialias->nombre := "Juan Pérez"
mialias->(DBGOTOP())
DO WHILE ! mialias->(EOF())
...
...
...
mialias->(DBSKIP())
ENDDO

¿ Y si quiero "browsear" el resultado de esto ?

Con xHarbour modo consola muy fácil:

mialias->(Browse())

y con Xailer, basta pegar el ALIAS a un objeto DBBrowse:

::oDBBrowse1:SetDBF("mialias")

En ninguno de los 2 casos necesitas cambiar los bloques de código que definen la navegación porque ADS "engaña" a xHarbour mediante el RDDADS, haciendole creer que lo que está visualizando es un DBF y no el resultado de un Query SQL ;-).

Cuando hallas terminado de utilizar este query, pues simplemente haces:

mialias->(DBCLOSEAREA())

Y listo, ya puedes ejecutar otro query de SQL.

El ejemplo completo para (x)Harbour en modo consola sería algo como esto:

Function Main
REQUEST ADS
RDDSETDEFAULT("ADS")

ADSSetFileType(2)
ADSSetServerType(7)

IF ADSConnection() == 0
ADSConnect("C:\programas\datos")
ENDIF

ADSCreateSQLStatement("mialias",2) // 1= DBFNTX 2 = DBFCDX 3=ADTADI

ADSExecuteSQLDirect("Select nombre, dire, tel from clientes order by nombre where nombre like '%Juan%'")

CLS

mialias->(DBGOTOP())
DO WHILE ! mialias->(EOF())
? mialias->nombre, mialias->dire, mialias->tel
mialias->(DBSKIP())
ENDDO

mialias->(DBGOTOP())
mialias->(BROWSE())

RETURN

Los queries pueden ser tan complejos como quieras, pudiendo incluso ejecutar procesos almacenados, puedes incluso realizar proceso "ciegos" como INSERT INTO, UPDATE o DELETE, solo que estas instrucciones no devolverán un cursor y por lo tanto no podras visualizar nada del resultado de estas instrucciones SQL.

He creado un pequeño manual con las instrucciones SQL soportadas por el XtremeLine SQL de ADS junto con sus funciones, este manual lo he extraído de mi libro de Advantage Database Server y de lo puedes descargar haciendo click aqui.

jueves, mayo 25, 2017

De Clipper a (x) Harbour con XEdit

Este artículo me lo han pedido muchísimos programadores de Clipper, y hasta ahora había tenido tiempo de escribirlo con calma, de hecho me ha llevado poco mas de una semana.

Lo que explicaré a continuación es la forma fácil y rápida de migrar tus programas CA-Clipper a (x)Harbour, con las menores molestias posibles, utilizando una herramienta muy interesante : XEDIT.

XEdit es una herramienta hecha en Xailer, de hecho, XEdit es un buen ejemplo de lo que se puede lograr programando con Xailer, pero además es un prototipo de lo que después se convertiría en el IDE de Xailer.

El Equipo de Xailer ha decidido mejorarlo y dejarlo como un producto individual independiente de Xailer para ayudar a los programadores novatos en (x)Harbour en los procesos de compilación y enlazado de sus aplicaciones, tanto para modo consola, como para Windows hechas con FiveWin, así es..... puedes usar XEdit para compilar y enlazar tus programas FiveWin. ;-)

Si trabajas con XEdit para migrar tus programas de Clipper a (x)Harbour, posteriormente la migración de tus programas a Windows con Xailer te será mucho mas fácil, ya que XEdit comparte muchas de las características de su hermano mayor: El IDE de Xailer, como son: El Gestor de Proyectos, El Editor de código fuente, El Depurador visual (solo para aplicaciones modo Consola, no para aplicaciones Windows, la depuración para aplicaciones Windows solo está disponible en Xailer), El Explorador de DBFs (DBU) y El Editor de SQLite., estos componentes no los voy a explicar en este artículo, pero haz click sobre los enlaces anteriores y obtendrás una descripción detallada de cada uno.

Antes de comenzar debo aclarar que todo lo aquí expuesto está basado en XEdit 5.0.4 de Noviembre 2017, más adelante encontrarás información sobre como obtenerlo.

Bien comencemos.

Los que ya llevamos una temporada trabajando con (x)Harbour sabemos que si bien el compilador es poderoso y versátil, no es nada fácil el proceso de compilación y enlazado de los programas, sobre todo porque tenemos por medio un compilador de C, del cual poco o nada sabemos, y es en este punto es donde el proceso de compilación y enlazado del EXE final se vuelve terrible.

Recordemos como hacíamos un programa EXE en Clipper:

archivo.prg -> archivo.obj -> archivo.exe

Escribimos nuestro código fuente en archivos .PRG, luego con el compilador Clipper compilamos esos archivos .PRG y obtenemos archivos .OBJ, posteriormente tomamos esos archivos .OBJ, y por medio de un enlazador como RTLINK, BLINKER, EXOSPACE etc, uníamos los archivos .OBJ con los archivos de librerías de Clipper (clipper.lib, extend.lib, terminal.lib, dbfntx.lib) y el resultado del proceso de enlazado o "linkeado" era un archivo .EXE.

En (x)Harbour las cosas son "un poquito" mas complejas:

archivo.prg -> archivo.c ->archivo.obj -> archivo.exe

En (x)Harbour tomas tu código fuente en archivos .PRG (el mismo código fuente que tienes en Clipper en este momento, los cambios que tienes que hacer son mínimos), en vez de utilizar el compilador Clipper compilamos con el compilador Harbour (los parámetros de compilación exactamente los mismos que Clipper), pero el resultado de la compilación NO SON ARCHIVOS .OBJ, SON ARCHIVOS ".C", efectivamente, Harbour "traduce" tu código Clipper a código en lenguaje "C", que no es en realidad un código "C" estándar, vamos que si eres experto en "C" y editas el contenido de un archivo resultado de la compilación con Harbour, el código te parecerá mas Ensamblador que "C", esto es porque el código generado es un "PCODE", es decir, un código que solo puede ser interpretado por un motor especial llamado "PMACHINE", la "PMACHINE" para interpretar este PCODE viene en las librerías de Harbour que tienes que enlazar en el archivo .OBJ para generar el archivo .EXE.

Un momento.... entonces sí deben de existir archivos .OBJ en alguna parte del proceso de compilación, ¡ claro que existen !, los archivos .OBJ provienen de compilar el código en "C" para ello necesitas un compilador de C, y aquí es donde empieza la fiesta porque actualmente (x)Harbour es compatible con varios compiladores de "C" como el Microsoft Visual C++ desde la versión 6 hasta la versión 8, el Pelles C, el MingW32 ó el Open Watcom, pero la versión mas popular es la desarrollada para Borland C++, ya que Borland ha liberado al dominio público sin restricciones de uso el compilador Borland C++ Ver. 5.5.

Otra ventaja adicional, es que al generar (x)Harbour código en "C", entonces puedes hacer programas con el lenguaje Clipper que ya conoces para otros sistemas operativos, como Linux, MacOS, OS/2 de IBM, MS-DOS de 32 bits (DR-DOS), eso sí, no serán programas gráficos con ventanas ni nada (Windows forms), serán programas MS-DOS (para modo consola). Para cada uno de estos sistemas operativos existen versiones de (x)Harbour disponibles, obviamente los compiladores de C para estas plataformas son distintos a los usados para aplicaciones Windows.

Retomando el tema, el Compilador de "C" volverá a compilar nuestros archivos generados con (x)Harbour, y ahora sí, generará los archivos .OBJ, posteriormente esos archivos .OBJ hay que "linkearlos" junto con las librerías de (x)Harbour para generar el archivo .EXE final. Todos los compiladores de "C" incluyen su propio enlazador (linker), por lo que no requieres ningún otro producto adicional, así que te puedes olvidar de Blinker, Exospace, etc.

El verdadero problema de generar un EXE con (x)Harbour viene en la parte de proceso de compilación con "C", y es aquí donde XEdit entra en acción.

Así que lo que primero que necesitamos para migrar nuestras aplicaciones es conseguir xHarbour, aunque xEdit soporta compilación con Harbour, también lo puede usar con xHarbour, por otro lado siendo el Borland C++ el compilador de C preferido por los programadores, entonces necesitaremos obtener una versión de xHarbour para Borland C++. Puedes ir directamente a la pagina de  xHarbour.org para descargar la versión para Borland C++.

No hay proceso de instalación, simplemente descarga este archivo .ZIP y desempácalo en una carpeta que se llame de preferencia c:\xharbour (los ejemplos que se mostrarán mas adelante los he construido basándome en esta ubicación).

Luego vas a necesitar el compilador C++ de Borland (ahora Embarcadero Technologies), el uso de este compilador es gratuito, pero no es de libre distribución, tienes que obtenerlo desde la página que Embarcadero ha establecido para tal fin, previo registro. Puedes acceder a la página para obtener el Borland C++ haciendo click aquí.

El archivo que se descarga se llama FreeCommandLineTools.Exe simplemente ejecútalo y realizará la instalación del compilador en la carpeta c:\Borland.

Finalmente debes descargar la ultima version de XEdit de:


Descarga XEdit desde la web de Xailer


Xedit viene con un programa de instalación con lo cual solo tendrás que ejecutarlo e instalarlo en tu disco duro, no hay nada mas que hacer.

A continuación te explicaré los primeros pasos en el uso de XEdit, que deberán ser suficientes para poder compilar cualquier aplicación Clipper actual a 32 bits con xHarbour.

Ejecuta el archivo XEDIT.EXE desde la carpeta donde lo haz instalado, y procederemos a configurar el comportamiento básico de la herramienta:

Selecciona:

Menú Principal / Herramientas / Opciones Generales

Aparece una ventana como esta:


Esta pantalla solo contiene configuraciones básicas que no te afectarán para tu programa, excepto la opcion que dice "Xailer". No es necesario que tengas Xailer instalado, configura los directorios a donde se encuentre XEdit, si es que el sistema no lo ha hecho por default.


Para poder compilar un programa, necesitamos crear un entorno de programación. Un entorno de programación es una configuración especial donde le indicaremos a XEdit las carpetas adicionales y las opciones de los compiladores tanto de xHarbour como de Borland, necesarias de acuerdo a cada necesidad específica, por ejemplo, para compilar una aplicación en (x)Harbour para modo consola se necesitan ciertos parámetros de compilación, mientras que para compilar una aplicación para Windows hecha con FiveWin, se necesitan incluir algunas librerías y definir la ubicación de los archivos de cabecera.

Para crear un entorno:

Menú Principal / Herramientas / Entorno de programación.

Puedes tener tantos entornos de programación como necesites, por ejemplo para xHarbour en modo consola, para FiveWin, para Harbour MiniGUI, etc.

Para agregar un nuevo entorno de programación haz click en el botón con el signo "+" que se encuentra en la parte inferior de la plantalla de configuración de entornos:



Lo que sigue es simple, solo tienes que darle un nombre a tu entorno y si lo requieres puedes copiar otro entorno similar para que no tengas que volver a dar todos los datos:



Una vez que haz dado nombre a tu entorno, procederemos a configurarlo con las opciones que muestran los folders de la pantalla de configuración de entorno de programación:

General:

Sirve para indicar las rutas a los archivos INCLUDE y LIB así como los archivos LIB adicionales que necesita tu aplicación.

En el caso de una aplicacion (x)Harbour para modo consola simple y llana, no sera necesario llenar ningun dato de esta pestaña, si tu aplicación es con Harbour MiniGUI o FiveWin, aquí deberás indicar la ruta a donde se encuentran los archivos de cabecera (include) y la ruta a la ubicación de las librerías adicionales que necesite tu aplicación.

Por ultimo para esta pestaña, deberás indicar EL NOMBRE DE LOS ARCHIVOS .LIB que utilice tu programa, EN EL FORMATO DEL COMPILADOR DE C QUE VAYAS A USAR. En el caso del Borland C++ simplemente se indican los nombres de los archivos anteponiendo un signo de "+" y separandolos por comas.

Este es un ejemplo de la configuración para FiveWin:

 
Compilador xBase:

En esta pestaña configuraremos el compilador de (x)Harbour que deseamos utilizar.

Oficialmente existen 3 versiones actualmente de (x)Harbour, el xHarbour como tal, que como recordarás es un "fork" del proyecto Harbour original, del cual no han hecho muchos cambios ultimamente y 2 versiones de Harbour, la 2.x  la 3.x, ¿ Cual es la diferencia ?.

En su momento un grupo de programadores por diferencia de opinión con otros programadores del proyecto Harbour original, decidieron crear su propia versión de Harbour, con miras a crear un producto comercial al que llamaron xHarbour (eXtended Harbour), e incluyeron en el muchas monerias que no encontrarás en Harbour como las estructuras SWITCH, el manejo de archivos XMLs, los "hashes", etc.

Luego vino la gente de Harbour y dijo.... nos estamos quedando atrás y evolucionarion el compilador a la versión 3 incluyendo muchas cosas de lo que xHarbour tenía, optimizando ademas los nucleos y haciendolo mucho mas rapido que xHarbour, además de tener versión de 64 bits, cosa que xHarbour no tiene.

Regresando a nuestro tema, en esta pestaña tendrás que configurar el compilador de (x)Harbour que desees utilizar:


En la parte superior, en los radio botones puedes seleccionar la versión de (x)Harbour que desees usar, y automaticamente en la parte inferior se añadirán las librerias necesarias dependiendo de la versión que vayas a utilizar. Lo unico que tienes que configurar es la ruta donde está tu compilador de (x)Harbour.

TIP: Hay muchas versiones de Harbour, muchas versiones de Xailer o de FiveWin, y en muchas ocasiones hay determinadas versiones del compilador que funcionan con tal o cual versión de otros productos, un consejo práctico: coloca la versión de Harbour compatible con tu herramienta en el mismo directorio donde tienes tu herramienta principal, esto te ahorrará muchos dolores de cabeza en el futuro.


Compilador de C:

(x)Harbour puede usarse con distintos compiladores de C, los mas populares: El Borland C++ porque fue con el que empezó todo y MinGW porque es un compilador de C totalmente open source, le sigue el Pelles C porque es gratuito y compatible con el Microsoft C++.

Quiero hacer aquí un paréntesis para mencionar que aunque no utilices el compilador de C de Pelles C, es conveniente descargarlo porque te ofrece 2 herramientas que si programas en FiveWin o MiniGUI te serán de gran utilidad:

El editor de recursos, que si estas acostumbrado a usar el Borland Resource Workshop y que no funciona en sistemas operativos de 64 bits, lo puede sustituir perfectamente a 32 bits y 64 bits.

El compilador de recursos PORC que además de ser muy rapido, opitimiza perfectamente el ejecutable final.

Puedes descargar el Pelles C haciendo click aqui

Dependiendo del compilador de C que vayas a utilizar las opciones se cargan automaticamente, solo tienes que establecer la ruta donde se encuentra tu compilador, en este ejemplo he seleccionado el compilador C++ de Borland:


Quedan 2 pestañas por analizar que no utilizaremos en esta primera aproximación a XEdit:

Compilador de recursos: Se utiliza en caso de que quieras usar otro compilador que no sea el del C++ nativo que vayas a usar, por ejemplo el PORC de Pelles C.

Enlazador: Similar a lo anterior, si no quieres usar el enlazador (linker) de tu compilador de C++ puedes usar esta pestaña para configurar otro distinto.

Una vez que hemos creado nuestros entornos de programación, hemos terminado con el proceso de configuración, ahora llegó el momento de comenzar a migrar nuestros programas a 32 bits.

Antes de comenzar, tenemos que entender como trabaja XEdit.

XEdit trabaja en base a "proyectos", un proyecto no es mas que una carpeta del disco duro que a su vez tiene subcarpetas donde se guardan los distintos componentes de la aplicación, por ejemplo el código fuente va en una carpeta, los archivos de cabecera .ch en otra, se hace otra para los archivos de recursos .rc, y así sucesivamente.

Para crear un proyecto nuevo:

Menú principal / Archivo / Nuevo Proyecto....

Puedes crear carpetas nuevas para tus proyectos desde la ventana donde se te pide que le des un nombre al proyecto, personalmente lo que yo hago es crear una carpeta llamada PROYECTOS debajo de la carpeta XEDIT2 y ahí voy creando subcarpetas para guardar cada proyecto.

Creemos pues la capeta "PRUEBA1" y pongamosle el mismo nombre a nuestro proyecto.

La configuración de cada proyecto se guarda en archivos XPJ (Xailer/Xedit ProJect) que no son mas que archivos .XML con información sobre el proyecto que estamos usando.

Pulsamos el botón de ACEPTAR y aparece esta ventana, que configura las propiedades del proyecto:


Aquí indicaremos si queremos crear un EXE, una LIB o una aplicación WEB (de momento no disponible), una descripción del aplicativo que estamos desarrollando, misma que se "pegará" al EXE final, deberemos indicar el nombre del archivo de salida, en este caso prueba1.exe y MUY IMPORTANTE debemos indicar el ENTORNO DE PROGRAMACION, previamente creado, que vayamos a utilizar para compilar este programa, en este caso "FW xHB", también deberemos indicar el nombre del módulo principal, pero de momento dejaremos en blanco este espacio, presionemos el botón ACEPTAR para guardar los cambios (puedes volver a esta ventana posteriormente desde Menú Principal / Proyecto / Propiedades del proyecto).

Al presionar el botón Aceptar XEdit te pondrá el siguiente mensaje de aviso:



Indicándote que se van a crear subcarpetas para guardar los distintos componentes de tu aplicación, simplemente haz click en el botón "SI".

Ya estamos listos para hacer un pequeño experimento, vamos a crear un pequeño .PRG de ejemplo y a compilarlo usando xEdit.

Seleccionaremos:

Menu Principal / Archivo / Nuevo / PRG.

Veremos en el editor de código fuente que aparece una pestaña nueva con el nombre MODULE1.PRG, escribiremos lo siguiente y guardaremos este código fuente :



Como verás es un programa Clipper puro y duro, con instrucciones básicas de modo consola.

Llegó el momento de compilar este programa, simplemente selecciona:

Menu Principal / Proyecto / Compilar
ó presiona Ctrl+F9.

Los mensajes del compilador los verás en la parte inferior de la ventana del editor de código:



Si la última línea es 1 Files, X Warnings, 0 Errors .... ¡ Felicidades ! haz logrado compilar tu primer programa a 32 bits.

Para ejecutarlo, haz doble click sobre él en el explorador de Windows y verás aparecer una ventana de MS-DOS con esto:



Para compilar mas de un .PRG, tienes que hacer lo siguiente:

Copia todos los .PRG que vayas a compilar a la carpeta SOURCE, y luego selecciona:

Menu Principal / Proyecto / Añadir Fichero al proyecto

Selecciona todos los .PRGs que necesites, realiza esta misma operación si tienes archivos .CH que desees integrar en tu sistema, estos los deberás colocar en la carpeta INCLUDE de tu proyecto.

Si en alguno de tus programas utilizas una FUNCTION MAIN() entonces en las propiedades del proyecto (Menu principal / Proyecto / Propiedades del Proyecto) en la opción de MODULO PRINCIPAL selecciona el PRG que tiene la función MAIN(), si no tienes función Main en algunos de tus programas, entonces selecciona el .PRG que arranca tu aplicación.

Para compilar todos los programas simplemente presiona Ctrl + F9.

Si estás programando con FiveWin, entonces hay que cambiar algunas cosas y añadir otras:

Los .PRGs para un programa con FiveWin se agregan al proyecto de la misma manera que como se hace para un proyecto para xHarbour modo consola.

Para integrar los recursos gráficos (archivos .RC, .BMP, .ICO, CUR, etc.) al proyecto XEdit, procederemos la siguiente manera:

Primero tenemos que crear un archivo de recursos vacío, esto se hace usando el Gestor de Recursos de XEdit, para activarlo selecciona:

Menu principal / Ver / Gestor de recursos

Y aparecerá la siguiente pantalla:



Presiona el botón que tiene hoja en blanco, del lado izquierdo de la pantalla, ese botón sirve para crear un archivo de recursos .RC vacío, aparecerá una ventana para dar nombre al archivo de recursos, esta pantalla te sugiere el nombre del .RC, en este caso será el mismo nombre que el de tu proyecto, pero mi sugerencia es: dale el mismo nombre que el archivo .RC que utilizas en tu programa FiveWin, esta operación creará un archivo RC vacío, pero quedará registrado el nombre del RC en las propiedades del proyecto para que al momento de compilar XEdit lo incluya en los archivos que deben ser enlazados para generar el EXE final.

DESPUES de crear el RC vacío, puedes copiar todos tus recursos a la carpeta RESOURCE de tu proyecto XEdit, y XEdit hace el resto, compilará y enlazará los recursos dentro de tu programa .EXE, es MUY IMPORTANTE que primero crees el .RC vacío, ya que si copias primero los recursos a la carpeta RESOURCE y luego creas el .RC con el Gestor de Recursos entonces TE VAS A CARGAR TU .RC, con todos los diálogos, cursores y bitmaps que tenga pegados adentro, así que el que avisa no es traidor, estás advertido.

Aprovechando que estamos hablando del tema de los recursos, la siguiente información te puede ser útil: ¿ sabías que puedes programar XEdit para "lanzar" cualquier aplicación que quieras desde el menú principal ?, esta característica es sumamente útil para enlazar por ejemplo tu editor de recursos como una opción del menú del Xedit, y no tener que ir navegando por todo el disco duro para encontrar el EXE adecuado, yo por ejemplo tengo configuradas las herramientas que más uso la opción HERRAMIENTAS del menú principal:


Para agregar herramientas, que pueden ser no solo archivos .EXE sino también archivos de ayuda .CHM hacemos lo siguiente:

Menu Principal / Herramientas / Configurar Herramientas

Aparece la siguiente pantalla, presiona el boton AÑADIR y luego selecciona el archivo .EXE o .CHM que quieras añadir al menú:



¡ y listo !, haz agregado una herramienta a tu menú, la cual se ejecutará de manera automática cada vez que la selecciones del menú.

Ahora bien, si el compilador de recursos de Borland te está dando problemas con el tamaño de los archivos .RC o con los bitmaps muy grandes o de muchos colores, también puedes cambiar el compilador de recursos para usar otro que dé menos problemas, para saber como lee mi artículo: Cambiando el compilador de recursos, dentro de este mismo blog, si compilas tu programa FiveWin con XEdit, puedes usar los trucos ahí mencionado, recuerda que XEdit es muy similar al IDE de Xailer.

Retomando el tema de FiveWin con xEdit, otra cosa importante son las librerías adicionales que suelen llevar los programas FW, para empezar las 2 básicas: FIVEHX.LIB y FIVEHC.LIB.

Para la gestión de librerías (archivos .LIB) Xedit posee un gestor de librerías, para acceder a el:

Menú Principal / Proyecto / Propiedades del Proyecto y seleccionar del árbol:LIBRERIAS


Aparece una pantalla similar a esta:


Pulsando el botón AÑADIR, podrás agregar las librerías que quieras incluir en tu proyecto, por default XEdit te incluirá que las de xHarbour y Borland C++, y tu podrás seleccionar las adicionales que necesites haciendo click en el checkbox, en este caso he añadido las 2 librerías de FiveWin. También es posible definir el orden de linkeado, subiendo y bajando las librerías con los botones que tienen flechas.


Existen mas trucos y herramientas disponibles con XEdit, pero ahora te toca a tí descubrirlas. El programador de Clipper que quiera migrar a xHarbour, encontrará en XEdit LA HERRAMIENTA que le facilitará el proceso de migración, además de que si en un futuro decide desarrollar aplicaciones para Windows usando Xailer, pues ya tendrá un buen trecho andado, porque el IDE de Xailer y XEdit comparten muchas herramientas comunes.

El programador de FiveWin también encontrará en XEdit un valioso aliado, conozco muchos programadores que todavía compilan sus programas con archivo .BAT o .MAK desde una ventana de MS-DOS o todavía utilizan el EDIT de MS-DOS o el NOTEPAD para escribir sus programas, con XEdit podrán automatizar mucho de ese trabajo, con el consabido ahorro de tiempo, tendrán un editor de código profesional, así como otras herramientas interesantes todas integradas en un mismo lugar, además de que podrán probar "un poquito" sobre como se desarrolla usando Xailer.

Espero que con este tutorial muchos de ustedes se animen a darle las gracias al nuestro viejo y querido Clipper y que se adentren en el mundo de la programación a 32 bits.

miércoles, abril 15, 2009

Sybase crea nuevo foro de soporte para xHarbour

Estupendas noticias para todos aquellos que usamos Advantage Database Server en nuestros desarrollos con (x)Harbour.

Sybase, los nuevos dueños de Advantage Database Server, han creado un nuevo foro de soporte para (x)Harbour.

Después de insistir bastante por parte de muchos usuarios de ADS con (x)Harbour, Sybase iAnywhere ha cedido a la presión y nos ha regalado un lugar en su grupo de noticias (newsgroup) para soportar ADS con xHarbour.

Tomando en cuenta que el cliente ADS para (x)Harbour fue creado por los mismos programadores de xHarbour, es un gran avance por parte de Sybase el reconocer a (x)Harbour como una plataforma seria y creciente de desarrollo.

Para acceder a los foros de Advantage Database Server con (x)Harbour, puedes utilizar un "news reader" como el Outlook Express o el Mozilla Thunderbird, el nombre del servidor es:

devzone.advantagedatabase.com

No requiere autenticación y ahi puedes encontrar grupos en distintos idiomas y lenguajes de programación para Advantage Database Server.

También puedes acceder a la página de soporte de ADS para realizar la conexión con el servidor de noticias en http://devzone.advantagedatabase.com.

Y finalmente si quieres tener acceso por web a los foros la pagina Newswhat te ofrece un acceso directo a los foros de ADS.

miércoles, abril 08, 2009

De vacaciones de Pascua

Les informamos que nuestras oficinas estarán cerradas del Jueves 9 al lunes 13 de abril del presente.

Volveremos a prestar nuestros servicios a partir del día 13.

Felices pascuas !!!!

sábado, abril 04, 2009

Nuevo "servicio" XBase Guru

Gracias a nuestro proveedor de estadísticas MOTIGO, puedo saber muchas cosas interesantes sobre la gente que visita Objeto Persistente.

Una de las características mas interesantes de MOTIGO es su sección de FUENTES DE TRAFICO, donde me da un listado de las consultas que mis lectores hacen en Google y otros buscadores y que finalmente los traen a Objeto Persistente.

He visto que muchas de esas preguntas se repiten semana tras semana y no son difíciles de constestar, así que he decidido abrir un nuevo servicio llamado Xbase Guru.

En este nuevo blog, voy a responder a las preguntas MAS INTERESANTES y MAS FRECUENTES que me llegan por medio de las fuentes de tráfico de Motigo sobre programación en Xbase, ya sea Clipper, Xailer, (x)Harbour, FiveWin, y en general las preguntas que entren dentro de mi ámbito de "expertise".

No voy a dar un curso, no voy a explicar como hacer sistemas completos ni voy a explicar nada a detalle, tampoco voy a responder preguntas particulares ni voy a enviarles respuestas privadas a nadie, simplemente te daré las pistas para que tu continúes tu investigación y que puedas soluciona tu problema de programación, como lo saben todos los que han tomado curso conmigo: yo no les regalo pescados, yo les enseño a pescar.

Por supuesto hay una sección de comentarios (moderada) para cada comentario en los cuales podrás pedir mas información.

No prometo que el blog se actualice diario ni mucho menos, pero sí que cada semana habrá preguntas contestadas, quizá 3 o mas de un solo golpe.

Esta semana las preguntas contestadas son:

Convertir DBF a XLS con Clipper 5.x
Soporte de SQLite con Xailer
Documentación de xHarbour
Lenguajes de programación mas usados
Crack para Xailer

Si tu quieres preguntar algo y quieres que responda en Xbase Guru, simplemente ve a Google, o a cualquier buscador y teclea lo que quieras preguntar, y si en las respuestas sale un link a OBJETO PERSISTENTE simplemente haz click ahí y listo, tu pregunta me llega y yo la contesto.

Espero que este nuevo servicio sea de su agrado, visitanos en www.xbaseguru.blogspot.com

lunes, marzo 30, 2009

Prodigy Infinitum aumenta su velocidad, Buenas noticias para Advantage Database Server

El servicio de Internet ADSL de Banda Ancha de Telmex en México: Prodigy Infinitum va a aumentar su velocidad de acceso a la red en los próximos días, las nuevas velocidades serán:





Infinitum 512AnteriorNueva
Vel. Bajada512 kbps784 kbps
Vel. Subida128 kbps256 kbps




Infinitum 1000AnteriorNueva
Vel. Bajada1024 kbps1536 kbps
Vel. Subida128 kbps384 kbps




Infinitum 2000AnteriorNueva
Vel. Bajada2048 kbps3072 kbps
Vel. Subida256 kbps512 kbps




Infinitum 4000AnteriorNueva
Vel. Bajada4096 kbps6144 kbps
Vel. Subida768 kbps1024 kbps

Como siempre el aumento de velocidad será paulatino y de momento no está disponible en todo el país, ya sabes, las principales ciudades (México, Guadalajara y Monterrey) y algunas otras localidades.

Para verificar la nueva velocidad es necesario apagar y encender el modem/router y luego puedes verificar la velocidad en www.speedtest.net este sitio tiene un velocímetro de internet bastante confiable.

La buena noticia para los usuarios de Advantage Database Server, es que con las nuevas velocidades de Infinitum, el acceso al Advantage Internet Server se hace mucho mas eficiente, al estar dentro de la misma red (la de Prodigy Infinitum) la velocidad de respuesta es como si estuvieras dentro de una LAN de 10 mbps, perfectamente manejable, lo que te permite conectar sucursales remotas con tus archivos DBFs con una velocidad muy buena, sin necesidad de VPN ni de instalar nada del lado del cliente, solo tu servidor ADS que ya tiene incluido el Advantage Internet Server.

Prueba estos demos que se conectan a nuestra base de datos en la Ciudad de México, la respuesta debe ser bastante buena ya que nuestra conexión de 6 megas de bajada y 1 de subida.