miércoles, 13 de mayo de 2015

Quitando elementos de un array

Desde los inicios de Clipper, para quitar un elemento de un array utilizabamos la función aDel(), cuyo uso tenía un efecto un poco extraño: no disminuía el tamaño del array, sino que desplazaba una posición todos los elementos posteriores al eliminado. Esto obliga a utilizar la función aSize( ) para rectificar la situación.

Gracias a la experiencia y lucidez de los desarrolladores de Harbour esto ya es un inconveniente del que nos podemos olvidar. Ahora la función aDel tiene un tercer parámetro, lShink, que hace la tarea obvia de disminuir el tamaño.

aDel( aArray, nElement <, lShrink> )

Por defecto lShrink es .F., por lo que sigue siendo compatible con el código existente.

LOCAL aTest:= { 1, 2, 3, 4, 5 }

? Len( aTest ) // -> 5

aDel( aTest, 3 )
? Len( aTest ) // -> 5


aDel( aTest, 3, .T.  )
? Len( aTest ) // -> 4 !

Tantas veces hemos tenido que ajustar el array debido al comportamiento particular de aDel() que no podía dejarlo pasar.

miércoles, 1 de febrero de 2012

Funciones para manipular bits


La plantilla de nuevas funciones en Harbour es muy extensa, pero al no tener una buena documentación es dificil saber como se llaman las que estamos necesitando y a veces incluso terminamos duplicándolas sin saber que ya están escritas y con un código de gran calidad.
Rebuscando entre el código fuente de Harbour y sus ejemplos encontré las funciones de manipulación de bits que buscaba, y ya puestos os dejo una breve descripción de las mismas que espero les resulte útil.

HB_BITAND( nParam1, nParam2, … ) → nResult
Retorna un entero, el 'AND' lógico entre uno o más números enteros.

? HB_BITAND( 1, 3, 5 ) // 1

HB_BITOR( nParam1, nParam2, … ) → nResult
Retorna un número entero, el 'OR' lógico entre uno o más números enteros.

? HB_BITOR( 1, 3, 5 ) // 7

HB_BITXOR( nParam1, nParam2, … ) → nResult
Retorna un número entero, el 'XOR' lógico (OR exclusivo) entre uno o más números enteros.

? HB_BITXOR( 1, 3, 5 ) // 7

Como punto a destacar en estas tres funciones, y a diferencia de otras implementaciones que había visto anteriormente, se pueden especificar más de 2 parámetros.

HB_BITNOT( nParam ) → nResult
Retorna el entero negado del argumento.

? HB_BITNOT( 5 ) // -6

HB_BITTEST( nParam, nBit )  → lResult
Devuelve el valor lógico que indica si en bit nBit está en 1. Los bits están enumerados del 0 a 31, siendo el 0 el bit menos significativo.

? HB_BITTEST( 5, 0 ) // .T.
? HB_BITTEST( 5, 1 ) // .F.
? HB_BITTEST( 5, 2 ) // .T.

HB_BITSET( nParam1, nBit ) → nResult
Retorna el entero resultante de activar el bit nBit en el entero nParam1.

? HB_BITSET( 3, 2 ) // 7

HB_BITRESET( nParam1, nBit ) → nResult
Retorna el entero resultante de desactivar el bit nBit en el entero nParam1.

? HB_BITRESET( 3, 0 ) // 2

HB_BITSHIFT(  nParam1, nBit ) → nResult
Devuelve el entero nParam1 desplazado nBits, cuyo valor es positivo para desplazamientos a la izquierda y negativo a la derecha.

? HB_BITSHIFT( 3, 2 ) // 12
? HB_BITSHIFT( 9, -1 ) // 4

En todos los casos los parámetros se validan, y generan un error irrecuperable si el tipo es diferente de N.

Hasta la próxima...

viernes, 2 de septiembre de 2011

Extended Codeblocks

De más está decir con la versión 2  ha habido un salto de calidad enorme, la velocidad de Harbour es impresionante y reconocido por gente como la de Xailer, que tiene su producto basado en xHarbour.
Seguramente al igual que yo, como usuario de Harbour, a veces sentirás que te pierdes las novedades que día a día se incorporan. Más allá de la sacudida interna que significó la reorganización de las librerias, también aparecieron muchas cosas interesantes, como es el caso de los extended codeblocks.

¿Y eso que es?

Es una funcionalidad que ya existía en xHarbour, al menos muy similar, aunque con una sintaxis levemente diferente. Lo que permite es poder declarar un codeblock que se extienda más de una linea, con variables locales, y con la posibilidad de usar todo el juego de instrucciones. Seguramente alguna vez te ha pasado que el código de un codeblock era tan complejo que era ilegible, y terminabas escribiendo una función que lo reemplazaba. Por ejemplo en un programa en el que trabajo en este momento, con Harbour y FiveWin, si quiero añadirle una hotkey a un GET para que llame a una función de búsqueda, escribía algo así: 

