Page 1 of 2

XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Sat Jan 17, 2026 5:14 pm
by José

Hola a todos

Después de mucho tiempo de nuevo acá, en otro intento por modernizar mi software.

Por favor si alguien me puede ayudar con esto:

En XBrowse (muy bueno!!!) incluyo columnas que muestran pequeños bitmaps, usando AddResource, y cuando esas columnas están visibles en el navegador, cada desplazamiento, de cualquier forma, aumenta el consumo de memoria (leído con administrador de tareas de Windows), de modo que si desplazo hacia abajo o hacia arriba el contador sube y sube.

Por otro lado, sin tocar nada, cuando oculto las columnas, el contador de consumo de memoria se congela, no sube sin importar cuanto navegue. Vuelvo a activar las columnas, y el contador vuelve a subir al navegar. Y es similar con 100, 1.000 o 20.000 registros.

Este es un código fuente de ejemplo, que funciona y presenta el problema indicado:

Code: Select all | Expand

aCabe := { '', 'Aut', 'Seg' }
aData := { 'CLAVE', 'Au', 'Se' }
aPict := { '', '', '' }
aSize := { 150, 30, 30 }

cQry :=  'Select CLAVE, CRAYON1 As Au, CRAYON2 As Se From MOVMAE Limit 2000'
oQry:= oMyCon:Rowset(cQry,.f.)

Define Dialog oDlg Resource 'BROXSDVD' Font oFontGral Title 'Prueba'

Redefine XBrowse oBrw ID 100 Of oDlg Update DataSource oQry Columns aData Headers aCabe ColSizes aSize Pictures aPict 

add column to oBrw at 1    // inserté una columna para ejemplo, pero podría ser una existente...
oBrw:aCols[1]:AddResource( { 'COMUN_SELECC_NO', 'COMUN_SELECC_SI' } )
oBrw:aCols[1]:cHeader         := '>'
oBrw:aCols[1]:cToolTip        := 'Muestra'
oBrw:aCols[1]:nHeadStrAlign   := 2      // (centrado)
oBrw:aCols[1]:nWidth          := 30
oBrw:aCols[1]:cSortOrder      := nil
oBrw:aCols[1]:bLClickHeader   := { || '' }
oBrw:aCols[1]:lBmpStretch     := .f.
oBrw:aCols[1]:lBmpTransparent := .t.
oBrw:aCols[1]:bBmpData        := { || if( ascan( oBrw:aSelected, oBrw:BookMark ) > 0, 1, 2 ) }
oBrw:aCols[1]:bStrData        := { || '' }
oBrw:aCols[1]:bEditValue      := { || '' }
oBrw:aCols[1]:nDataBmpAlign   := 2
oBrw:aCols[1]:cEditPicture    := Nil
oBrw:aCols[1]:blDClickData    := { || MiMsgInfo( 'probando' ) }
oBrw:aCols[1]:bClrStd       := { || { CLR_BRWHT, CLR_BRWHB } }

Activate Dialog oDlg

RETURN Nil

He probado mil cosas y no logro resolverlo.

Además, al salir del navegador, aunque haga release, end(), y asigne nil, aún así la cantidad de memoria consumida hasta el momento permanece (no baja, no libera).

Uso HB MSVSC + FWH 24.04 + MySQL/MariaDB/DBFCDX (64 bits)

Muchas gracias, que tengan un excelente fin de semana.


Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Mon Jan 19, 2026 5:16 am
by Antonio Linares

Estimado José,

Lo estamos revisando.

Gracias por tu feedback :idea:


Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Mon Jan 19, 2026 6:01 am
by Antonio Linares

Estimado José,

Al comienzo de tu app llama a:

SetResDebug( .T. )

Añade una opción a tu menú principal desde donde llames a este código:

MENUITEM "Consumo" ACTION ( FErase( "checkres.txt" ), CheckRes(), WinExec( "notepad checkres.txt" ) )

Sin salir de tu app, prueba el consumo de recursos y copia el log que te aparezca en pantalla y dáselo
a la IA para que lo analice.

Asi es como estamos intentando localizar el consumo que reportas. Gracias!


Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Mon Jan 19, 2026 6:02 am
by Antonio Linares

He analizado el log de recursos (checkres.txt) que has proporcionado. Este log es la "pistola humeante" (prueba definitiva) de que tienes objetos GDI que no se están destruyendo al cerrar la ventana o finalizar el proceso.

Aquí está el desglose de dónde viene la pérdida y los duplicados:

