INTRODUCCIÓN A LA PROGRAMACIÓN EN WINDOWS

 

1. Introducción

2. Visualizar una ventana de diálogo

3. Modificar la posición del cursor y sus propiedades

4. Creación de ventanas y manipulación de mensajes

 

1. Introducción

Este artículo se centra como su propio nombre indica en una introducción a la programación en windows. Se podrá utilizar cualquier entorno que soporte la programación en 32 bits sobre la plataforma Windows. En los ejemplos se usará el Entorno de Desarrollo Integrado (IDE) Microsoft Visual C++. En este tutorial, mediante la construcción de una serie de mini aplicaciones, se irán introduciendo contenidos de concepto y sobre todo contenidos procedimentales.

¿Cómo se puede comunicar una aplicación o proceso con el sistema operativo Windows?. Para ello existen un conjunto de funciones, procedimientos, tipos de datos, constantes que conforman lo que se denomina la Win32 API ( Application programming interface ).

Para poder usar la Win32 API hay que importar el módulo "windows.h". Ésta a su vez importa otros módulos como por ejemplo "windef.h" donde están declarados prácticamente todos los tipos de datos usados en windows. Si se le echa un vistazo a este último módulo citado se podrán ver las siguientes declaraciones de tipos:

Nombre tipo de dato Tipo de dato equivalente
ULONG unsigned long
PULONG ULONG *
USHORT unsigned short
PUSHORT USHORT *
UCHAR unsigned char
PUCHAR UCHAR *
PSZ char *
DWORD unsigned long
BOOL int
BYTE unsigned char
WORD unsigned short
PWORD WORD near *
LPWORD WORD far *
INT int
WPARAM UINT
LPARAM LONG
LRESULT LONG


 

 

2. Visualizar una ventana de diálogo

Se va a crear una aplicación que realice una llamada a una función de la API. El código fuente puedes descargártelo en el siguiente enlace:

Primeramente habrá que crear un proyecto de Win32 Console Application tal y como viene reflejado en la figura 1.

- Figura 1-

Una vez rellenado los campos con el nombre del proyecto y la ubicación del mismo, pulsar sobre el botón "OK".

- Figura 2 -

En la siguiente ventana (figura 2) seleccionar "An empty project", pues se quiere construir un proyecto vacío.

- Figura 3 -

En la figura 3, aparece una ventana donse se informa que se ha creado un proyecto vacío.

 

- Figura 4 -

Ahora se tendrá que añadir un archivo a nuestro proyecto que inicialmente se encontraba vacío ( ver figura 4).

- Figura 5-

Tal y como se ve reflejado en la figura 5, le pondremos un nombre al archivo. En este ejemplo se le ha puesto el nombre de "principal.c".

Ahora se va a introducir el código de la figura 6 en el archivo"ppal.c".

#include <windows.h>
#include <stdio.h>

void main(void)
{
int respuesta;

respuesta = MessageBox(NULL, "¿Tienes 18 años o más?", "Comprobación de edad del usuario",MB_YESNO);

if (respuesta == IDYES)
printf("Eres mayor de edad\n");
else
printf("Eres menor de edad\n");
}

- Figura 6 -

Ejecutar el código pulsando sobre el icono con el signo de admiración o bien dándole a la combinación de teclas CTRL+F5.

Cómo se puede observar el resultado de ejecución es una ventana de diálogo ( figura 7 ).

- Figura 7 -

Vamos a analizar cada una de las líneas de código del archivo "principal.c".

En este archivo se importan las siguientes librerías:

1) windows.h : donde se encuentra la mayor parte de las funciones de WIN32 API

2) stdio.h : para poder usar la función printf, y todas las funciones de entrada/salida.

A continuación se realiza una llamada a la función MessageBox ( función perteneciente a la WIN32 API ). El prototipo de esta función es el siguiente:

