What happens when settimer replaces a timer?

Guía Completa para Usar SetTimer en Windows

06/10/2025

Valoración: 4.8 (16625 votos)

En el desarrollo de aplicaciones para Windows, a menudo nos encontramos con la necesidad de ejecutar una porción de código de manera periódica. Ya sea para actualizar la interfaz de usuario, realizar comprobaciones en segundo plano o crear animaciones, los temporizadores son una herramienta fundamental. La API de Win32 nos proporciona una función robusta y versátil para esta tarea: SetTimer. A través de esta guía, exploraremos en profundidad cómo funciona, sus diferentes modos de uso y cómo gestionarla correctamente para crear aplicaciones eficientes y estables.

What is the difference between settimer and killtimer?
SetTimer () is the Win32 function to register a timer event and KillTimer () can be used to stop that timer. Application written in MFC & C++ can use CWnd::SetTimer () and CWnd::KillTimer () member functions of CWnd class. SetTimer () API can be called with proper argument to set a timer routine with defined time interval.
Índice de Contenido

¿Qué es la API SetTimer?

La función SetTimer es una API del sistema operativo Windows que permite a un desarrollador crear un temporizador que genera eventos a intervalos regulares. Una vez que se inicia un temporizador, el sistema operativo se encarga de notificar a nuestra aplicación cada vez que transcurre el intervalo de tiempo especificado. Esta notificación puede llegar en forma de un mensaje de Windows o mediante la llamada a una función específica que definamos. Esta flexibilidad la convierte en una herramienta indispensable en la caja de herramientas de cualquier programador de Win32.

La firma (o prototipo) de esta función es la siguiente:

UINT_PTR SetTimer( HWND hWnd, UINT_PTR nIDEvent, UINT uElapse, TIMERPROC lpTimerFunc );

Para utilizarla correctamente, es crucial entender cada uno de sus parámetros:

  • hWnd: Es un manejador (handle) a la ventana que estará asociada con el temporizador. Todos los eventos del temporizador se dirigirán a esta ventana. Si este parámetro es NULL, el temporizador no estará asociado a ninguna ventana, lo cual tiene implicaciones en cómo se manejan los otros parámetros.
  • nIDEvent: Un valor entero distinto de cero que sirve como identificador único para el temporizador. Si se crea un temporizador asociado a una ventana (hWnd no es NULL), este ID debe ser único para esa ventana. Si hWnd es NULL, este parámetro es ignorado.
  • uElapse: Es el corazón del temporizador. Especifica el intervalo de tiempo, en milisegundos, entre cada evento del temporizador. Por ejemplo, un valor de 1000 hará que el evento se dispare cada segundo. Es importante notar que Windows tiene límites; si el valor es menor que USER_TIMER_MINIMUM (10 ms), se ajustará a este mínimo. Si es mayor que USER_TIMER_MAXIMUM, se ajustará al máximo.
  • lpTimerFunc: Este parámetro opcional determina cómo nuestra aplicación será notificada. Si es NULL, el sistema enviará un mensaje WM_TIMER a la cola de mensajes de la ventana especificada en hWnd. Si, por el contrario, proporcionamos un puntero a una función (una función de tipo TIMERPROC), el sistema llamará a esa función directamente cada vez que el temporizador se dispare.

Si la función SetTimer tiene éxito, devuelve un valor entero que identifica al nuevo temporizador. Si falla, devuelve cero. Este valor de retorno es importante, especialmente cuando necesitamos destruir el temporizador más tarde.

Dos Caminos para un Mismo Fin: WM_TIMER vs. TimerProc

Como mencionamos, SetTimer nos ofrece dos mecanismos distintos para manejar los eventos del temporizador. La elección entre uno y otro dependerá de la arquitectura de nuestra aplicación y de la tarea específica que deba realizar el temporizador.

How does settimer work?
SetTimer creates a timer that triggers an event after so many milliseconds have elapsed. The timer continues triggering events between intervals until it is removed using KillTimer. The timer can be configured to either send a WM_TIMER message to the owning window or call a callback function whenever the time-out period elapsed.

