Page 1 of 1

Para Antonio... posible bug en Harbour

PostPosted: Mon Aug 15, 2016 10:09 am
by xmanuel
Sé que no es aquí sitio más apropiado pero como mi inglés es pésimo no quiero escribir en la lista...

Tengo una funcion en C que básicamente recibe un parametro por referencia y lo guarda en una estructura.

Luego con un GET acepto el valor desde un PRG pero, he aquí el problema, cuando la variable la declaro en el PRG como LOCAL el valor no es visible en C, en cambio cuando lo hago como STATIC sí.
He averiguado que si antes del GET pongo esto _GET_( niVar, "niVar" ) si funciona bien aunque sea local. Por lo que deduzco que el GET hace algo por que hacer perder la referencia a la variable.
Code: Select all  Expand view


#include "hdo.ch"
#include "InKey.ch"

//------------------------------------------------------------------------------

procedure main()

    static nSocIni, nSocFin  // Con local no funciona, static si... porque?     <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    local oDb, oStmt, oCur, e
    local cDb := "agenda.db"
    local cTabla := "socios"
    local cSql := "SELECT * FROM " + cTabla + " WHERE clavesocio BETWEEN ? AND ? ;"
    local getlist := {}
           
    nSocIni := nSocFin := 0

    cls

    oDb := THDO():new( "sqlite" )

    oDb:setAttribute( ATTR_ERRMODE, .t. )

    if oDb:connect( cDb )
        TRY
            oStmt := oDb:prepare( cSql )  // Prepara la sentencia y crea el objeto oStmt

            oStmt:bindParam( 1, @nSocIni )   // <<<<<<<<<<<<<<<<<<<<<<<<<<< AQUI LAS METO EN LA ESTRUCTURA EN C
            oStmt:bindParam( 2, @nSocFin )  // <<<<<<<<<<<<<<<<<<<<<<<<<<< AQUI LAS METO EN LA ESTRUCTURA EN C

            @ maxrow(), 00 say "Presiona <INTRO> para selecionar rangos o <ESC> para salir..."

            while inkey( 0 ) != K_ESC

                cls

                @ 02, 02 say "Entrada de datos:"
                @ 04, 02 say "Entre rango inicial:" get nSocIni picture "@K9"
                @ 05, 02 say "Entre rango final..:" get nSocFin picture "@K9" valid validaRango( nSocIni, nSocFin )
   
                read
               
                if lastkey() != K_ESC .and. updated()

                    oStmt:execute() // Ejecuta la sentencia     <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< AQUI USO LAS VARIABLES PERO EN C PERO SOLO PASA EL VALOR SI SON STATIC O LAS ASIGNO SIN EL GETSYSTEM

                    // Creamos un cursor local (navigator) como un hash table
                    oCur := THashCursor():new( oStmt:fetchAll( FETCH_HASH ) )

                    cls

                    @ 00, 00 say "Resultado de la consulta -> " + hb_ntos( oStmt:rowCount() ) + " registros:" color "W+/R"
                    @ maxrow(), 00 say "<ESC> para volver al menu..." color "W+/R"

                    if oCur:reccount() > 0
                        miBrwCursor( oCur, 1, 0, maxrow() - 1, maxcol() )
                    else
                        msg( "No hay registros en ese rango" )
                    endif

                    oCur:free()
                else
                    msg( "Nada que hacer..." )
                endif

                cls
                @ maxrow(), 00 say "Presiona <INTRO> para selecionar rangos o <ESC> para salir..."
            end
           
        CATCH e
            eval( errorblock(), e )
        FINALLY
            if oStmt:className() == "THDOSTATEMENT"
                oStmt:free()
            endif
            msg( "Se acabo" )
        end

    endif

    oDb:disconnect()

return

//------------------------------------------------------------------------------
 


Qué puede ser? :x :x :x :mrgreen: :mrgreen: :mrgreen: :mrgreen: :oops: :oops: :oops: :oops:

Re: Para Antonio... posible bug en Harbour

PostPosted: Mon Aug 15, 2016 10:27 pm
by Antonio Linares
Manu,

Puedes mostrar el código de bindParam() ?

Re: Para Antonio... posible bug en Harbour

PostPosted: Tue Aug 16, 2016 6:01 am
by xmanuel
Gracias Antonio, por supuesto que si, pero me reitero cuando lo asigno directamente aunque sea local funciona
así funciona nSocIni := 5 es cuando lo paso por el GET cuando deja de funcionar salvo que la declare como static...

Aquí está el c´digo del métod BINDPARAM:

Code: Select all  Expand view

HB_METHOD( THDOSTATEMENT_BINDPARAM )
{
    PHDOSTMT stmt = hb_getStmt();

    if( stmt )
    {
        STMT_BINDPARAM( stmt, hb_param( 1, HB_IT_NUMERIC | HB_IT_STRING ),
                        hb_param( 2, HB_IT_BYREF ), hb_parni( 3 ), hb_parni( 4 ) );
    }
}

 


Y aquí está el código de la función bindParam()

Code: Select all  Expand view

static HB_ERRCODE bindParam( PHDOSTMT stmt, PHB_ITEM pParam, PHB_ITEM pVariable, HB_USHORT uiType, HB_SIZE nLen )
{
    if( pParam && pVariable )
    {
        /* Si no existe la lista de parametros la creamos y la inicializamos */
        if( !stmt->pListParam )
        {
            stmt->pListParam = ( PHDO_LISTBIND ) hb_xalloc( sizeof( HDO_LISTBIND ) );

            if( stmt->pListParam )
            {
                stmt->pListParam->uiCount = 0;
                stmt->pListParam->pListBind = NULL;
            }
            else
            {
                hdo_throwException( stmt->hdo, HDO_NOTMEMPAR, NULL );
                return HB_FAILURE;
            }
        }

        if( stmt->pListParam )
        {
            PHDO_BIND pBind = ( PHDO_BIND ) hb_xalloc( sizeof( HDO_BIND ) );

            if( pBind )
            {
                HB_UINT i = stmt->pListParam->uiCount++;

                stmt->pListParam->pListBind = ( PHDO_BIND * ) hb_xrealloc( stmt->pListParam->pListBind,
                                          sizeof( PHDO_BIND ) * stmt->pListParam->uiCount );
                pBind->pId = hb_itemNew( pParam );
                pBind->pVariable = pVariable;
                pBind->uiType = uiType ? uiType : HB_ITEM_TYPE( pVariable );
                pBind->nMaxLen = nLen;

                *( stmt->pListParam->pListBind + i ) = pBind;

                return HB_SUCCESS;
            }
            else
            {
                hdo_throwException( stmt->hdo, HDO_NOTMEMPAR, NULL );
                return HB_FAILURE;
            }
        }
    }

    hdo_throwException( stmt->hdo, !pVariable ? HDO_NOTREFER : HDO_NOTINTORSTR, NULL );
    return HB_FAILURE;
}
 


A ver si descubrimos porqué... :D

Re: Para Antonio... posible bug en Harbour

PostPosted: Tue Aug 16, 2016 6:37 am
by Antonio Linares
Si almacenas una variable a bajo nivel, tienes que bloquearla para que el recolector de basura no la destruya.

Eso explicaría porque las static funcionan y no las locales.

Re: Para Antonio... posible bug en Harbour

PostPosted: Tue Aug 16, 2016 9:34 am
by Antonio Linares
Prueba con:

pBind->pVariable = hb_gcLock( pVariable );

para liberar la variable:

hb_gcUnlock( pBind->pVariable );

Re: Para Antonio... posible bug en Harbour