int MessageBox( HWND hWnd, // manejador de la ventana propietaria
LPCTSTR lpText, // Texto que aparecerá dentro de la ventana
LPCTSTR lpCaption, // Texto que aparecerá en el título de la ventana
UINT uType // Estilo de la ventana de diálogo
);

Generalmente en una aplicación existe una jerarquía de ventanas, como en este ejemplo no existe dicha jerarquía, el primer parámetro de la función ( ventana propietaria ) "MessageBox" se le pasará el valor NULL.

El estilo de la ventana de diálogo puede ser cualquiera de los siguientes:

MB_OK: un botón de aceptar, MB_OKCANCEL : un botón de aceptar y otro de cancelar, MB_YESNO : dos botones uno "Sí" y otro con el valor "No", etc....

La función "MessageBox" devuelve un entero que corresponde con una de las siguientes constantes:

IDCANCEL: Se ha seleccionado el botón de cancelar, IDNO: se ha elegido el botón con la etiqueta "NO", IDYES: el botón con la etiqueta "SÍ" ha sido pulsado, IDOK: se seleccionó el botón "Aceptar".

3. Modificar la posición del cursor y sus propiedades

El código fuente puede descargárselo en el siguiente enlace:

Creamos un nuevo proyecto Win32 Console Application siguiendo los pasos del apartado anterior. Obviamente lo único que se va a alterar es el contenido del archivo principal.c.

#include <windows.h>
#include <stdio.h>
#include <conio.h>

void main(void)
{
COORD coordenadas;
SHORT valor;
CONSOLE_CURSOR_INFO info_cursor;
DWORD escrito;
WORD atributo_color;
int i;

printf("\nIntroduzca las siguientes coordenadas(LIMITES X=80,Y=25)");

//Hay que asegurar que las coordenadas no sobrepasan
//los límites de la pantalla
do{
printf("\nValor X: ");
//Se utiliza "%hd" para indicar que el valor a
//capturar es de tipo short
scanf("%hd", &valor);
}while((valor<0) || (valor > 80));

coordenadas.X = valor;

do{
printf("\nValor Y: ");
scanf("%hd", &valor);
}while((valor<0) || (valor > 25));

coordenadas.Y = valor;

//Se indican las coordenadas en las cuales
//aparecerá el cursor

SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coordenadas);

printf("Linea escrita en coordenada X:%hd,Y:%hd\n",
coordenadas.X, coordenadas.Y);


printf("\nPulsa una tecla para ocultar el cursor");
_getch();
//Se oculta el cursor
info_cursor.bVisible = FALSE;
info_cursor.dwSize = 100;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info_cursor);

printf("\nPulsa una tecla para volver a visualizar el cursor");
_getch();

//Vuelve otra vez a ser visible el cursor
info_cursor.bVisible = TRUE;
info_cursor.dwSize = 10;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info_cursor);

printf("\nPulsa una tecla para borrar la pantalla");
_getch();

coordenadas.X = 0;

//Se va a insertar el color. Todos los colores
//tendrán que crearse a partir del Rojo, verde y Azul
//Si mezclamos los tres colores obtenemos el blanco

atributo_color = FOREGROUND_BLUE | FOREGROUND_GREEN
| FOREGROUND_RED ;

for(i = 0; i< 25; i++)
{
coordenadas.Y = i;

FillConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
atributo_color, 80, coordenadas, &escrito);

FillConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE),
' ', 80, coordenadas, &escrito);
}

printf("\nFin de programa\n");

}

- Figura 8 -

En la figura 8 se podrá ver el contenido del archivo "principal.c".

Este programa realiza las siguientes acciones:

A) Situar el cursor en una posición determinada


Para ello se realiza una llamada a la siguiente función:

BOOL SetConsoleCursorPosition(
HANDLE hConsoleOutput, // Manejador de la pantalla de la consola
COORD dwCursorPosition // Nuevas coordenadas
);

En el primer parámetro se le pasa el manejador de la salida estándar. Gracias a la siguiente llamada obtenemos como valor de retorno el manejador de la salida estándar:

GetStdHandle(STD_OUTPUT_HANDLE)

En el segundo argumento hay que pasarle las coordenadas donde se quiere posicionar el cursor:

typedef struct _COORD {
SHORT X; // coordenada horizontal
SHORT Y; // coordenada vertical
} COORD;

B) Ocultar el cursor

Para ocultar el cursor se llama a la función "SetConsoleCursorInfo":

BOOL SetConsoleCursorInfo(
HANDLE hConsoleOutput, // Aquí se le pasará como en el apartado anterior, el manejador de la salida estándar.
CONST CONSOLE_CURSOR_INFO *lpConsoleCursorInfo
// Dirección de la estructura que describe las características del cursor.
);

La estructura del tipo de dato CONSOLE_CURSOR_INFO es la siguiente:

typedef struct _CONSOLE_CURSOR_INFO { // cci
DWORD dwSize;
BOOL bVisible; //Este campo indica si el cursor va a ser visible (TRUE) o no ( FALSE)
} CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;

El campo "dwSize" especifica un número entre 1 y 100, indicando el porcentaje de la celda del carácter que será rellenada por el cursor.

CONSOLE_CURSOR_INFO info_cursor;

info_cursor.bVisible = FALSE;
info_cursor.dwSize = 100;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info_cursor);

C) Volver a mostrar el cursor

Prácticamente igual que en el apartado anterior, lo que ocurre es que el tamaño tomará el valor 10 ( tamaño normal ) y el campo visible el valor TRUE (bVisible).

D) Borrar el contenido de la pantalla.

//El atributo de color se tiene que realizar con la combinación de los colores rojo, verde y azul ( será una variable de tipo "int"):

atributo_color = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED ;

//Primero se rellena la coordena X con el valor 0:

coordenadas.X = 0;

//Se hace un barrido de las 25 líneas de texto

for(i = 0; i< 25; i++)
{

//En cada iteración se modifica el número de línea
coordenadas.Y = i;

//Se indica el color (atributo_color), cuántos caracteres se van a escribir (80), y la posición a partir de la cual se va a escribir ( //coordenadas )

FillConsoleOutputAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
atributo_color, 80, coordenadas, &escrito);

//Se va a escribir el carácter espacio blanco (' '), 80 veces, a partir de las coordenadas especificadas ( coordenadas )

FillConsoleOutputCharacter(GetStdHandle(STD_OUTPUT_HANDLE),
' ', 80, coordenadas, &escrito);
}

4. Creación de ventanas y manipulación de mensajes

Windows utiliza el modelo de programación conducido por eventos. De tal forma, que generalmente, las aplicaciones de Windows se inicializan y esperan a que suceda algo, un "evento". Ese evento puede ser que se presione una tecla, que se realice cualquier acción con el ratón, etc... Pero cómo funciona este mecanismo internamente: cuando ocurre un "evento", Windows envía un mensaje a la aplicación sobre la cual va dirigida el evento, añadiendo para ello el mensaje a la "cola de mensajes" que tiene cada aplicación. Obviamente la aplicación estará constantemente comprobando el contenido de esa cola de mensajes, cuando recibe un mensaje éste será enviado a la "Ventana de Procedimiento" ( window procedure). Esta ventana de procedimiento ejecutará una serie de acciones en respuesta al mensaje recibido.

- Figura 9 -

Cada aplicación tendrá su propia cola de mensajes ( observar figura 9 ). El bucle de mensajes está comprobando constantemente el contenido de la cola de mensajes. Se encargará de obtener el mensaje de la cola y lo enviará al procedimiento de ventana ( windows procedure ). Una vez que este bucle emita el mensaje, Windows ejecutará "automáticamente" el procedimiento de ventana. Con respecto al procedimiento de ventana, aclarar que una aplicación podrá tener varios procedimientos de ventana. En este procedimiento de ventana se escribirá el código que será ejecutado en respuesta a un evento determinado.

