Principios básicos de programación Windows - Lenguaje C++

Estado
Cerrado para nuevas respuestas

rob1104

Super Moderador
Super Moderador
(Creado por rob1104)

INTRODUCCIÓN

Hola a todos. En esta ocasión vamos a aprender un poco de programación Windows bajo el lenguaje C++ utilizando la API Win32.
Este es un tema muy poco tratado, por lo tanto la documentación que existe en español es muy escasa, y la mayoría se limita solo a explicar de forma muy abstracta, por lo que nos podemos quedar perdidos un poco al tratar de entender.
Antes de empezar debo advertir que necesitaras un nivel intermedio de conocimiento del lenguaje C/C++ para poder comprender al 100%. ¿Por qué? Simplemente porque a pesar de que veamos grandes cantidades de líneas y algúnas palabras raras y desconocidas, no deja de ser lenguaje C++ en ningún momento. Y sigue la misma estructura que un programa en modo Consola, con pequeñas diferencias que veremos a lo largo de este tutorial.

API DE WINDOWS

Una API (Application Programming Interface) es un conjunto de funciones, librerías, métodos e instrucciones que nos ofrece un programa para poder programar sobre él. En esta ocasión, el sistema operativo Windows, como todo buen S.O., necesita ofrecer a sus desarrolladores todas las funciones indispensables para así hacerle la vida más fácil a la hora de programar el software. Ejemplos claros de la API de Windows son por ejemplo los eventos de las ventanas (cerrar, minimizar, maximizar, restaurar), son funciones que ya vienen programadas y el desarrollador solamente se encarga de manejarlas.


CONCEPTOS BASICOS DE PROGRAMACION WINDOWS


Elementos de una ventana
Una de las características más importantes de todos los programas Windows, es que están formados por ventanas (de ahí el nombre Windows). Pero lo que no muchos saben, es que todos los elementos de un programa son ventanas, un botón de comando es una ventana, una caja de texto también es una ventana, una etiqueta también, en fin, todo lo que vemos está formado por ventanas. Veamos los elementos básicos de un programa:

Imagen Rota/Perdida

En la barra de título se puede apreciar, a parte del título de la aplicación, su icono de identificación y los botones predefinidos minimiza, maximizar/restaurar y cerrar, los cuales vienen implícitos con el borde de ventana.

Programas Windows y el Sistema operativo
Cuando escribimos un programa Windows, éste pasa a ser ‘controlado’ por el sistema operativo. Es decir, nuestro programa no tratará directamente con el hardware, y todo lo que haga el programa pasara primero por el núcleo de Windows, y éste será quien decida qué hacer.
Para entenderlo más fácilmente, existen dos formas de programar para un sistema operativo: Modo Usuario y Modo Kernel. En el segundo modo, es donde si se tiene acceso al hardware, es en el cual se escriben los controladores para que funcionen los distintos dispositivos correctamente. Programar en dicho modo, es un poco más complicado, ya que se requiere también conocimiento de lenguajes de más bajo nivel y conocer la estructura de hardware a detalle. Los errores que se cometan en ese modo no los puede manejar el sistema operativo, y en ocasiones tiene que detener todo y provocar algúna excepción para no dañar el equipo, en el caso de Windows, una pantalla azul apagando el sistema dando los detalles del error.
Por esta razón, existe el modo usuario o modo protegido, aquí como mencioné antes, es el sistema operativo quien toma las decisiones, y nosotros nos encargamos de programar que es lo que queremos hacer. Al producirse algún error, simplemente el sistema nos lo informa y cierra el programa conflictivo.

Windows y los Eventos

Programar en Windows sigue la metodología de la programación orientada a eventos, esto quiere decir, que al ejecutar un programa, éste se queda esperando que algún evento ocurra y así poder decidir qué hacer. La mayor parte del código fuente de un programa Windows está enfocada en procesar estos eventos, los cuales pueden ser provocados por el usuario, por el mismo programa ó por un programa tercero.

Mensajes
Un evento en Windows ocurre por ejemplo, al dar clic izquierdo en el mouse, al presionar cierta tecla, o cuando un contador llega cero. Windows graba cada evento en un mensaje, el cual es almacenado en una cola de mensajes para ser procesado por la función de nuestro programa encargada de ello. Un mensaje es como llama Windows a cada evento o acción realizada y que tiene que ser procesada por el programa, es decir, al producirse un mensaje, el programa ejecuta el código asociado a ese mensaje, y después regresa el control al sistema operativo, pero el programa sigue activo esperando más mensajes, y no terminará hasta que reciba el mensaje de que debe cerrarse.