oBancoGet:bKeyDown:= {|nKey, uVal| If( nKey == VK_F2,If( !Empty(uVal:= Buscar(cDbfBancos, 'Codigo')), (oRB:Banco:= uVal,oDlg:Update()),) ,) }


En una línea tienes que montar todo: Verificar que la tecla es la que quieres, llamar a la función de búsqueda, y si esa función retorna un valor, asignarlo a la variable y actualizar el control.



Con extended codeblocks...

La cosa se ve mucho más clara:

oHC['Banco']:bKeyDown:= {|nKey|
                        LOCAL uVal
                        If nKey == VK_F2
                           If !Empty(uVal:= Buscar(cDbfBancos, 'Codigo'))
                              oRB:Banco:= uVal
                              oDlg:Update()
                           EndIf
                        EndIf
                        Return NIL
                        }

mucho más claro, verdad? Además se pueden declarar variables locales, usar IFs o cualquier otra instrucción. Es obligatorio que incluya una instrucción RETURN.

Hasta la próxima, espero que no pase tanto tiempo.

miércoles, 24 de diciembre de 2008

Eventos para OLE

Hace bastante tiempo que echaba en falta el manejo de eventos de los COM. Las librerías que existen y que manejan eventos tienen asociados controles visuales, por ejemplo con Fivewin, que maneja perfectamente objetos como internet explorer con sus eventos, pero siempre a condicion de que sean visuales.
Por suerte hace algún tiempo Oskar Lira hizo pública una librería que mostraba la forma de hacerlo, aunque al igual que el resto requiere estar asociado a un control. Mirándo la forma en la que maneja eventos hice algunas pruebas con el código propio para usar Active Template Library guiándome por el código de Oskar y ¡salió funcionando! El código de Oskar, aunque al principio parecía chino, luego de leer y estudiar un poco resulto no ser tan complejo y, como todo, solo necesita de un poquito de know how.

¿How To?
Hay una clase propia de Windows, AtlAxWin, que hace las veces de wrapper al control OLE. Normalmente esta clase tiene como ventana padre la de nuestra aplicación, y lo que hice fue cambiar ese padre (en modo consola somos algo así como huérfanos de ventana padre) por la ventana del escritorio.
El resto es lo mismo para los ActiveX, y ya estaba todo hecho, solo quedaba ensamblar.

Usando Eventos con ADO
Tengo mis propias clases que envuelven las clases reales de ADO, para poder acceder a los campos de los resultados directamente por el nombre y usar verbos típicos de dbase como gotop, skip, etc., como si fuese una tdatabase. Ademas la conexión tiene un modo FROM USER, que incorpora la posibilidad de consultarle al usuario la conexión. Esto lo explica bien Biel en su blog,
y el conocimiento de ADO original viene de las clases de José Luis Capel. A ambos mi reconocimiento y agradecimiento.

Las clases de ADO que originalmente usaban un CreateObject(), ahora usan un OleWEvent():New(), y eso es todo lo que habría que hacer para usar las nuevas clases en lugar de las originales.

En los archivos hay un primer ejemplo, que es un proyecto con xMate, donde estan las clases, el 100% del código fuente, y una prueba con Harbour puro, sin FiveWin.

En el segundo ejemplo, hay un proyecto de xMate con FW, que es el programa testxbrw2 del directorio Samples de Fivewin, pero modificado para que use ADO, y muestre la reaccion a los eventos de la nueva clase.

Una advertencia importante: es muy fácil enredarse con los eventos, es lo primero que me pasó al meterme con FW. Resulta que si dentro del evento actualizo la ventana que contiene un XBrowse, el pintado del xbrowse me genera nuevos eventos cuando todavía no he terminado de procesar el primero, y la aplicación queda en un bucle de eventos y hay que matar el proceso para salir, por favor tenedlo en consideración.

También he probado las OleWEvent con otros ActiveX como PdfCreator y funciona a la perfección. Si haces la prueba con algún ActiveX que use eventos por favor comenta los resultados.

¡Feliz Navidad!

martes, 25 de noviembre de 2008

Otra forma de enviar correo

Desde que tuve disponible una conexión a Internet he usado muchas soluciones diferentes para enviar correos desde mis programas, desde MS-DOS usando blat hasta nuestros días con [x]Harbour y TIP, pasando por todas las variedades de clases y librerías. Hace poco, buscando información sobre un tema totalmente diferente encontré por casualidad en un foro unos artículos que me llamaron la atención que mostraban una opción más sobre la que no había oído ni leído nunca, pero que se supone que está ahí, para usar, y forma parte de la librería de Windows desde hace mucho.