1. El problema del Pintado (Confirmación de tu sospecha)

Hay una entrada crítica al final del log que confirma que el repintado (scroll o refresh) está dejando basura:

01/19/26 06:55:49: ... BRUSH, 2131760879, TXBROWSE:PAINT(2350)->...

  • Análisis: El método Paint (línea 2350 en tu versión de xbrowse.prg) crea un BRUSH (Pincel) para pintar el fondo o un área específica, y nunca lo destruye.
  • Impacto: Cada vez que el Paint se ejecuta (y se ejecuta cientos de veces al hacer scroll), si esa línea condicional se cumple, se crea un nuevo pincel. Si no hay un DeleteObject() correspondiente para ese pincel específico, la memoria se llena rápidamente.
2. Duplicados en la creación (TXBROWSE:NEW)

Hay tres Bitmaps que se crean al instanciar el Browse (NEW) y quedan vivos. Fíjate en estas líneas:

  1. BMP, 50667437, TXBROWSE:NEW(853)...
  2. BMP, 251994086, TXBROWSE:NEW(854)...
  3. BMP, -217768098, TXBROWSE:NEW(854)...
  • Identificación: Las líneas 853 y 854 del xbrowse.prg original suelen corresponder a la carga de los bitmaps de ordenación (flechas arriba/abajo) en la variable ::aSortBmp.
  • ¿Por qué hay duplicados?
  • La línea 854 aparece dos veces con handles diferentes (251994086 y -217768098).
  • Esto indica que, o bien se han creado dos xBrowses y ninguno se ha destruido, o bien el código de inicialización ha cargado ese recurso dos veces para el mismo browse.
  • Causa de la fuga: Estos bitmaps se guardan en variables internas o en aBitmaps. Si el log los muestra al final, significa que el método Destroy() del XBrowse no se ejecutó o no pudo limpiar estos handles específicos.
3. Fuga en Columnas (TXBRWCOLUMN)

BMP, 788861018, TXBRWCOLUMN:ADJUST(13680)...

  • Durante el ajuste de la columna, se creó un Bitmap (posiblemente para un Checkbox o un botón de filtro) que quedó huérfano.
Conclusión y Solución

El log indica que el objeto TXBrowse (y sus columnas) no está completando su ciclo de destrucción.

  1. Fuga en Paint (Urgente): Revisa la línea 2350 de tu xbrowse.prg. Debería haber un código similar a DEFINE BRUSH ... o CreateSolidBrush. Debes asegurarte de que ese pincel se libere con DeleteObject() o RELEASE BRUSH antes de que termine el método Paint.
  2. Fallo en End/Destroy: Los bitmaps de NEW (853/854) son nativos de la clase. Si aparecen aquí, es porque la ventana contenedora (el TMDIFRAME o TMDICHILD) no envió correctamente el mensaje de destrucción al control XBrowse, o el método Destroy del XBrowse falló antes de llegar a la limpieza de bitmaps.

Prueba recomendada:
Asegúrate de que en tu ventana principal o dialogo, el objeto browse se asigne a una variable local o DATA y sea parte de la lista de controles de la ventana (oWnd:aControls). El mecanismo de FiveWin limpia automáticamente los recursos solo si el control está correctamente enlazado a la ventana que se cierra.


Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Mon Jan 19, 2026 6:14 am
by Antonio Linares

Parece que hay una pérdida de recursos que no está monitorizando FWH

Seguimos investigándolo


Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Mon Jan 19, 2026 1:06 pm
by José

Hola Antonio

Muchas gracias, haré las pruebas que me indicas.

Quedo atento a cualquier información.

Saludos.


Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Thu Jan 22, 2026 1:13 am
by carlos vargas

antonio, en esa linea, en el actual xbrowse, existe esto:

Code: Select all | Expand

      // To enable programmer to change color during runtime
      DeleteObject( ::hBrushRecSel )
      ::hBrushRecSel := CreateColorBrush( ::nRecSelColor )  //aca es la linea 2350

aca se crea un brush, el cual previamente se elimina, pero durante toda la vida de la funcion Paint, no es eliminado.


Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Thu Jan 22, 2026 1:20 am
by carlos vargas

Code: Select all | Expand

...
EXTEND CLASS TXBROWSE     WITH METHOD SetMyBmpSort
...