Función WindowsProc()
Todo programa Windows, necesita una función específica la cual se encargará de procesar los mensajes. Esta función es comúnmente llamada WindowsProc() o wndProc(), aunque no requiere un nombre especifico, ya que se asigna a través de un puntero cuando se crea y registra la ventana, pero es conveniente seguir el estándar para poder identificar esta función rápidamente en caso de un programa muy extenso.
Afortunadamente, no es necesario escribir un código para todos los mensajes que puedan ocurrir, solamente para los que realmente vamos a necesitar, es decir, si no necesitamos el click derecho, no es necesario manejar ese mensaje, todos los mensajes no filtrados son procesados al final sin ejecutarse ningún código la realizar la acción.

Tipos de Datos Windows
Para facilitarnos un poco más la programación, Windows define algúnos tipos de datos especiales usados específicamente por la API, estos son:

Imagen Rota/Perdida

Las únicas palabras que nos pueden parecer nuevas de esta tabla serian: manejador e instancia.
Como menciona la tabla, un handle (manejador), no es más que un en número entero de 32 bits. ¿Para qué se usa? Para identificar un objeto de todos los que residen en memoria, es decir, viene siendo un número único que distingue un objeto de otro. Estos los asigna el sistema operativo por cada objeto nuevo creado en memoria.
Por ejemplo, al ejecutar la calculadora de Windows, el programa se abre y dibuja una ventana con muchos botones y una etiqueta para mostrar los dígitos. Ahí, la ventana principal de la calculadora tiene su propio handle, cada botón también tiene el suyo, así como la etiqueta. Esto ayuda, por ejemplo a la hora de programar, saber que ventana envió algún mensaje, o para saber a qué objeto o ventana el sistema va a devolver un resultado. Lo veremos más adelante con un ejemplo para que quede totalmente claro el concepto y utilidad de los manejadores.
Lo que es una instancia, lo veremos más adelante en el ejemplo, pero se puede resumir como un programa ejecutándose ya en la memoria. Por ejemplo al abrir un programa y visualizar su pantalla, ya tiene su instancia, ya depende de nosotros si dejamos que se puedan crear tantas instancias del mismo programa o solo una a la vez.


Notación estándar en programas Windows.

Para poder ajustarnos a una buena práctica de programación, es recomendable utilizar prefijos a la hora de crear las variables, Microsoft recomienda utilizar la notación húngara para el desarrollo de programas Windows, es una forma sencilla de declaración de variables, que consiste en utilizar un prefijo, seguido del nombre de la variable, altamente recomendado que tenga relación con el uso que se la va a dar a la variable. Esto hará más fácil la modificación del programa en el futuro, así como una mejor comprensión del código para programadores terceros.

Imagen Rota/Perdida

Y así fácilmente podremos crear los nombres de las variables, para poder identificarla
HANDLE hInstance;
DWORD dwIntensidad;[/PHP]


ESTRUCTURA DE UN PROGRAMA WINDOWS

Para poder escribir el programa mas pequeño basado en la API de windows, necesitarás principalmente dos funciones:

  • WinMain() Función principal con la que inicia el programa, es el equivalente a main() de los programas en modo consola. Es importante mencionar que la función debe llamarse exactamente así y no puede llevar otro nombre, lo que si podemos cambiar libremente son el nombre de sus parametros (pero no sus tipos).
  • WindowsProc() Función encargada de procesar los mensajes, su nombre puede ser modificado, pero no lo recomiendo para facilitar su identificación. Dependiendo de los mensajes, podría llegar a ser la función más grande del programa.
Lo interesante de ésto, es que a pesar de que con solo esas dos funciones podemos realizar un programa, éstas no están conectadas entre sí, es decir, WinMain() no manda llamar a WindowsProc(). Lo que en realidad sucede es que al crear una ventana dentro de WinMain(), uno de los parametros de la función que la crea es elegir la función encargada de procesar los mensajes. Entonces el sistema operativo, es el encargado de mandar llamar la función WindowsProc() cuando es necesario, una preocupación menos ^_^

Imagen Rota/Perdida

