Si no sabes que es un API de Windows o como funcionan las ventanas del sistema operativo te recomiendo que primero leas el artículo Cómo funciona el sistema de ventanas en Windows.
La gran diferencia entre esta forma de crear protectores de pantalla y la mostrada en el otro artículo es que al utilizar el API de Windows no tenemos que preocuparnos por controlar los parámetros de ingreso para detectar si es o no un protector de pantalla y tampoco tenemos que preocuparnos de ocultar los bordes de nuestras ventanas ni nada de eso.
Además otra diferencia importante es que al no contar con un formulario, el dibujo tenemos que hacerlo utilizando los métodos del API en lugar de los utilizados en el Graphics o Canvas, esto no permitiría a su vez crear gráficos tridimensionales utilizando DirectX o OpenGL.
Objetivo
El objetivo es hacer un protector de pantalla que muestre un cuadrado rojo rebotando por la pantalla.
Creando el proyecto
Debes crear un proyecto vacío de tipo Win32. Cuando crees un proyecto vacío deberás ver que solo se ha creado el proyecto pero no hay ningún archivo en él.
Ahora lo que tienes que hacer es agregar un nuevo archivo de tipo cpp a tu proyecto. Este archivo será el que contendrá el código de nuestro programa. El archivo cpp estará en blanco pero te doy la estructura principal de cualquier protector de pantalla que utilice el API de Windows.
#include <windows.h>
#include <scrnsave.h>
#ifdef UNICODE
#pragma comment(lib, "ScrnSavw.lib")
#else
#pragma comment(lib, "ScrnSave.lib")
#endif
#pragma comment(lib, "comctl32.lib")
LONG WINAPI ScreenSaverProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)
{
// Handles screen saver messages
switch(message)
{
case WM_CREATE:
return 0;
case WM_ERASEBKGND:
return 0;
case WM_TIMER:
return 0;
case WM_DESTROY:
return 0;
}
return DefScreenSaverProc(hwnd,message,wparam,lparam);
}
BOOL WINAPI ScreenSaverConfigureDialog(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)
{
return true;
}
BOOL WINAPI RegisterDialogClasses(HANDLE hmodule)
{
return true;
}
El código que te he presentado es lo único que debe estar en el archivo cpp de tu proyecto. Como te puedes dar cuenta, en este código no existe una función main, que es el punto de partida para cualquier programa. Esto se debe a que el include que hemos hecho a la librería scrnsave.h ya incluye la función main que responde ante todos los mensajes necesarios para poder procesar nuestro programa como un protector de pantalla. El código que hemos colocado nosotros simplemente complementa al de scrnsave.h para poder darle forma a nuestro protector de pantalla sin tener que preocuparnos por el resto.
Aunque no parezca, este proyecto ya es un protector de pantalla, controla la creación de la ventana donde tenemos que dibujar, controla que se cierre cuando movemos el mouse o presionamos alguna tecla, ocupa toda la pantalla, no muestra bordes etc.
Para que podamos entender un poco mejor el código aquí te va la explicación:
Líneas 1 – 9
En estas líneas incluyo la librería Windows.h para poder utilizar el API, y la librería scrnsave.h para no tener que preocuparme por la gran mayoría de opciones de un protector de pantalla. Entre las líneas 4 y 9 me aseguro de que el Linker conozca las librerías externas y las incluya.
Línea 11 – 29
En estas líneas estoy declarando la función principal del protector de pantalla. Esta función es la que recibe todos los mensajes de Windows para un protector de pantalla. El primer parámetro es el handle de la ventana donde se está mostrando el protector de pantalla, el segundo es el tipo de mensaje que se está recibiendo y los últimos dos son los parámetros asociados a dicho mensaje.
Dentro de esta función estamos haciendo un switch para 4 diferentes mensajes. Cuando se cree nuestro protector de pantalla, cuando necesite borrar el fondo, cuando se ejecute el timer (este mensaje será el que se repite constantemente mientras mi protector de pantalla esté activo) y por último cuando mi protector de pantalla se destruya.
Por último se realiza una invocación a la función DefScreenSaverProc que será la encargada de procesar todos los mensajes que nosotros no procesamos. Es muy importante que esta invocación esté presente para que el protector de pantalla funcione correctamente. Por ejemplo, en este código nosotros no estamos controlando mensajes de movimientos de mouse por lo que si no colocamos esta invocación nunca serán procesados y el protector de pantalla no se cerrará.
Línea 30 – 33
La función que será invocada cuando un protector de pantalla necesite mostrar su ventana de configuración. Como nuestro protector de pantalla no tiene ningún tipo de configuración simplemente devolvemos true, pero aquí puedes colocar todo el código que controla tu ventana de configuración.
Línea 34 – 37
La función que permite registrar clases especiales que controlan cuadros de diálogo en la parte de configuración. Como no la utilizaremos simplemente le ponemos que devuelva true.
Probando el protector de pantalla
Aunque no lo creas, tu protector de pantalla está listo. Obviamente el cuadrado rojo aún no rebota por la pantalla pero todo el control del protector de pantalla ya está funcionando. Vamos a probarlo. Compila tu proyecto para que generes el archivo ejecutable (.exe), cámbiale la extensión .exe por .scr y copia este archivo a C:\Windows\System32 o C:\Windows\System dependiendo de tu versión de Windows. si no sabes en que carpeta debes copiarlo simplemente busca la carpeta que contenga los protectores de pantalla (archivos con extension scr) que vienen por defecto con windows.
Una vez copiado el archivo scr, entra a la configuración para cambiar el protector de pantalla y selecciona el tuyo de la lista que aparece.
Ahora, como tu protector de pantalla aún no dibuja nada, en realidad lo único que vas a ver cuando se ejecute es la pantalla que estaba siendo mostrada justo antes de que tu protector de pantalla se ejecutara. La mejor forma de probar que esté funcionando es abrir un programa que tenga movimiento constante, como por ejemplo el reloj de windows. Ahora puedes ver como este reloj avanza de forma constante hasta el momento en el que tu protector de pantalla se ejecute. Cuando el reloj deja de moverse puedes estar seguro que tu protector de pantalla está corriendo, ahora simplemente mueve el mouse o presiona una tecla y verás que el reloj comienza a avanzar otra vez.
Como puedes ver, el API de Windows se encarga de casi todo lo engorroso!!.
Creando el timer
La gran mayoría de animaciones que realizamos en un programa se deben realizar cuadro por cuadro donde la diferencia entre los cuadros nos da una sensación de movimiento.
Para nuestro protector de pantalla, necesitamos crear un timer que se ejecutará cada cierta unidad de tiempo. Cada vez que se ejecute el timer debemos dibujar un nuevo cuadro y así daremos el efecto de movimiento.
Ahora te muestro el código con el timer ya creado (solo se muestra la función ScreenSaverProc):
LONG WINAPI ScreenSaverProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
static UINT uTimer;
// Handles screen saver messages
switch(message)
{
case WM_CREATE:
uTimer = SetTimer(hwnd, 1, 100, NULL);
return 0;
case WM_ERASEBKGND:
return 0;
case WM_TIMER:
return 0;
case WM_DESTROY:
if (uTimer)
KillTimer(hwnd, uTimer);
return 0;
}
return DefScreenSaverProc(hwnd, message, wparam, lparam);
}
En la línea 3, he declarado una variable estática de tipo UINT (unsigned int) que guardará el handle del timer que vamos a crear. La variable se crea estática para que solamente se inicialice una vez. Esto es necesario ya que esta función será llamada constantemente por nuestro protector de pantalla y no queremos que todas las veces se inicialice el valor del timer.
En la línea 9, correspondiente al mensaje que llega cuando se crea nuestro protector de pantalla, creamos el timer. Este paso siempre se debería crear en este mensaje ya que nos interesa que el timer exista desde que se crea hasta que se destruye nuestro protector de pantalla.
El timer que estoy creando recibe cuatro parámetros. El primero le indica a que ventana está asociado el timer, el segundo el tipo de timer (siempre será 1 para nuestro caso), el intervalo en milisegundos entre cuadro y cuadro (en nuestro caso 100 milisegundos) y el puntero a la función que se ejecutará cada 100 milisegundos. En este caso le mandamos NULL para que en lugar de invocar a una función simplemente nos mande un mensaje de tipo WM_TIMER que será procesado por la línea 15 de nuestro programa.
En las líneas 19 y 20 verifico si es que existe un timer y de ser así lo elimino. Esto limpia mi memoria para que el timer no se quede corriendo después de finalizado mi protector de pantalla.
Esto es todo lo que tenemos que hacer para crear el timer, ahora vamos a ver como dibujar nuestro cuadrado.
Dibujando y moviendo el cuadrado rojo
Para poder mover el cuadrado rojo por la pantalla simulando un rebote, necesitamos utilizar cuatro variables x, y, dx, dy de tipo entero que me permitirán saber la posición del cuadrado y la dirección en la que se mueve en x e y. Vamos a ver el código y luego te lo explico.
LONG WINAPI ScreenSaverProc(HWND hwnd,UINT message,WPARAM wparam,LPARAM lparam)
{
static UINT uTimer;
static int x, y, dx, dy;
static RECT pantalla, cuadrado;
static HDC hdc;
// Handles screen saver messages
switch(message)
{
case WM_CREATE:
uTimer = SetTimer(hwnd, 1, 100, NULL);
x = y = dx = dy = 10;
return 0;
case WM_ERASEBKGND:
return 0;
case WM_TIMER:
// Obtenemos el canvas de dibujo
hdc = GetDC(hwnd);
// Obtenemos las dimensiones de la pantalla
// y las guardamos en la variable pantalla
GetClientRect (hwnd, &pantalla);
// Llenamos la pantalla con color negro
FillRect (hdc, &pantalla, CreateSolidBrush( RGB(0,0,0) ) );
// Configuramos las dimensiones del cuadrado
cuadrado.left = x;
cuadrado.top = y;
cuadrado.right = x + 50;
cuadrado.bottom = y + 50;
// Dibujamos el cuadrado de color rojo
FillRect (hdc, &cuadrado, CreateSolidBrush( RGB(255,0,0) ) );
// Verificamos si debe rebotar y rebotamos si es necesario
if (x + dx <= pantalla.left || x + dx + 50 >= pantalla.right)
dx *= -1;
if (y + dy <= pantalla.top || y + dy + 50 >= pantalla.bottom)
dy *= -1;
// Movemos el cuadrado
x += dx;
y += dy;
// Liberamos el canvas de dibujo
ReleaseDC(hwnd,hdc);
return 0;
case WM_DESTROY:
if (uTimer)
KillTimer(hwnd, uTimer);
return 0;
}
return DefScreenSaverProc(hwnd,message,wparam,lparam);
}
Líneas 4-6
En estas líneas hemos declarado las cuatro variables enteras para controlar el cuadrado y su movimiento, además hemos declarado dos variables de tipo RECT que contendrán las dimensiones de la pantalla y del cuadrado respectivamente. Por último definimos una variable de tipo HDC que contendrá nuestro canvas de dibujo.
Línea 13
En la línea 13 inicializamos nuestras variables que controlan el cuadrado y su movimiento.
Línea 20 – 50
En estas líneas estoy realizando todo el proceso de dibujo. Espero que los comentarios en el código sean lo suficientemente claros. En términos generales lo que hago es obtengo el área de dibujo y sus dimensiones, pinto toda la pantalla de negro, pinto el cuadrado de ancho 50 y color rojo (RGB(255,0,0)) verifico si el cuadrado debe rebotar, muevo el cuadrado y libero el área de dibujo.
Ya está terminado el protector de pantalla, ahora solo tienes que cambiarle la extensión por scr y copiarlo en la carpeta de Windows.
Si te interesa aprender un poco más acerca de las funciones de dibujo que ofrece el API de Windows, te recomiendo que visites http://msdn.microsoft.com/en-us/library/aa923590.aspx

Deja un comentario