Método 1: El Mensaje WM_TIMER

Este es el enfoque más común, especialmente en aplicaciones basadas en una interfaz gráfica tradicional. Al dejar el parámetro lpTimerFunc como NULL, le indicamos al sistema que, cada vez que el temporizador se active, debe poner un mensaje WM_TIMER en la cola de mensajes de nuestra aplicación. Luego, en el procedimiento de ventana (WndProc), podemos capturar este mensaje y ejecutar el código correspondiente.

Ventajas:

  • Integración natural con el bucle de mensajes de una aplicación GUI.
  • El código del temporizador se mantiene centralizado dentro del WndProc.
  • Simple de implementar para tareas relacionadas directamente con la actualización de una ventana.

Método 2: La Función Callback TimerProc

Al proporcionar una función de devolución de llamada (callback), el sistema llamará a esta función directamente cada vez que el temporizador se dispare. Esta función debe tener una firma específica, conocida como TIMERPROC.

Ventajas:

  • El código está más encapsulado y separado de la lógica del WndProc, lo que puede mejorar la legibilidad.
  • No depende directamente de la cola de mensajes, aunque el hilo que creó el temporizador debe seguir despachando mensajes para que el callback sea invocado.
  • Útil para tareas que no están intrínsecamente ligadas a una ventana específica.

Tabla Comparativa

CaracterísticaWM_TIMERCallback TimerProc
ImplementaciónlpTimerFunc es NULL. Se maneja con un case WM_TIMER: en el WndProc.Se proporciona un puntero a una función con la firma VOID CALLBACK TimerProc(...).
Dependencia de VentanaRequiere un hWnd válido, ya que el mensaje se envía a esa ventana.Puede funcionar sin un hWnd asociado.
Organización del CódigoLa lógica reside dentro del procedimiento de ventana, potencialmente mezclada con otros manejadores de mensajes.La lógica está contenida en una función separada, promoviendo un código más limpio.
Caso de Uso IdealActualizar controles de una ventana, animaciones simples, etc.Tareas periódicas en segundo plano que no modifican directamente la UI.

El Ciclo de Vida de un Temporizador

Un temporizador no solo se crea, sino que también se puede modificar y, fundamentalmente, se debe destruir para liberar recursos del sistema.

What is settimer API?
The SetTimer () API function creates a timer and sets its parameters. Once a timer is created, it will generate timer events until the timer is terminated or the application exits. The prototype of this function is hWnd – a handle to the window to be associated with the timer.. iD – specifies an id value associated with the timer.

Creación y Modificación

La creación se realiza con la primera llamada a SetTimer. Una característica interesante es que SetTimer también sirve para modificar un temporizador existente. Si se llama a SetTimer con el mismo hWnd y nIDEvent de un temporizador ya activo, el sistema no crea uno nuevo. En su lugar, reemplaza el temporizador anterior. El temporizador se reinicia, lo que significa que el nuevo intervalo de tiempo (uElapse) comenzará a contar desde ese momento, ignorando el valor anterior.

Destrucción: La Función KillTimer

Cuando un temporizador ya no es necesario, es crucial destruirlo utilizando la función KillTimer. No hacerlo puede llevar a fugas de recursos y a comportamientos inesperados, especialmente si la ventana asociada se destruye pero el temporizador sigue activo.

La firma de KillTimer es mucho más simple:

BOOL KillTimer( HWND hWnd, UINT_PTR uIDEvent );
  • hWnd: El manejador de la ventana asociada al temporizador que se quiere destruir. Debe ser el mismo que se usó al crearlo.
  • uIDEvent: El identificador del temporizador que se quiere destruir.

La función devuelve un valor distinto de cero si tiene éxito y cero si falla. Un lugar común para llamar a KillTimer es en el manejador del mensaje WM_DESTROY, asegurando que todos los temporizadores asociados a una ventana se limpien cuando esta se cierra.

How to create a timer using settimer?

Ejemplo Práctico en C++