Bien, una vez que haya quedado claro lo anterior, llega la hora de escribir el código y empezar a practicar lo aprendido. Pero, solo una cosa más... como sabe el compilador los nuevos tipos de datos, y esos nombres de funciones que no están en el estandar... Respuesta: windows.h

En el archivo de cabecera windows.h, se encuentran declaradas otras cabeceras importantes para que funcionen los programas basados en windows, por ejemplo: winbase.h, winuser.h, wingdi.h, winerror.h entre otras más, que por ahora no es necesario conocer a fondo. Pero que contienen funciones como WinMain() GetMessages() TranslateMessages() DispatchMessages() que como mencioné son indispensables para escribir nuestro programa.


NUESTRO PRIMER PROGRAMA WINDOWS

Ahora si, a poner en práctica lo aprendido. En teoría podemos usar cualquier compilador que genere ejecutables de 32 bits para windows. Pero por comodidad y facilidad usaré el IDE Code::Blocks, el cual incorpora el compilador MinGW, mas que suficiente para este ejemplo.

Este IDE cuenta con un asistente, que con un par de clicks puede crear un proyecto Win32 facilmente, pero como vamos a prácticar lo aprendido, la unica forma de aprender es haciendolo desde 0. Asi que comenzemos.


  1. Abrimos code::blocks
  2. Crearemos un nuevo archivo desde el menu File/New/File... Imagen Rota/Perdida
  3. Elegimos C/C++ Source (Archivo Fuente C/C++) y después click en Go...Imagen Rota/Perdida
  4. En este caso es indiferente elegir C o C++, pero por compatibilidad con futuros cambios y mejor compatibilidad al estandar elegiremos C++, click en next. Imagen Rota/Perdida
  5. Por ultimo escribimos un nombre para el archivo y seleccionamos la ruta donde se guardará, no vamos a añadir el archivo a un proyecto ya que será el unico fuente. Click en finish para que termine el asistente y nos muestre nuestra area de trabajo:Imagen Rota/Perdida

Función WinMain típica.
La función WinMain, a diferencia de main(), necesita obligatoriamente cuatro parametros, generalmente es declarada asi: Código:
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{

}

La macro WINAPI, indica que es una función windows, esto la hace un tanto especial, y es ahi cuando el compilador se da cuenta que estamos generando un ejecutable especificamente para Windows con interfaz gráfica.


  • hInstance: es un manipulador para la instancia del programa que estamos ejecutando. Cada vez que se ejecuta una aplicación, Windows crea una Instancia para ella, y le pasa un manipulador de dicha instancia a la aplicación.
  • hPrevInstance es un manipulador a instancias previas de la misma aplicación. Como Windows es multitarea, pueden existir varias versiones de la misma aplicación ejecutándose, varias instancias. En Windows 3.1, este parámetro nos servía para saber si nuestra aplicación ya se estaba ejecutando, y de ese modo se podían compartir los datos comunes a todas las instancias. Pero eso era antes, ya que en Win32 usa un segmento distinto para cada instancia y este parámetro es siempre NULL, sólo se conserva por motivos de compatibilidad.
  • lpCmdLine, esta cadena contiene los argumentos de entrada de la linea de comandos.
  • nCmdShow, este parámetro especifica cómo se mostrará la ventana. Para ver sus posibles valores consultar valores de ncmdshow. Se recomienda no usar este parámetro en la función ShowWindow la primera vez que se ésta es llamada. En su lugar debe usarse el valor SW_SHOWDEFAULT.
Como mencioné antes, podemos cambiar los nombres de los parametros, pero no los tipos, aun así es preferible dejarlos tal cuales, y es lo que voy a hacer.

La función WinMain() necesita hacer 4 cosas:

  1. Especificarle al sistema operativo que tipo de ventana se requiere
  2. Crear la ventana
  3. Inicializar la ventana
  4. Manejar los mensajes (prepara la cola de mensajes que WindowsProc() va a procesar y los va enviando conforme van ocurriendo esperando un resultado)
Imagen Rota/Perdida



PASO 1


El primer paso al crear una ventana, es definir y especificar el tipo de ventana que necesitamos. Esto es sencillo. Para ello, Windows define un tipo especial de estructura (struct) llamado WNDCLASSEX, que contiene toda la información para especificar los parametros de una ventana, que de ahora en adelante llamaremos clase de ventana (No confundir con una clase de C++).
Entonces lo que necesitamos hacer es crear una variable de tipo WNDCLASSEX, y asignarle valores a cada uno de sus miembros (como si estuvieramos estableciendo las propiedades de un formulario). Una vez asignados los valores, tenemos que pasarlos al sistema operativo a través de una función que veremos mas adelante, a eso se le llama Registrar una clase. Ya cuando esté registrada, Windows puede manejarla y podemos asignarla a una ventana que crearemos en el proximo paso.