A continuación se van a indicar los pasos necesarios para crear una aplicación muy sencilla. El código del siguiente ejemplo puedes descargártelo pulsando en el siguiente enlace:

Lo primero de todo es crear un nuevo proyecto del tipo "Win32 Application Project" ( AVISO: ¡No seleccionar Win32Console Application Project!).Ver figura 10.

- Figura 10 -

Una vez seleccionado el tipo de proyecto, en la siguiente ventana ( figura 11 ), se elige "An empty project".

 

- Figura 11 -

Ahora habrá que añadir al menos un archivo al proyecto con extensión .c ( por ejemplo "principal.c"). Para ello se situa el ratón en la carpeta "Source files" se pulsa el botón derecho del ratón y se hace click en la opción "Add Files to Folder..." ( figura 12 )

 

- Figura 12 -

 

Ahora mismo dispondremos de un archivo sin ninguna línea de código. Lo primero que habrá que hacer es importar el módulo "windows.h" ( #include <windows.h> ), que tendrá todo lo necesario para la programación en windows ( Win32 API ). El programa tendrá que tener como mínimo las siguientes dos funciones:

1) int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int); Esta función es la equivalente al "main()" pero para la programación en windows.

2) LRESULT CALLBACK ProcesaMensajes(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); Esta función manejará los eventos que recibirá la ventana. Se le denomina "Procedimiento de ventana".

Habrá que crear una variable global que se usará para identificar la ventana principal. Todas aquellas variables que hagan referencia a un objeto para poder identificarlo del resto se les denominará "Handle" ( manejador ). Se inicializará al valor cero.

El código hasta ahora escrito quedará de la siguiente forma:

#include <windows.h>

/*Esta variable se utilizará para identificar la ventana ppal. "Handle" a una ventana. En la programación de windows se usará los "Handles" para poder referenciar a cualquier objeto*/
HWND IdentificadorVentanaPrincipal=0;

/*Prototipos de subprogramas*/

LRESULT CALLBACK ProcesaMensajes(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int);

- Figura 13 -

A continuación se verá la primera función: "WinMain". Esta función se encargará de crear la ventana, y luego entrará en un bucle en el cual irá recuperando los mensajes de la cola. Para la creación de una ventana se tendrán que seguir los siguientes pasos:

PRIMER PASO

int WINAPI WinMain(
HINSTANCE hInstance, // Handle a la instancia de la aplicación actual ( Es un identificador)
HINSTANCE hPrevInstance, // No usado en la programación Win32, tomará el valor NULL
LPSTR lpCmdLine, // Línea de comando usada para ejecutar la aplicación
int nCmdShow // Especifica cómo tiene que visualizarse la ventana (SW_SHOWMAXIMIZED, SW_HIDE)
) // ( maximizada, etc...)
{

/*****************************************************************************
PRIMER PASO: Describir la ventana que se va a usar ( Realmente es la descripción
de una "clase" que luego se registrará en Windows). En definitiva, definir una clase para la ventana
*******************************************************************************/

WNDCLASSEX clase_ventana; //Esta variable se usará para especificar los atributos de la ventana
MSG mensaje; //Variable que se usará posteriormente para ir recuperando los mensajes recibidos


clase_ventana.cbSize = sizeof(WNDCLASSEX);
clase_ventana.style = CS_HREDRAW | CS_VREDRAW; // Especifica el estilo
// de la clase. Con los parámetros que se han puesto en el ejemplo
// la ventana será refrescada cada vez que se cambie su tamaño
// horizontal o vertical.

clase_ventana.lpfnWndProc = ProcesaMensajes; // Se le indica cuál será
// la función que se encargará del tratamiento de los mensajes.
// La mayoría de los autores denominan a esta función "windows procedure" ( procedimiento de ventana )

//Los siguientes parámetros indican si se quiere un almacenamiento extra después de la clase ventana (cbClsExtra) o de la estructura window // (cbWndExtra).
clase_ventana.cbClsExtra = 0;
clase_ventana.cbWndExtra = 0;

//Hay que pasarle el manejador de la instancia de la propia aplicación. Se utiliza el parámetro pasado en WinMain ( hInstance )
clase_ventana.hInstance = hInstance;

//Se especifica el icono de la barra de título. Para cargar el icono se usa la API "LoadIcon". Hay iconos predefinidos como: //IDI_APPLICATION, IDI_WINLOGO, etc...
clase_ventana.hIcon = LoadIcon(NULL, IDI_APPLICATION);

//Se indicará cual va a ser el cursor que inicialmente tendrá la aplicación
clase_ventana.hCursor = LoadCursor(NULL, IDC_ARROW);

//Color de fondo de la ventana ( WHITE_BRUSH, BLACK_BRUSH, HOLLOW_BRUSH ( fondo transparente ))
clase_ventana.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH);

