Estimado FiveWiDi:
Buena pregunta. Lo he verificado contra el código actual de FWH (clase TTimer) y contra el comportamiento documentado de la API de Windows, y la respuesta corta es: no se crean 'n' timers. Vamos por partes.
En FWH cada TTimer recibe un identificador único al construirse (un contador estático que empieza en 1):
Code: Select all | Expand
METHOD New( nInterval, bAction, oWnd ) CLASS TTimer
...
::nId = nId++
...
Y Activate() llama a la API con ese mismo identificador:
Code: Select all | Expand
METHOD Activate() CLASS TTimer
::nId = SetTimer( ::hWndOwner, ::nId, ::nInterval, 0 )
::lActive = .t.
return nil
La clave está en cómo funciona SetTimer() de Windows: cuando se le pasa un HWND (no NULL) y un nIDEvent que ya existe para esa ventana, no crea un timer nuevo: reemplaza el existente, aplicando el nuevo intervalo y reiniciando la cuenta atrás. Como ::nId se conserva entre llamadas, tus respuestas concretas son:
¿'n' timers al llamar SetTimer() 'n' veces? No. Siempre es el mismo timer (mismo hWndOwner + mismo nId).
¿Se sobrescribe el existente? Sí: se redefine con el intervalo que tenga ::nInterval en ese momento.
¿Se puede modificar su intervalo? Sí, precisamente así: asignas ::nInterval y llamas de nuevo a Activate(). Eso sí, la cuenta atrás se reinicia desde cero.
¿Se omite la definición si ya existe? No se omite: se reemplaza.
Sobre tu propuesta:
Code: Select all | Expand
METHOD Activate() CLASS TTimer
If .Not. ::lActive
::nId = SetTimer( ::hWndOwner, ::nId, ::nInterval, 0 )
::lActive = .t.
EndIf
return nil
Es correcta y no hace daño, pero no es necesaria para evitar duplicados (con el mismo nId no puede haber duplicados). Su efecto real sería otro: impedir que un Activate() repetido reinicie la cuenta atrás del timer. Si en tu aplicación llamas a Activate() desde varios sitios y no quieres ese reinicio, tu guardia es una buena idea; si lo llamas una sola vez, no cambia nada.
Un caso distinto que sí conviene tener presente: si cada TTimer tuviera su propia ventana (hWndOwner distinto), los identificadores podrían repetirse entre ventanas sin conflicto, porque la pareja (hWnd, nId) es lo que identifica al timer. Aquí no es el caso porque el contador es global, así que no hay colisiones.
Y lo importante al final del ciclo de vida: DeActivate() y End() ya liberan el timer con KillTimer( ::hWndOwner, ::nId ), así que el timer muere correctamente con el objeto.
Un saludo,
FiveTech AI