Antes de escribir el código que especifica y registra la clase de ventana que vamos a usar, voy a explicar la estructura WNDCLASSEX y sus miembros, la cual está definida en el archivo winuser.h de la siguiente forma:


Código PHP:

typedef struct _WNDCLASSEXA
{
UINT cbSize; //Tamaño de la estructura en bytes
UINT style; //Estilo de la ventana
WNDPROC lpfnWndProc; //Puntero a la función que procesa los mensajes
int cbClsExtra; //Especifica cuantos bytes extra se reservarán a continuación de la estructura de la clase
int cbWndExtra; //Especifica cuantos bytes extra se reservarán a continuación de la instancia de la ventana
HINSTANCE hInstance; //Instancia de la ventana a la que pertenece esta clase
HICON hIcon; //Icono de la ventana
HCURSOR hCursor; //Cursor que tomará el mouse sobre la ventana
HBRUSH hbrBackground; //Pincel que utilizará la ventana
LPCSTR lpszMenuName; //Puntero a una cadena terminada con cero que especifica un nombre de recurso de la clase menú
LPCSTR lpszClassName; //Puntero a el nombre de la clase
HICON hIconSm; //Icono pequeño asociado a la ventana
}

Bien, ya que sabemos como está estructurada la variable, procedamos a crearla en nuestro programa y ajustar todos los miembros de acuerdo a nuestras necesidades. La siguiente imagen nos muestra como debe quedar el código, en seguida lo explicaré: Imagen Rota/Perdida

Bueno, primero que todo, ese error en la linea 10. Como mencioné antes, la propiedad lpfnWndProc, es un puntero a la función que procesa los mensajes. Dicha función es WindowsProc(), la cuál no he definido. Para hacerlo más sencillo de entender, vamos a colocar la funcion WindowsProc() antes que WinMain(),

La API Win32 especifica que el prototipo de la función que procese los mensajes es el siguiente: Código:
LRESULT CALLBACK WindowsProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
Debe ser tipo LRESULT, por que retorna los resultado de los mensajes, que no es más que un entero largo de 32 bits. También, debido a que es un puntero a función, debe ser declarado CALLBACK, ya que así lo especifica el estandar de la API win32.

Los parametros que recibe son:
HWND hwnd: Es el manejador de la ventana que envía el mensaje, una vez que termine de procesar los mensajes que recibe, le devuelve el control al manejador para que continue con lo suyo.
UINT msg: El identificador de un mensaje es siempre un numero natural sin signo (Unsigned INT), esto hace más fácil el proceso y manejo de los mensajes, es por eso que son recibidos a través de este parametro.
WPARAM wParam y LPARAM lParam: Como existen varios tipos de mensajes, estos parametros ayudan a procesar los mensajes. Ya que algúnos mensajes pueden contener un parametro adicional al ser procesadors. Pueden ser tipo WORD (entero sin signo) para WPARAM ó LONG (entero de 32 bits con signo) para LPARAM).

Afortunadamente, nosotros no tenemos que preocuparnos de estos parametros, ya que existe una función encargada de pasar los mensajes a Windows con todo lo necesario para ser procesados, y además también espera e interpreta el resultado de cada mensaje. Esta función es DispatchMessage(), la cual veremos un poco más adelante.

Por lo pronto, el programa nos queda de la siguiente manera:
Imagen Rota/Perdida

A lo largo de éste código observamos algúnas constantes, como CS_HREDRAW, CS_VREDRAW, IDI_APPLICATION, IDI_ARROW y COLOR_WINDOW
Asi como 3 funciones: LoadIcon(), LoadCursor() y RegisterClassEx().

Las constantes que puede recibir la propiedad style son las siguientes: Imagen Rota/Perdida
Todas son enteros de 16 bits, que pueden ser combinadas con el operador OR (|) para ajustar el estilo deseado.