FUNCTION SetMyBmpSort()
   LOCAL Self := hb_QSelf()
   LOCAL oBmp, hBmp

   IF ::aSortBmp[ 1, 1 ] != 0
      DeleteObject( ::aSortBmp[ 1, 1 ] )
   ENDIF
   IF ::aSortBmp[ 2, 1 ] != 0
      DeleteObject( ::aSortBmp[ 2, 1 ] )
   ENDIF

   ::aSortBmp := {}

   DEFINE BITMAP oBmp NAME "BMS_ARROWDOWN"
   hBmp := oBmp:hBitmap
   AAdd( ::aSortBmp, { hBmp, 0, nBmpWidth( hBmp ), nBmpHeight( hBmp ), NIL, FALSE } )

   DEFINE BITMAP oBmp NAME "BMS_ARROWUP"
   hBmp := oBmp:hBitmap
   AAdd( ::aSortBmp, { hBmp, 0, nBmpWidth( hBmp ), nBmpHeight( hBmp ), NIL, FALSE } )

RETURN NIL

Este código nos muestra la forma correcta de realizar un cambio en los bitmaps de las flechas de ordenación, si el usuario desea cambiar los que usa fwh por defecto y usar los propios cambiando ::aSortBmp, debe tener el cuidado de borrar los anteriores correctamente, como muestra la función que adjunto.


Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Thu Jan 22, 2026 5:38 am
by Antonio Linares
carlos vargas wrote: Thu Jan 22, 2026 1:13 am

antonio, en esa linea, en el actual xbrowse, existe esto:

Code: Select all | Expand

      // To enable programmer to change color during runtime
      DeleteObject( ::hBrushRecSel )
      ::hBrushRecSel := CreateColorBrush( ::nRecSelColor )  //aca es la linea 2350

aca se crea un brush, el cual previamente se elimina, pero durante toda la vida de la funcion Paint, no es eliminado.

Estimado Carlos,

Probé a comentar esas dos líneas y aún así, se mantiene el consumo de recursos. Debe ser algo más pero aún no lo hemos localizado. No queda registrado en el registro de recursos de FWH.


Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Thu Jan 29, 2026 1:52 am
by José

Hola Antonio

¿Hay alguna novedad respecto a esto?

Saludos


Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Thu Jan 29, 2026 9:55 am
by Antonio Linares

Hemos localizado la herramienta idónea para localizar el tipo de objeto GDI que no se está liberando:

GDIView
https://www.nirsoft.net/utils/gdi_handles.html

En concreto la versión de 64 bits:
https://www.nirsoft.net/utils/gdiview-x64.zip


Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Thu Jan 29, 2026 10:55 am
by Antonio Linares

Bug detectado en tgdiplus.prg:

Code: Select all | Expand

METHOD Destroy() CLASS Region

   //  GdiPlusDeletePen( ::hRegion )  incorrecto
   GdiPlusDeleteRegion( ::hRegion ) // correcto

   ::hRegion = nil

return nil

código para GdiPlusDeleteRegion() en gdiplus.cpp:

Code: Select all | Expand

HB_FUNC( GDIPLUSDELETEREGION )
{
   delete ( ( Region * ) hb_parptr( 1 ) );
}

Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Mon Feb 02, 2026 11:56 pm
by Antonio Linares

GDI+ leak solucionado!

Audit gdipfwh.cpp for Memory Leaks Completed the comprehensive audit of
gdipfwh.cpp

. Identified and fixed multiple critical memory leaks where GDI+ objects (Graphics, FontFamily,
Bitmap, Brush) were allocated with new but not deleted.

Applied fixes to 11 functions including GDIP_RINGGRAD, GDIP_DRAWARROW, GDIP_DRAWTEXT, and image handling functions.


Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Tue Feb 03, 2026 12:03 am
by Antonio Linares

José,

Indicame si necesitas las librerias para Borland o MS, 32 ó 64 bits, y te las enviamos :idea: :D


Re: XBrowse con AddResource > Consumo progresivo de Memoria

Posted: Tue Feb 03, 2026 3:40 pm
by José

Estimado Antonio

Hola, que buena noticia que se haya resuelto!!

Yo uso
Harbour MSVSC 64 bits (Harbour 3.2.0dev)
FWH 24.04, 64 bits (04/2024)
Pelles C 64 bits, para Windows, v 9.00.9, 2018
MySQL/MariaDB/DBFCDX

Así que entiendo que serían las librerías para MS, 64 bits.

Nota. Aprovecho de preguntar si, con la configuración que uso, podría actualizar VSCode 2022 a VSCode 2026 (enero 2026) sin romper algo de la configuración o del proyecto.

Gracias por todo, quedo atento.