PostPosted: Tue Aug 16, 2016 12:29 pm
by xmanuel
:roll: me temo que de eso no es ya lo he probado.
Te recuerdo que si en vez de tomar el valor del GET se lo asigno directamente SÍ funciona.
Además pVariable es un PHB_ITEM pasado por referencia con lo que se supone que el ITEMAPI lo habrá hecho automáticamente.

Ya que estás Antonio me podrías decir para qué vale y cuándo se debe usar la función "hb_itemUnRef()" :D

Muchas gracias por tu tiempo :oops:

Re: Para Antonio... posible bug en Harbour

PostPosted: Tue Aug 16, 2016 3:47 pm
by Antonio Linares
Manu,

> Te recuerdo que si en vez de tomar el valor del GET se lo asigno directamente SÍ funciona.

Puedes proporcionar un ejemplo auto contenido que no use ninguna librería externa y
que reproduzca el problema ?

> Además pVariable es un PHB_ITEM pasado por referencia con lo que se supone que el ITEMAPI lo habrá hecho automáticamente.

El que las locales fallen es un caso típìco de que la local ha sido destruida. El que se pase por referencia
no creo que haga que la variable se bloquee. Una vez sales de una función, las locales se destruyen.

> Ya que estás Antonio me podrías decir para qué vale y cuándo se debe usar la función "hb_itemUnRef()"

/* De-references item passed by the reference */

PHB_ITEM hb_itemUnRef( PHB_ITEM pItem )

Re: Para Antonio... posible bug en Harbour

PostPosted: Tue Aug 16, 2016 8:43 pm
by xmanuel
Antonio antes de nada volverte a dar las gracias por tu tiempo...

Aquí tienes un ejemplo simplon
Parte PRG:

Code: Select all  Expand view


 procedure main()
 
    local getlist := {}
    local parametro := 0 // Solo funciona si se asigna directamente
    //static parametro := 0  // Asi funciona siempre
    local hSt := creaSt()
   
    bindParam( hSt, @parametro )
   
    cls
   
    // Desmarca la que preceda entre los dos casos:
   
    // Caso (1) Asignacion directa
    // parametro := 100  // Asignado directamente funciona siempre

    // Caso (2) Solo funciona si se declara la variable "parametro" como static
    @ 05, 10 SAY "Introduce el parametro:" GET parametro PICTURE "@K9"
    READ
   
    execute( hSt )
   
    Inkey( 100 )
   
return
   
 


Parte de C
Code: Select all  Expand view


#include "item.api"
#include <windows.h>

typedef struct miStructura
{
    HB_USHORT uiCount;
    PHB_ITEM  pVariable;               
} MIESTR, *PMIESTR;

HB_FUNC( MYMSG )
{
   MessageBox( NULL, hb_parc( 1 ), "Atencion",
                         MB_OK | MB_ICONINFORMATION | MB_SYSTEMMODAL );
}


/*
 * Crea una estructura vacia
 */

 
HB_FUNC( CREAST )
{
    PMIESTR lc = ( PMIESTR ) hb_xalloc( sizeof( MIESTR ) );
   
    if( lc )
    {
        lc->uiCount = 0;
       
        hb_retptr( lc );
    }
    else
    {
        hb_ret();
        MessageBox( NULL, "No se ha creado la estructura", "Atencion", MB_OK | MB_ICONINFORMATION | MB_SYSTEMMODAL );
    }
}

HB_FUNC( BINDPARAM )
{
    PMIESTR lc = ( PMIESTR ) hb_parptr( 1 );
   
    if( lc )
    {
        PHB_ITEM  pVariable = hb_param( 2, HB_IT_BYREF );
       
        if( pVariable )
        {
            lc->pVariable = pVariable;
            lc->uiCount++;
        }
        else
        {
            MessageBox( NULL, "Parametro 2 no se paso por referencia", "Atencion", MB_OK | MB_ICONINFORMATION | MB_SYSTEMMODAL );
        }
    }
    else
    {
        MessageBox( NULL, "Parametro 1 incorrecto", "Atencion", MB_OK | MB_ICONINFORMATION | MB_SYSTEMMODAL );
    }
}