Asi como esas, existen cientos de constantes mas declaradas en los distintos archivos de cabecera que utiliza windows, sería imposible mencionarlas todas. Además es una gran ventaja que en C++ ya estén declaradas, ya que por ejemplo en Visual Basic 6 teniamos que asignar el valor de las constantes manualmente cuando necesitabamos trabajar con la API de Windows. Por lo tanto explicaré las 3 restantes que aparecén hasta ahora:
IDI_APPLICATION = Constante que indica que se usará el icono estandar de aplicacíon Win32 para el programa
IDC_ARROW = Constante que indica que se usará el cursor del mouse estandar, es decir, la flecha que esté como predeterminada.
COLOR_WINDOW = Constante cuyo valor indica el color predeterminado de las ventanas de Windows

Las funciones LoadIcon() y LoadCursor(), sirven para cargar tanto el icono como el cursor al programa. Ambas reciben los mismos parametros que son: (Instancia actual, Nombre del recurso). En este caso, obviamos la instancia actual, ya que es la única, y usamos las constantes predefinidas en Windows para el nombre del recurso, así el sistema identifica cual icono y cursor debe cargar sin problema.

RegisterClassEx()
Esta función registra una clase de ventana para su uso subsecuente en llamadas a las funciones de creación de las ventanas, como CreateWindow(), que veremos mas adelante, esta recibe como parametro la dirección de la estructura de la clase creada.


PASO 2

Una vez que Windows sabe que clase de ventana va a utilizar, es hora de crear la ventana.
Primero tenemos que declarar un manejador para la ventana, este debe ser un HANDLE para ventanas, definido en el estandar como HWND.
Despuésinvocamos a la función CreateWindow(), la cual recibe 11 parametros y devuelve un HWND

Los función CreateWindow() está definidia en winuser.h y su prototipo es:

Código PHP:

HWND CreateWindow(
LPCTSTR lpClassName, // Puntero al nombre de la clase registrada
LPCTSTR lpWindowName, // Puntero al nombre de la ventana
DWORD dwStyle, // Estilo de ventana
int x, // Posición horizontal de la ventana
int y, // Posición vertical de la ventana
int nWidth, // Ancho de la ventana
int nHeight, // Alto de la ventana
HWND hWndParent, // Manejador de la ventana padre o propietaria
HMENU hMenu, // Manejador de menú o identificador de ventana hija
HANDLE hInstance, // Manejador de la instancia de la aplicación
LPVOID lpParam // Puntero a los datos para la creación de la ventana
);

Despuésde crear la ventana, hay que mostrarla en pantalla, para ello utilizaremos otra función de la API, la cuál es: ShowWindow(), ésta solo recibe dos parametros, su definición es: Código PHP:
BOOL ShowWindow(
HWND hwnd, // Manejador de ventana
int nCmdShow // Modo de visualización de ventana
);

Una vez conociendo los parametros, será fácil ajustarlos en el programa, al momento de crear la ventana. Vamos a crear una ventana sencilla: Imagen Rota/Perdida

Aqui hay que destacar un parametro muy importante, el tercero. Indica el estilo que tomará la ventana, es decir, si se puede redimensionar, mover, si tiene barra de titulo, bordes, botones de maximizar, cerrar y restaurar, etc.... La siguiente tabla detalla las constantes que pueden ser tratadas en ese parametro: Imagen Rota/Perdida
Podemos crear y mostrar tantas ventanas necesitemos en nuestra aplicación, incluso, como mencioné al principio, con este metodo también crearemos los botones, cajas de texto, etiquetas entre otros controles que pueden ser usados en nuestros programas.
Ahora el siguiente paso es inicializar la ventana.

PASO 3

Despuésde llamar a la función ShowWindow() la ventana se muestra en pantalla, pero aun no tiene contenido. Asi que primeramente, necesitamos habilitar la ventana para que se pueda dibujar en ella, es decir, en el area de cliente de la ventana.

La función UpdateWindow() actualiza el área de cliente de la ventana especificada enviándole un mensaje determinado (WM_PAINT) a ésta si la región de actualización no está vacía. La función envía dicho mensaje directamente al procedimiento de ventana de la ventana especificada, evitando la cola de la aplicación. Si la región de actualización está vacía, no se envía mensaje.

Esta función solamente necesita como parametro el manejador de la ventana que necesita actualizar. Dejandola totalmente inicializada para poder dibujar en ella. Asi que este paso 3 solo tendrá una sola linea:

Imagen Rota/Perdida


PASO 4