//Para indicar el menú de la ventana
clase_ventana.lpszMenuName = NULL;

//Nombre que tomará la clase ventana
clase_ventana.lpszClassName = CLASE_VENTANA;

//Manejador de un icono que se usa para la barra de tareas y esquina
//superior izquierda de la ventana

clase_ventana.hIconSm = LoadIcon(NULL, IDI_APPLICATION);

- Figura 14 -

Como se puede observar en el primer paso se ha usado una constante denominada "CLASE_VENTANA". Para la definición de esa constante habrá que escribir la siguiente línea de código en las primeras líneas del programa:

#define CLASE_VENTANA "La clase ventana"

Esta constante lo que realmente almacena es el nombre que va a tener la clase creada, para poder referenciarla posteriormente.

SEGUNDO PASO

/*****************************************************************************
SEGUNDO PASO: Registrar la clase ventana definida en el primer paso
*******************************************************************************/

if (!RegisterClassEx(&clase_ventana))
{
MessageBox(0, "El registro de la clase no ha podido ser realizado con éxito",
"Error", MB_OK);
return FALSE;
}

- Figura 15 -

TERCER PASO

/*****************************************************************************
TERCER PASO: Crear una ventana basada en la descripción de la clase registrada
en el paso anterior.
*******************************************************************************/

IdentificadorVentanaPrincipal =
CreateWindow(CLASE_VENTANA, /*Nombre de la clase registrada*/
"Ventana de prueba", /*Texto de la barra de título*/
WS_OVERLAPPEDWINDOW, /* Crea una ventana
"overlapped" ( ventana con barra de título y borde). Todos los botones menos el menú
y además WS_CAPTION :tiene barra de título
WS_SYSMENU : : tiene un menú en la "barra de título"
WS_THICKFRAME : Border ventana grueso
WS_MINIMIZEBOX, WS_MAXIMIZEBOX :botones de maximizar
y minimizar*/

0, 0, /*Coordenadas x,y*/
640, 480, /*Ancho por alto*/
0, /*este argumento sería el manejador de la ventana padre. En el caso
de que la ventana no esté relacionada con ninguna tomará el valor cero*/

NULL, /*Manejador del menú de opciones que se va a utilizar.
No va a tener menú de opciones la ventana*/

clase_ventana.hInstance, /* Identificador de la instancia de la aplicación*/
NULL /*Puntero a los datos de creación de ventana*/
);

if (!IdentificadorVentanaPrincipal)
{
/*La ventana no ha podido ser creada*/
MessageBox(0, "Creación de ventana cancelada", 0, 0);
return FALSE;
}

- Figura 16 -

CUARTO PASO

/*****************************************************************************
CUARTO PASO: Se visualiza la ventana creada en el tercer paso
*******************************************************************************/
ShowWindow(IdentificadorVentanaPrincipal, SW_SHOWMAXIMIZED);

- Figura 17 -

QUINTO PASO

/*****************************************************************************
QUINTO PASO: Se refresca la ventana creada
*******************************************************************************/
UpdateWindow(IdentificadorVentanaPrincipal);