HB_FUNC( EXECUTE )
{
    PMIESTR lc = ( PMIESTR ) hb_parptr( 1 );
   
    if( lc )
    {
       char szBuffer[3 ];

        wsprintf( szBuffer, "%d", hb_itemGetNI( lc->pVariable ) );

        MessageBox( NULL, szBuffer, "Atencion", MB_OK | MB_ICONINFORMATION | MB_SYSTEMMODAL );
    }
    else
    {
        MessageBox( NULL, "Parametro 1 incorrecto", "Atencion", MB_OK | MB_ICONINFORMATION | MB_SYSTEMMODAL );
    }
}

 


Si la variable "parametro" se declara como local solo funciona si se asigna directamente. Prueba a comentar la parte del GET "caso 2"
Si la variable "parametro" se declara como static funciona con el "caso 1" y con la parte del GET "caso 2"

A ver si puedes ver el problemilla y como solucionarlo usando el GET y sin "trucos" :roll:

Re: Para Antonio... posible bug en Harbour

PostPosted: Thu Aug 18, 2016 4:54 pm
by Antonio Linares
A mi me aparece siempre un cero mostrado desde tu función Execute()

No entiendo bien lo que quieres hacer

Re: Para Antonio... posible bug en Harbour

PostPosted: Thu Aug 18, 2016 8:22 pm
by xmanuel
Lo que tendría que salir es el valor introducido en el get, pero desde C, lo que pretendo es que cuando introduzca un valor desde PRG sin necesidad de pasarlo como un parámetro en una función en C ya sea visible. Y ya te digo, funciona siempre que la variable en cuestión no pase por un GET, por eso creo que es un fallo del getSystem de Harbour que no respeta la referencia original...

Mira este trozo de codigo:
Code: Select all  Expand view

procedure main()
 
    local getlist := {}
    local parametro := 0 // Solo funciona si se asigna directamente <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    //static parametro := 0  // Asi funciona siempre <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    local hSt := creaSt()
 

comenta el local y descomenta el static:
Code: Select all  Expand view

 procedure main()
 
    local getlist := {}
    //local parametro := 0 // Solo funciona si se asigna directamente
    static parametro := 0  // Asi funciona siempre
    local hSt := creaSt()
 


y prueba ahora.

ATENCION OTRA COSA:
Además prueba a poner lo que te indico aunque la variable parametro sea local si funciona

Code: Select all  Expand view

 procedure main()
 
    local getlist := {}
    local parametro := 0 // Solo funciona si se asigna directamente
    //static parametro := 0  // Asi funciona siempre
    local hSt := creaSt()

    _GET_( parametro , "parametro " )  // <<<<<< Si pongo esto también funciona, OJO por encima de la función bindParam, por eso pienso que se pierde la referencia cuando pasa por el get

    bindParam( hSt, @parametro )
   
    cls
   
    // Desmarca la que preceda entre los dos casos:
   
    // Caso (1) Asignacion directa
    // parametro := 100  // Asignado directamente funciona siempre

    // Caso (2) Solo funciona si se declara la variable "parametro" como static
    @ 05, 10 SAY "Introduce el parametro:" GET parametro PICTURE "@K9"
    READ
   
    execute( hSt )
   
    Inkey( 100 )
   
return
 

Re: Para Antonio... posible bug en Harbour

PostPosted: Fri Aug 19, 2016 3:58 pm
by Antonio Linares
Manuel,

Lo suyo es que lo comentes en la lista de usuarios de Harbour

Con que pongas un ejemplo es suficiente

Re: Para Antonio... posible bug en Harbour

PostPosted: Mon Aug 22, 2016 6:12 pm
by xmanuel
OK, ya lo he puesto.
Aún así s puedes miralo a ver si conseguimos algo :?