Llegamos al corazón de la aplicación. Ahora toca controlar la cola de mensajes que recibe la ventana, para que se envien a la funcion WindowsProc().
El algoritmo es muy sencillo:
Código:
Mientras la cantidad de mensajes en la cola sea mayor a cero
Traducir el mensaje
Enviar el mensaje a la función que los procesa
Fin mientras
Regresamos el control a Windows


GetMessage()

Básicamente, el programa debe estar al pendiente de los mensajes que reciba, para que los enve a WindowsProc(), y ésta se encarga de procesar el evento asociado a cada mensaje, termina de hacerlo, regresa el control a la aplicación, y se queda en espera de mas mensajes, así sucesivamente hasta recibir el mensaje que cierra el programa.
¿Pero como sabemos si hay mensajes?. La API nos proporciona la función GetMessage().
Esta función recupera un mensaje de la lista de mensajes de la aplicación y lo coloca en la estructura especificada. La función recuperará los mensajes en el rango especificado. Pero no recuperará mensajes de ventanas que pertenezcan a otros procesos o aplicaciones.

Su prototipo recibe cuatro parametros y devuelve un valor booleano:


Código PHP:

BOOL GetMessage(
LPMSG lpMsg, // Puntero a la estructura que contendrá el mensaje
HWND hWnd, // Manejador de ventana, si es nulo, recibirá mensajes de cualquier ventana que pertenezca al mismo proceso de la aplicación.
UINT wMsgFilterMin, // Primer mensaje
UINT wMsgFilterMax // Último mensaje
);



Imagen Rota/Perdida

Solo falta el código que va dentro del bucle, que son un par de funciones que se encargan de traducir el mensaje, y enviar el mensaje a la función WindowsProc().

TranslateMessage() y DispatchMessage()
Ambas funciones solo reciben como parametro la dirección de memoria donde se encuentra el mensaje.
La primera se encarga
de traducir los mensajes de teclas virtuales a mensajes de carácter, es decir, traduce los mensajes de el código que envia el hardware a el código que pueda entender Windows.
La segunda envía el mensaje al procedimiento de ventana, donde será tratado adecuadamente.

Estructura de un mensaje
Hemos hablado de los dichosos mensajes durante todo este texto, pero ¿que son en realidad? Son un tipo especial de variable especificado por Windows en una estructura de la siguiente manera:

Código PHP:

struct MSG
{
HWND hwnd; //Manejador de la ventana que envia el mensaje
UINT message; // Identificador del mensaje
WPARAM wParam; // Parametro del mensaje (32 bits sin signo)
LPARAM lParam; // Parametro del mensaje (32 bits con signo)
DWORD time; // Tiempo que durará el mensaje en la cola
POINT pt; // Posición del mouse
};

No es necesario ajustar todas sus propiedades, bastará con solo asignar el parametro retornado al sistema operativo, o algúnos más en otros tipos de mensajes mas avanzados.
El código del paso 4, quedará de la siguiente manera: Imagen Rota/Perdida


PROCESANDO LOS MENSAJES

Ya creamos la clase de ventana, creamos una ventana, asignamos la clase a la ventana, mostramos la ventana en pantalla y mandamos los mensajes a la funcion que los procesa. Pero esa función esta vacía, solamente tenemos que manejar los mensajes y ejecutar cierto código dependiendo del tipo de mensaje que sea.

La función
DispatchMessage() le pasa el identificador del mensaje a WindowsProc().

El proceso para decodificar y tratar los mensajes recibidos, es con la sentencia de selección multiple switch() propia de C++.

Hay muchos tipos de mensajes diferentes, generalmente identificados con un prefijo seguido de un guión bajo y después una palabra en ingles que identifica la acción del mensaje.
Los prefijos pueden ser:
BM_ Mensaje de un botón de comando
CB_ Mensaje de una lista desplegable
CDM_ Mensaje de un cuadro de dialogo común
DRV_ Mensaje de un Driver o controlador
EM_ Mensaje de Caja de Texto
LB_ Mensaje de ListBox
WM_ Mensaje de Ventana
Seguidos de palabras como
PAINT - Dibuja en la ventana
DESTROY - Destruye la ventana
QUIT - Ocure al cerrar la ventana
LBUTTONDOWN - Ocurre al presionar el click izquierdo

LLBUTTONUP - Ocurre al soltar el click izquierdo