- Figura 18 -

SEXTO PASO

/*****************************************************************************
SEXTO PASO: Bucle que se encarga de obtener los mensajes de la cola
*******************************************************************************/

//Se rellena el bloque de memoria con ceros
ZeroMemory(&mensaje, sizeof(mensaje));

seguir = 1;

while (seguir)
{
/*La función "PeekMessage" comprueba si existe un mensaje en la cola de mensajes, rellenando la estructura pasada en el primer parámetro*/
/*BOOL PeekMessage( LPMSG lpMsg, // Puntero a la estructura del mensaje
HWND hWnd, // Manejador a la ventana UINT wMsgFilterMin, // Estos dos parámetros sirven
UINT wMsgFilterMax, // para seleccionar los mensajes a recuperar
UINT wRemoveMsg // El mensaje después de leerlo se eliminará
//de la cola ( PM_REMOVE ) o no (PM_NOREMOVE)
);*/
.................if (PeekMessage (&mensaje, IdentificadorVentanaPrincipal, 0, 0, PM_REMOVE))
.................{
..................................../* Si se recibe un mensaje de salida, habrá que terminar el bucle while*/
....................................if (WM_QUIT == mensaje.message)
....................................{
......................................................seguir = 0;
....................................}

..................................../* Es un mensaje distinto al de WM_QUIT*/
....................................else
....................................{
//Windows envía mensajes WM_KEYDOWN y WM_KEYUP a la ventana que tiene el foco y esos mensajes serán //traducidos a mensajes de tipo WM_CHAR por una llamada a TranslateMessage
//WM_CHAR contendrá el código de la tecla pulsada
......................................................TranslateMessage (&mensaje);
//La función "DispatchMessage" envía el mensaje a la función que se encarga de manipular los mensajes ( en este ejemplo //"ProcesaMensajes" )
......................................................DispatchMessage (&mensaje);
....................................}
..................}
..................else
..................{
/* No se ha recibido ningún mensaje y por tanto aquí se harán todas las tareas de actualización, de refresco de imagen, etc...*/
..................}
}
return mensaje.wParam;;

- Figura 19 -

Ya se ha finalizado el código básico de la función "WinMain". Lo lógico para que el código del programa quede un poco "más ordenado" hubiera sido crear otra función que tuviese el código del sexto paso. Para bajarte este ejemplo organizado de la forma descrita pinchar en el siguiente enlace:

A este último trozo de código ( sexto paso ) se le denomina bucle de mensajes. Este bucle de mensajes se puede resumir en la siguiente secuencia de pasos:

1) Se usa la función "PeekMessage" para buscar en la cola de mensajes. En el caso de estar vacía, la función devolvería falso, y por tanto se pasaría a ejecutar el bloque de código "else".

2) Una vez obtenido un mensaje de la cola, se usará la función "TranslateMessage", el cual traduce los mensajes de teclas virtuales a mensajes con caracteres.

3) Una vez traducido el mensaje llamamos a "DispatchMessage", con lo que se consigue enviar dicho mensaje al Procedimiento de Ventana definido ( en nuestro ejemplo: "ProcesaMensajes").

 

A continuación se va a entrar en la segunda función "ProcesaMensajes":

/* Esta función es el manejador de los mensajes de windows. Cada vez que
windows envía un mensaje a esta aplicación la función "ProcesaMensajes" se
encargará de manipularlo*/

LRESULT CALLBACK ProcesaMensajes(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
..................case WM_DESTROY:
....................................PostQuitMessage(0); //Para informar a Windows que se quiere cerrar la aplicación
....................................return 0;
....................................break;
..................case WM_KEYUP:
....................................switch(wParam)
....................................{
......................................................case VK_ESCAPE:
......................................................................../*El usuario ha pulsado la tecla ESCAPE*/
........................................................................DestroyWindow(hwnd);
........................................................................return 0;
........................................................................break;
....................................}

..................break;
}