Collaboration Data Objects

Los Collaboration Data Objects (CDO) son un conjunto de componentes que Microsoft desarrolló para facilitar la gestión de mensajes, inicialmente destinados a usarse como mecanismo de enlace e interacción con servidores Exchange, pero luego se extiende su uso hacia todo el espectro de servicios de mensajes de Internet. Hace su aparición junto con Windows 2000 y desde esa versión está disponible como parte de la libreria del sistema operativo, es decir que no necesitamos utilizar ninguna librería ajena al propio Windows. El soporte de los componentes está en una dll dentro del directorio del sistema de windows, %WINDOWS%\System32\cdosys.dll. El soporte de la dll es completo con Borland C++ 5.5, y en el directorio include del compilador se encuentran varios encabezados que, aunque no los necesitaremos, pueden ayudar como referencia al usar los objetos COM.

Manos a la obra

Para enviar correo utilizamos dos componentes. El primero de ellos, referido a la configuración del servicio de correo, se usa para establecer la información de la cuenta que utilizaremos para el envío de correo. Nótese la particular nomenclatura de las variables del componente, al principio me costó un poco encontrar la forma de acceder directamente a ellos para darles un valor, que al final lo resolví por analogía con ADO, usando la propiedad 'Value'.

loCfg := CREATEOBJECT( "CDO.Configuration" )
WITH OBJECT loCfg:Fields
:Item( "http://schemas.microsoft.com/cdo/configuration/smtpserver" ):Value := "smtp.gmail.com"
:Item( "http://schemas.microsoft.com/cdo/configuration/smtpserverport" ):Value := 465
:Item( "http://schemas.microsoft.com/cdo/configuration/sendusing" ):Value := 2
:Item( "http://schemas.microsoft.com/cdo/configuration/smtpauthenticate" ):Value := .T.
:Item( "http://schemas.microsoft.com/cdo/configuration/smtpusessl" ):Value := .T.
:Item( "http://schemas.microsoft.com/cdo/configuration/sendusername" ):Value := "testcdo@gmail.com"
:Item( "http://schemas.microsoft.com/cdo/configuration/sendpassword" ):Value := "prueba2345"
:Update()
END WITH


En este ejemplo hay otra particularidad: como usamos gmail, el puerto del smtp no es el estandar 25, sino 465, y requiere ademas autenticación usando ssl.

Para componer el mensaje propiamente dicho usamos el componente Message, que tiene las propiedades normales de todo correo: To, From, CC, BCC, etc.


loMsg := CREATEOBJECT ( "CDO.Message" )
WITH OBJECT loMsg
:Configuration = loCfg
:From = "testcdo@gmail.com"
:To = "carlosantoniomora@gmail.com" // <----- Coloca aqui tu direcci¢n de correo
:Subject = "Prueba con CDO"
:TextBody = "Este es un mensaje de prueba con CDO desde Harbour."
:Send()
ENDWITH



En general todos los errores presentan al ejecutar el metodo Send, al final. Dado que son COMs, lo mejor es empaquetar el bloque dentro de un TRY/CATCH para poder tenerlos controlados.

El proyecto completo está aquí, es solo Harbour puro y duro. Luego veremos como manejar adjuntos, contenido html y más.

He cambiado el alojamiento de los ejemplos a ziddu, vamos a ver que resultado dá.

martes, 4 de noviembre de 2008

Harbour Advisor 0.1

En un post en el foro de Fivetech, Manuel Mercado nombró 'Harbour Advisor' como una de las cosas deseables a futuro, y ese nombre me trajo muchísimos buenos recuerdos.
Hace algunos años, en las épocas donde Clipper aún vivía, teníamos gran cantidad de publicaciones con información técnica, y de muy buen nivel. Una de las más importantes era Databased Advisor, y su versión especializada Clipper Advisor, que cubria el desarrollo de varios lenguajes, entre los que se incluía, como no, a Clipper. Los gurúes como Rick Spence y otros solían publicar artículos de gran factura técnica.
Hoy en día, y por la razón que sea, ya no existen publicaciones dedicadas a [x]Harbour, Clipper, FiveWin, Xailer ni ninguna otra GUI, pero estoy convencido de que si la hubiese, seguramente tendría muchos seguidores.
Tambien creo que es factible al menos tener una edición electrónica, tal como la que existe para Ubuntu, que se llama Full Circle Magazine. Solo sería necesario un grupo de personas dispuesto a compartir conocimientos, con un compromiso de aportar una ó dos colaboraciones al año. Es como hacer lo que hacemos siempre, pero de forma aunada y con cierta continuidad. Habría que considerar la publicación simultanea en inglés y castellano, al menos en el corto plazo.
Es para pensarlo...