A continuación, se muestra un programa de ejemplo que crea una ventana y utiliza un temporizador para actualizar su título con la hora actual cada segundo. El código está preparado para usar tanto el método WM_TIMER como el callback TimerProc, controlado por la macro USE_TIMER_PROC.

#include <windows.h> #include <time.h> // Descomenta la siguiente línea para usar el método de callback // #define USE_TIMER_PROC #define MY_TIMER_ID 100 #ifdef USE_TIMER_PROC // Función callback para el temporizador VOID CALLBACK MyTimerProc(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { time_t rawtime; struct tm* timeinfo; char buffer[80]; if (idEvent == MY_TIMER_ID) { time(&rawtime); timeinfo = localtime(&rawtime); strftime(buffer, 80, "Hora actual: %I:%M:%S %p", timeinfo); SetWindowText(hWnd, buffer); } } #endif // Procedimiento de ventana principal LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASS wc = {0}; wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wc.lpszClassName = "TimerDemoClass"; RegisterClass(&wc); HWND hWnd = CreateWindow("TimerDemoClass", "Demo de SetTimer/KillTimer", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 200, NULL, NULL, hInstance, NULL); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // Bucle de mensajes MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: // Iniciar el temporizador al crear la ventana #ifdef USE_TIMER_PROC SetTimer(hWnd, MY_TIMER_ID, 1000, MyTimerProc); #else SetTimer(hWnd, MY_TIMER_ID, 1000, NULL); #endif break; #ifndef USE_TIMER_PROC case WM_TIMER: if (wParam == MY_TIMER_ID) { time_t rawtime; struct tm* timeinfo; char buffer[80]; time(&rawtime); timeinfo = localtime(&rawtime); strftime(buffer, 80, "Hora actual: %I:%M:%S %p", timeinfo); SetWindowText(hWnd, buffer); } break; #endif case WM_DESTROY: // Es crucial destruir el temporizador al cerrar la ventana KillTimer(hWnd, MY_TIMER_ID); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } 

Preguntas Frecuentes (FAQ)

¿Qué pasa si llamo a `SetTimer` para un temporizador que ya existe?
El temporizador existente es reemplazado por el nuevo. El contador de tiempo se reinicia con el nuevo valor de `uElapse`. Esto es útil para cambiar el intervalo de un temporizador dinámicamente.
¿Puedo tener múltiples temporizadores en una misma ventana?
Sí. Puedes crear varios temporizadores para una misma ventana, siempre y cuando utilices un `nIDEvent` (identificador) diferente para cada uno. Esto te permite gestionar diferentes eventos periódicos con distintas frecuencias.
¿Es `SetTimer` preciso al milisegundo?
No. La precisión de `SetTimer` no está garantizada. El valor `uElapse` es un tiempo de espera mínimo. El sistema enviará la notificación tan pronto como sea posible después de que transcurra el intervalo, pero puede haber retrasos debido a la carga del sistema u otras tareas de mayor prioridad. No debe usarse para aplicaciones de tiempo real que requieran alta precisión.
¿Es obligatorio destruir los temporizadores con `KillTimer`?
Absolutamente. No destruir un temporizador es una fuente común de errores y fugas de recursos. Siempre debes llamar a `KillTimer` cuando el temporizador ya no sea necesario, típicamente en el manejador de `WM_DESTROY` para temporizadores asociados a ventanas.

Conclusión

La función SetTimer, junto con su contraparte KillTimer, proporciona un mecanismo potente y flexible para la gestión de eventos periódicos en aplicaciones Windows. Comprender sus dos modos de operación —mediante mensajes WM_TIMER o funciones callback TimerProc— nos permite elegir la estrategia más adecuada para cada situación. Al gestionar correctamente el ciclo de vida de los temporizadores, aseguramos que nuestras aplicaciones sean robustas, eficientes y libres de fugas de recursos, dominando así uno de los aspectos más importantes de la programación asíncrona en el entorno Win32.

Si quieres conocer otros artículos parecidos a Guía Completa para Usar SetTimer en Windows puedes visitar la categoría Juegos.

Subir