Este es el último comentario del año, y he decido cerrar con broche de oro, porque luego se me quejan que estoy "perdiendo el toque" y que ya no publico cosas interesantes y que lo único que hago es meterme con FiveWin, para que mis detractores vean que no es cierto y como un regalito adelantado de Reyes para mis amigos, aquí les va este comentario que creo que será interesante para mas de uno.
En esta ocasión vamos a hablar del "Sistema Extendido" de (x)Harbour, este comentario lo puse hace algunos meses en el foro privado de Xailer, pero considero de interés de todos los programadores de (x)Harbour tener acceso a esta información.
Este es un "comentario" simplemente, no pretende ser una guía completa del Sistema Extendido de (x)Harbour pero te va a dar una muy buena idea de como hacer muchas cosas en "C", con instrucciones básicas para integrar rutinas escritas en ese lenguaje en tus programas (x)Harbour, Xailer, MiniGUI o FiveWin.
Al igual que Clipper, (x)Harbour tiene un "Sistema Extendido" que te permite conectarte con funciones en lenguaje "C" mediante "wrappers" o "envolturas", seguramente si te pasas por la cocina de casa y ves la caja del foil (papel) de aluminio que se usa para envolver el bocadillo o tapar el tupper, verás que la caja dice "Reynolds Wrap":
Ahora que nos ha quedado claro de donde viene la palabra "wrapper", y que es un wrapper, podemos comenzar con la explicación.
Un wrapper o envoltura sirve, como su nombre lo indica, para "envolver" una función en C y así poder utilizarla desde xHarbour.
Un wrapper realiza básicamente 2 trabajos: traducción y ejecución.
El primer trabajo, el de "traducción", significa que el wrapper "intercepta" los parámetros enviados a la función desde xHarbour y "traduce" dichos parámetros enviados a los tipos de variable utilizados por la función en "C", y para esto cuenta con una serie de funciones que son las funciones llamadas hb_parXXXXX (harbour parameter).
Veamos un ejemplo:
Si yo tengo que pasarle un parámetro numérico a una función en "C", desde (x)Harbour no tengo problemas, es un "numeric" simple y sencillo, pero en "C" los números se pueden expresar de muchas formas, como integer, long, float, etc. las funciones hb_parXXXX son las que se encargan del proceso de traducción a los valores en "C" correspondientes.
Una vez "traducidos" los parámetros de los tipos de datos de (x)Harbour a los tipos requeridos por la función en "C", viene el proceso de "ejecución" en el cual se manda llamar la función en "C" que deseamos, enviándole los parámetros traducidos.
Una vez que se ejecuta la función y esta devuelve un valor, dicho valor debe ser traducido nuevamente a un tipo de dato válido que (x)Harbour pueda manipular, si la función retorna por ejemplo un valor "double", este tiene que ser traducido a "numeric" para esto se utilizan las funciones hb_retXXXX (Harbour Return)
Veamos un ejemplo práctico, tomado del RDDADS de (x)Harbour:
Supongamos que queremos ejecutar una función llamada:
AdsSetServerType(integer) -> valor
Esto quiere decir que la función AdsSetServerType escrita en "C", recibe un parámetro numérico "integer" tipo de dato que NO EXISTE en xHarbour, y devuelve un valor "X" no sabemos de que tipo.
Bien, tenemos que crear un wrapper o envoltorio para poder llamar a esta función escrita en "C" desde nuestro código xHarbour / Xailer / MiniGUI / FiveWin, y ahora verás porque se llaman "envolturas":
Lo primero que debemos hacer es crear el "nombre harbour" para la función esto se hace así:
HB_FUNC( ADSSETSERVERTYPE ){ }
Es MUY IMPORTANTE que el nombre de la función vaya TODO CON MAYUSCULAS, las {} indican el principio ({) y el fin (}) de la envoltura.
Como esto es una función en "C", nosotros debemos definir las variables con las cuales va a trabajar nuestra función, así que las definimos:
HB_FUNC( ADSSETSERVERTYPE )
{
int servType;
UNSIGNED32 ulRetVal = 999999;
}
Hemos definido una variable llamad servType de tipo INTEGER y un "entero sin signo" (UNSIGNED32) llamada ulRetVal, y le hemos dado un valor de 99999.
La primer variable nos servirá para "recibir" el parámetro "numeric" enviado desde xHarbour, y la segunda variable nos servirá para recoger el valor retornado por la llamada a la función en "C" y posteriormente devolverlo en formato xHarbour.
Como expliqué antes, ServType nos va a servir para recibir el parámetro de entrada, y ulRetVal para regresar el valor devuelto por la función, así que manos a la obra:
Primero tenemos que "interceptar" el valor enviado como parámetro:
HB_FUNC( ADSSETSERVERTYPE )
{
int servType;
UNSIGNED32 ulRetVal = 999999;
servType = hb_parni( 1 )
}
Lo que hicimos fue utilizar una función hb_parXXXX(), en este caso la función hb_parni(
{
int servType;
UNSIGNED32 ulRetVal = 999999;
servType = hb_parni( 1 );
hb_retnl( ulRetVal);
}
{
int servType;
UNSIGNED32 ulRetVal = 999999;
servType = hb_parni( 1 );
ulRetVal = AdsSetServerType( servType );
hb_retnl( ulRetVal);
}
{
int servType;
UNSIGNED32 ulRetVal = 999999;
if( hb_pcount() > 0 )
{
servType = hb_parni( 1 );
ulRetVal = AdsSetServerType( servType );
}
hb_retnl( ulRetVal );
}
2) Incluirlos dentro de algún archivo .PRG de tu aplicación.
...
#pragma enddump
local cFile
...
...
return cFile
HB_FUNC( D2BIN )
{
BYTE *Buffer;
Buffer = (BYTE *) hb_xgrab( sizeof(double) );
*( (double *) ( Buffer ) ) = ( double ) hb_parnd( 1 );
hb_retclen( ( char *)Buffer, sizeof(double) );
hb_xfree(Buffer);
}
{
hb_retni( hb_parni( 1 ) & 0x00FF );
}
{
hb_retni( ( hb_parni( 1 ) >> 8 ) & 0x00FF );
}
LOCAL cVret := ""
cVret := SUBSTR(cFileName,1,RAT(".",cFileName)-1)
RETURN (cVret)
No hay comentarios.:
Publicar un comentario