Para continuar nuestro ejemplo, vamos a procesar solo dos mensajes que van a ocurrir.
WM_PAINT: Ocurrirá al inicializar la ventana
WM_DESTROY: Ocurrirá al cerrar la ventana.

La función DefWindowProc() procesará los mensajes que no manejemos, ya que aunque no tengamos códdigo para ellos, de todas formas ocurren. Recibe los mismos parametros que WindowsProc(), hasta ahora nos debe quedar asi:
Imagen Rota/Perdida

Empecemos por procesar el primer mensaje. WM_PAINT. Este mensaje sucede al crearse la ventana, así que veremos su ejecución enseguida.

Vamos a 'pintar' un mensaje en la ventana. Para ello necesitaremos algúnas variables y funciones nuevas que veremos a continuación. Lo que haré será colocar el código y después lo explicaré:Imagen Rota/Perdida

Primero, creamos un dispositivo de contexto, que es la parte dibujable. Imaginemos que es como una hoja de papel que pegamos sobre la ventana.
Despuésla estructura PAINTSTRUCT, que brinda la información desde la ventana al dispositivo de contexto. Es necesaria porque define el sector de memoria necesario para poder dibujar sobre el dispositivo de contexto.

BeginPaint()
Esta función recibe dos parametros, el identificador de la ventana, y la dirección de memoria de el PAINTSTRUCT. Esto devuelve un numero entero que se asigna como manejador al dispositivo de contexto. Con esto ya está todo preparado para comenzar a pintar cualquier cosa sobre la ventana.

Ahora, para definir que es lo que se va a dibujar, vamos a crear un rectangulo, que no es más que una simple estrcutrua que define la parte exacta del dispositivo de contexto donde se va a dibujar.

GetClientRect()
Recupera las coordenadas del área de cliente de la ventana. Las coordenadas de cliente especifican las esquinas superior izquierda e inferior derecha del área de cliente. Como las coordenadas de cliente son relativas a la esquina superior izquierda del área de cliente de la venana, las coordenadas de la esquina superior izquierda son (0,0).
Los unicos dos parametros que recibe son el manejador de la ventana y la dirección de memoria del rectangulo.

DrawText()

Ahora realmente dibujamos el texto usandoDrawText( ), pasamos el HDC a usar y el string a dibujar. El tercer parámetro es la longitud del string, pero hemos pasado -1 debido a que DrawText( ) es lo suficientemente astuto para darse cuenta cual es la longitud del texto. En el cuarto parámetro pasamos la dirección de memoria del rectangulo donde estamos dibujando

EndPaint()
Marca el final del pintado para una ventana dada. La llamada a ésta función se requiere para cada llamada a la función BeginPaint(), pero sólo después de que el proceso de pintado se haya completo.
Recibe como parametros el manejador de la ventana y la dirección de memora del PAINTSTRUCT usado.

Por ultimo, y para terminar nuestra ventana, vamos a procesar el mensaje WM_DESTROY, que ocurre al cerrar la ventana. En este caso, queremos que al cerrar la ventana termine la ejecución del programa.
Para eso, solamente necesitaremos una función que nos proporciona la api de windows:

PostQuitMessage()
Envia un mensaje WM_QUIT a la cola de mensajes, el cual es procesado por DefWindowProc() para terminar la aplicación. Al mandarle un 0 como parametro indicamos que todo ha salido bien e indica una salida exitosa del programa.
Posterior a eso retornamos también un 0 al programa para que termine con exito.

Imagen Rota/Perdida

Listo, tenemos nuestra primer ventana en C++ con la ayuda de la API de windows. Podemos ejecutar el programa sin problemas y tendremos nuestra bonita ventana saludando al mundo:

Imagen Rota/Perdida

Espero esto les ayude a entender como maneja Windows las ventanas. Al principio talvez parezca un poco complicado, pero con práctica se volverá mucho más facil.

Aun faltan cosas, como agregar controles a las ventana y procesar sus eventos, pero es exactamente lo mismo. Ya veremos como hacerlo pronto.

Mientras tanto, dejo abierto el post para cualquier duda, critica, queja, comentario, o algo que se me haya pasado. Estaré ausente unos días pero lo leere cuando regrese.



rob1104
trucoswindows.net

 
Estado
Cerrado para nuevas respuestas
Thread starter Temas similares Forum Replies Date
FranGK Manuales Programación 1
Temas similares
Ejemplos básicos en C
Arriba Pie