return DefWindowProc(hwnd, msg, wParam, lParam);;
}

- Figura 20 -

En "ProcesaMensajes" se realizará una acción asociada según el tipo de mensaje. Siempre, una vez finalizado el tratamiento del mensaje, habrá que llamar a la función "DefWindowProc" la cual realizará las acciones por defecto según el tipo de mensaje.

Una vez procesado el mensaje se volvería al punto desde donde se hizo la llamada a "DispatchMessage", regresando por tanto de nuevo al bucle de mensajes.

¿Qué contiene una variable del tipo MSG?:

typedef struct {
HWND hwnd; //manejador de la ventana a la cual va dirigida el mensaje
UINT message; // Identificador del mensaje
WPARAM wParam; // Información adicional del mensaje
LPARAM lParam;// Información adicional del mensaje
DWORD time;// Hora en la que el mensaje fue enviado
POINT pt; // Coordenadas del cursor cuando se produjo el evento
} MSG, *PMSG;

Por ejemplo en los mensajes de teclado se tendrían los siguientes parámetros:

message WM_KEYDOWN

wParam Código de la tecla virtual. Podría ser: VK_F1 a VK_F12 ( teclas F1 a F2 ), VK_ESCAPE ( Escape), VK_SPACE ( Espacio), VK_RETURN ( Tecla enter ), VK_LEFT, VK_UP, VK_RIGHT, VK_DOWN ( Teclas del cursor )
LParam Datos adicionales sobre la tecla pulsada: Bits 0-15: Nº de repeticiones generadas, Bits 16-23: Scancode, Bit 24: Especifica si es extendida (1/0), etc...

Si las teclas tienen una correspondencia directa con el formato ASCII, se podría utilizar el mensaje WM_CHAR:

wParam Código del carácter.
LParam Flags extra (como WM_KEYDOWN).

- Figura 21 -

Cuando se pulsa la tecla "E" se generan los siguientes tres mensajes ( en este orden ): WM_KEYDOWN( cuando se pulsa una tecla), WM_CHAR, WM_KEYUP ( cuando se suelta la tecla ). Se puede por tanto aprovechar el segundo mensaje (WM_CHAR) para rescatar el código ASCII de la tecla pulsada. ( observar figura 21 )

Imaginemos que se pulsa la tecla de mayúsculas (SHIFT) a la vez que la tecla "E". Ésto provocaría la secuencia de mensajes mostrada en la figura 22.

- Figura 22 -

 

Para los mensajes producidos por eventos del ratón tenemos los siguientes tipos:

message WM_MOUSEMOVE ( El ratón se mueve sobre el área cliente ), WM_LBUTTONDOWN ( Botón izquierdo pulsado), WM_RBUTTONDOWN ( Botón derecho pulsado) , WM_LBUTTONUP ( Botón izquierdo soltado), WM_RBUTTONUP ( Botón derecho soltado). WM_LBUTTONDBLCLK ( Doble click botón izquierdo), etc..

wParam Estado de las teclas cuando el ratón ha producido el evento
LParam Coordenadas del ratón. LOWORD(lParam) = Coordenada X del ratón, HIWORD(lParam) = Coordenada Y del ratón.

Espero que este pequeño artículo le haya servido como una pequeña introducción a la programación en windows. Ahora solamente os queda lo que hoy en día más falta hace, dar rienda suelta a tu IMAGINACIÓN y sobre todo CREATIVIDAD.

¡ Te deseo suerte de todo corazón!.

Autor: Daniel Leyva Cortés

Contacto: transistor47@hotmail.com

 

BIBLIOGRAFÍA

Introduction To 3D Game Programming With DirectX 9.0

http://msdn.microsoft.com/library/spa/

http://msdn.microsoft.com/library/

http://winapi.conclase.net/

http://winprog.org/tutorial/es/

http://pinsa.escomposlinux.org/sromero/articulos/win95/win95-3.html