Versión 3.0

800x600 mínimo
En esta lección:

Introducción
-----
Procesando mensajes
-----


Otras secciones:

Conceptos básicos
-----
Programando en C
-----
Programando en C++
-----
Programando Windows 9x.
-----
Teoría electrónica
-----
Circuitos electrónicos
-----
Actividades adicionales
-----
Hipervínculos
-----


Contácteme:

Dudas y comentarios
-----


Hola mundo

Introducción

Una ventana en una aplicación escrita para el sistema operativo MS-Windows es una area rectangular de la pantalla donde la aplicación despliega salida y recibe entrada del usuario. Una ventana comparte la pantalla con otras ventanas, incluyendo aquellas de otras aplicaciones. Solo una ventana a la vez puede recibir entrada del usuario. El usuario puede utilizar el ratón, el teclado u otro dispositivo de entrada para interactuar con esta ventana y con la aplicación propietaria. La ventana es el único medio que una aplicación escrita para MS-Windows tiene para interactuar con el usuario y completar las tareas de la aplicación, de esta manera, una de las primeras tareas de una aplicación basada en MS-Windows es crear una ventana. Para esto utilizamos la Interfaz de Programación de Aplicaciones (API, por sus siglas en inglés) del sistema operativo MS-Windows. Al iniciar Windows se crea automáticamente la ventana del escritorio la cual se encarga de pintar el fondo de la pantalla y sirve de base para todas las aplicaciones Windows de 32 bits. Cada aplicación basada en Win32 crea al menos una ventana, llamada ventana principal que sirve de interfaz entre la aplicación y el usuario. La mayoría de las aplicaciones crean otro tipo de ventanas, sea directa ó indirectamente, como por ejemplo, botones, cuadros de diálogo, barras de desplazamiento, etc.

Para crear una aplicación basada en Win32 podemos utilizar varios lenguajes, entre ellos Visual Basic de Microsoft, Delphi de Borland, C++ y C. Como habrá adivinado, en este sitio utilizaremos C para demostrar la funcionalidad básica de una aplicación de 32 bits para el sistema operativo MS-Windows y posteriormente usaremos C++ al adentrarnos en la moderna tecnología utilizada por Microsoft en el desarrollo de aplicaciones, incluyendo aquellas que conducirán al sistema operativo de 64 bits. Todos los conceptos en materia de programación involucrados en el desarrollo de una aplicación para Windows 9x. de 32 bits los encontrará sea en nuestro tutorial de C o bien en la sección dedicada a C++, en tanto que en esta sección se concentrará lo concerniente a Windows. Empezamos pues mostrandole el código necesario para crear una ventana principal que sirva de soporte a nuestra aplicación, observe que está escrita en C sin embargo se utilizan algunos elementos de C++ como los comentarios, esto es perfectamente válido ya que C está completamente soportado por C++ además, es muy importante entender que al programar para Windows 9x en realidad nos estamos comprometiendo con el concepto de Programación Orientada a Objetos (POO) que como Usted sabe es la piedra angular de C++. Utilizaremos el código para explicar los conceptos elementales de una ventana y nos servirá a su vez como punto de partida para prácticamente el resto de las aplicaciones Windows que desarrollaremos en este sitio.


//**************************************************
//	Ventana.c
//	Aplicación básica para Windows 9x
//	(c)1998, Virgilio Gómez Negrete
//**************************************************

#include <windows.h>

LRESULT CALLBACK Procedimiento_de_ventana(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  PSTR szCmdLine, int iCmdShow)
{
    static char   szAppName[] = "Win32basico";
    HWND          hwnd;
    MSG           msg;
    WNDCLASSEX    clase_de_ventana;

    clase_de_ventana.cbSize        = sizeof (clase_de_ventana);
    clase_de_ventana.style         = CS_HREDRAW | CS_VREDRAW;
    clase_de_ventana.lpfnWndProc   = Procedimiento_de_ventana;
    clase_de_ventana.cbClsExtra    = 0;
    clase_de_ventana.cbWndExtra    = 0;
    clase_de_ventana.hInstance     = hInstance;
    clase_de_ventana.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
    clase_de_ventana.hCursor       = LoadCursor (NULL, IDC_ARROW);
    clase_de_ventana.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
    clase_de_ventana.lpszMenuName  = NULL;
    clase_de_ventana.lpszClassName = szAppName;
    clase_de_ventana.hIconSm       = LoadIcon (NULL, IDI_APPLICATION);

    RegisterClassEx (&clase_de_ventana);

    hwnd = CreateWindow (szAppName, "Título de la aplicación",
      WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
      CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

    ShowWindow (hwnd, iCmdShow);
    UpdateWindow (hwnd);

    while (GetMessage (&msg, NULL, 0, 0))
    {
        TranslateMessage (&msg);
        DispatchMessage (&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK Procedimiento_de_ventana (HWND hwnd, UINT iMsg,
  WPARAM wParam, LPARAM lParam)
{
    HDC           hdc;
    PAINTSTRUCT   ps;
    RECT          rect;

    switch (iMsg)
    {
        case WM_PAINT:
        hdc = BeginPaint (hwnd, &ps);
        GetClientRect (hwnd, &rect);
        DrawText (hdc, "Aplicación básica en windows 9x de 32 bits",
          -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
        EndPaint (hwnd, &ps);
        return 0;

        case WM_DESTROY:
        PostQuitMessage (0);
        return 0;
    }
    return DefWindowProc (hwnd, iMsg, wParam, lParam);
}

El resultado de la ejecución del código es el siguiente:

Aplicación básica para Windows 9x

Como se puede apreciar, el programa crea una ventana típica con su barra de título, botones para maximizar, minimizar y cerrar la aplicación e ícono para acceder al menú del sistema (también conocido como menú de control). Es importante que Usted compile y ejecute el código aquí presentado para que observe las funciones adicionales aportadas por el sistema operativo MS-Windows 95, como la capacidad de mover la ventana alrededor de la pantalla, cambiarla de tamaño, minimizarla y maximizarla, compruebe como el texto se posiciona automáticamente al centro de la ventana conforme cambia el tamaño de ésta. Se puede ver que este programa tiene toda la funcionalidad característica de un programa Windows. Para adentrarnos en el funcionamiento de este programa es bueno ver las partes que lo componen. Como todo programa C, empezamos indicandole al sistema que incluya el archivo de cabecera windows.h, éste incluye otros archivos de cabecera que contienen las declaraciones de las funciones, las estructuras, tipos de datos y constantes numéricas utilizadas por Windows. Enseguida tenemos la declaración de la función Procedimiento_de_ventana necesaria porque se hace referencia a ella dentro de la función principal del programa, después tenemos la función principal en sí que en este caso es de tipo int, utiliza la secuencia de llamada WINAPI y se llama por definición WinMain, como es fácil deducir, es similar a la función C main. Contiene cuatro parámetros:

  • hInstance (manejador de instancia). Es un número asignado por el sistema operativo para identificar a su programa en forma exclusiva al momento de ejecutarse.

  • hPrevInstance (instancia previa). Este parámetro es siempre NULL en Windows 9x de 32 bits, se utilizaba en los sistemas operativos de 16 bits para identificar una copia anterior en uso del mismo programa.

  • szCmdLine (línea de comandos). Se trata de un puntero hacia una cadena de caracteres que contiene instrucciones para el programa pasadas directamente desde la línea de órdenes del modo MS-DOS.

  • iCmdShow (visualiza ventana). Es una instrucción que determina la forma de visualización de la ventana al iniciar el programa.

Ya dentro de la función WinMain hemos declarado un array de tipo static char que contiene simplemente el nombre de la aplicación; declaramos una variable de tipo HWND llamada hwnd que almacenará el "manejador de ventana" (handle to a Window); también se declara una estructura de tipo MSG y una clase de tipo WNDCLASSEX llamada en este caso clase_de_ventana para facilitar la comprensión del código. En seguida se debe definir los doce campos que componen la estructura WNDCLASSEX para después llamar a la función RegisterClassEx que nos permitirá registrar nuestra ventana en Windows, en estos campos especificamos características generales para la clase que creará nuestra ventana:


clase_de_ventana.cbSize        = sizeof (clase_de_ventana);
clase_de_ventana.style         = CS_HREDRAW | CS_VREDRAW;
clase_de_ventana.lpfnWndProc   = Procedimiento_de_ventana;
clase_de_ventana.cbClsExtra    = 0;
clase_de_ventana.cbWndExtra    = 0;
clase_de_ventana.hInstance     = hInstance;
clase_de_ventana.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
clase_de_ventana.hCursor       = LoadCursor (NULL, IDC_ARROW);
clase_de_ventana.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
clase_de_ventana.lpszMenuName  = NULL;
clase_de_ventana.lpszClassName = szAppName;
clase_de_ventana.hIconSm       = LoadIcon (NULL, IDI_APPLICATION);

RegisterClassEx (&clase_de_ventana);

Es en esta parte del código donde se establece entre otras cosas, el color del fondo de la ventana, el ícono de la aplicación, el tipo cursor y la función para el procedimiento de ventana que es la que se encarga de manejar los mensajes recibidos del sistema operativo. Tenga Usted muy en cuenta que un programa Windows está basado en un intercambio de mensajes generados por el usuario del programa al interactuar con la aplicación, estos mensajes se generan en los dispositivos de entrada, son controlados por Windows y éste informa a la aplicación en uso el tipo de mensaje generado, la aplicación es responsable de responder a estos mensajes generando a su vez otros mensajes que se envían a Windows para que los canalize al dispositivo de salida, sea pantalla de monitor, impresora o de otro tipo. Esto es muy importante y a la vez es la parte más difícil de asimilar en la programación para Windows siendo en este caso la práctica la mejor aliada para comprender este apasionante concepto de programación, si en este momento no entiende el mecanismo de intercambio de mensajes no se preocupe mucho, es cosa de constancia y de abordar un concepto a la vez, de esta manera en cosa de unos seis meses de programación se sentirá Usted mucho mejor al manejar estos conceptos, insisto, la práctica es el mejor camino para lograr el éxito en programación Windows.
Como yá dijimos, la clase de ventana define características generales de una ventana, cuando creamos una ventana especificamos las características particulares de esa ventana y la hacemos utilizando la función CreateWindow, ésta función requiere que todas las características de la ventana en cuestión se pasen como parámetros a la función, ésta devuelve el manejador de la ventana hwnd, la instrucción en detalle es como sigue:


hwnd = CreateWindow(szAppName,    // Nombre de la aplicación
       "Título de la aplicación", // Texto en la barra de título
       WS_OVERLAPPEDWINDOW,       // Estilo de ventana
       CW_USEDEFAULT,             // Posición x inicial
       CW_USEDEFAULT,             // Posición y inicial
       CW_USEDEFAULT,             // Tamaño x inicial
       CW_USEDEFAULT,             // Tamaño y inicial
       NULL,                      // Manejador de ventana padre
       NULL,                      // Manejador de menú de ventana
       hInstance,                 // Manejador de instancia del programa
       NULL);                     // Parámetros de creación

Observe que en el código de ejemplo no comentamos los detalles de los parámetros de la función CreateWindow, considero que una mejor opción para comprender cómo se utiliza cada uno de ellos se dará conforme avancemos en la presentación de los diferentes elementos que conforman una aplicación para Windows, por lo pronto es suficiente decir que el estilo de ventana definido en la función creará una ventana superpuesta con una barra de título, menú de sistema a la izquierda, íconos de minimizar, maximizar y cerrar a la derecha de la barra de título y un borde en la ventana que permite cambiar el tamaño de la misma. Este es un estilo estándar llamado WS_OVERLAPPEDWINDOW. Como mencionamos, la función CreateWindow devuelve un número que se almacena en la variable hwnd de tipo HWND que sirve para identificar en Windows a la ventana, pero además ésta variable es utilizada por una gran cantidad de funciones Windows por lo que es fácil comprender su importancia.
Una vez que tenemos bien definida nuestra ventana lo único que falta es mostrarla en pantalla, para esto llamamos a la función ShowWindow (hwnd, iCmdShow); y también a la función UpdateWindow (hwnd); que sirve para obligar a dibujar el área cliente de la ventana. El área cliente es aquella porción de la ventana que sirve para recibir entrada del usuario y para desplegar salida en pantalla y que no está ocupada por la barra de título. En este momento la ventana ya se ve en pantalla y es cuando se requiere que el programa tome el control para leer la posible entrada por parte del usuario, ya sea por medio del ratón ó por el teclado. Para esto, Windows genera una "cola de mensajes" (es decir el último en entrar es el primero en salir) para cada programa en ejecución, para este fin se provee al código de un bucle para manejar estos eventos:


while (GetMessage (&msg, NULL, 0, 0))
{
    TranslateMessage (&msg);
    DispatchMessage (&msg);
}
return msg.wParam;

Este bucle es el encargado de enviar al procedimiento de ventana a traves de las variables que forman la estructura MSG los diferentes mensajes que el usuario generó al interactuar con la ventana del programa, es en el procedimiento de ventana donde se procesan los diferentes mensajes de acuerdo a su naturaleza y se especifica el código ejecutable de acuerdo a cada mensaje recibido, los mensajes que no interesan al programa en particular se pasan al procedimiento por default de Windows. Desde el punto de vista del programador, la acción principal de una aplicación se desarrolla dentro del procedimiento de ventana, que como ya dijimos, es una función de tipo CALLBACK, es decir, que recibe mensajes provenientes del sistema operativo. En el ejemplo de arriba llamamos a esta función con un nombre totalmente descriptivo aunque bastante largo: Procedimiento_de_ventana. Este tipo de función siempre se define de la siguiente manera:


LRESULT CALLBACK Nombre_de_la_funcion(HWND hwnd, UINT iMsg,
  WPARAM wParam, LPARAM lParam)

Observe que los cuatro parámetros de la función son a su vez los primeros cuatro parámetros de la estructura MSG siendo este el mecanismo por el cual el procedimiento de ventana recibe los mensajes provenientes del bucle de mensajes. El primer parámetro es el manejador de ventana, el segundo parámetro es un número que identifica al mensaje entre tanto los últimos dos parámetros guardan información específica que depende del tipo de mensaje. Lo único que queda es procesar los mensajes, para esto es usual utilizar una instrucción switch y asignar un case para cada mensaje Windows que el programa necesite procesar, que en nuestro ejemplo se procesan solamente los mensajes WM_PAINT y WM_DESTROY.

Volver al principio

Hola mundo

Procesando los mensajes

El mensaje WM_PAINT es muy importante en Windows porque es el que informa al programa cuándo una parte o toda el área cliente de una ventana es "no válida" y por lo tanto se requiere dibujarla, esto sucede entre otros casos cuando la ventana se crea por primera vez, cuando se cambia el tamaño de la ventana, cuando se superponen unas ventanas sobre otras, etc. El procedimiento de ventana suele empezar con una llamada a la función BeginPaint que devuelve un "manejador a un contexto de dispositivo" hdc y termina llamando a la función EndPaint que libera el manejador del contexto de dispositivo. Un contexto de dispositivo es un número que el sistema operativo le asigna por ejemplo, al monitor de la computadora. Ambas funciones tienen como parámetros el manejador de la ventana hwnd y un puntero a una estructura de tipo PAINTSTRUCT que se encarga de almacenar alguna información necesaria para dibujar en el área cliente de la ventana. En el ejemplo también se utiliza la función GetClientRect que nos sirve para determinar las coordenadas del área cliente de la ventana, ésta información se almacena en una estructura de tipo RECT, con todos estos elementos llamamos a la función DrawText que como su nombre lo indica, sirve para dibujar texto, el primer parámetro de la función es el contexto de dispositivo, es decir es la manera en cómo se entera el programa que la cadena de texto especificada en el segundo parámetro se debe dibujar en el monitor de la computadora, el tercer parámetro se especifica a -1 para indicar que la cadena de texto termina con un carácter nulo, el cuarto parámetro es simplemente un puntero a la estructura que contiene las coordenadas del área cliente, el último parámetro esta constituido por una serie de "flags" (banderolas) especificadas en los archivos de cabecera de Windows y que sirven para posicionar el texto en el área cliente de la ventana.
En el procedimiento de ventana también especificamos procesar el mensaje WM_DESTROY, nuestro programa responde a este mensaje llamando a la función PostQuitMessage (0), como su nombre nos revela, esta función coloca en la cola de mensajes un mensaje WM_QUIT especificando como parámetro el número cero, si observamos el bucle de mensajes podemos apreciar que se utiliza la función GetMessage, ésta devuelve un valor distinto de cero para cualquier mensaje excepto WM_QUIT, en presencia de éste mensaje, GetMessage devuelve cero y esto ocasiona que el programa salga del bucle terminando así la ejecución del programa destruyendose por lo tanto la ventana de la aplicación.

Como puede ver, programar para Windows requiere asimilar conceptos que no se manejan en la programación convencional de C, existe cierta cantidad de código común a todas las aplicaciones Windows que generalmente existe dentro de la función WinMain en tanto que la acción propiamente dicha de una aplicación en particular reside en el procedimiento de ventana que es el lugar donde se procesan los mensajes que Windows envía a la aplicación, el ejemplo que mostramos en esta primera lección pretende simplemente introducir el código redundante de la función WinMain y demostrar la funcionalidad del procedimiento de ventana, esto constituye meramente el primer paso de un camino francamente largo, pero apasionante y muy rico en experiencia ganada como programador, esto sin contar que practicamente en la actualidad la programación para el entorno MS-Windows domina el mercado de la computación personal.
Para concluir la primera lección en programación Windows es importante hacer notar que no cualquier compilador C es adecuado para desarrollar una aplicación Windows, consulte la documentación de su compilador para saber si éste incluye las librerias del Kit de Desarrollo de Windows así como los archivos de cabecera requeridos por este entorno, también es recomendable tener cierta familiaridad con la programación en C y C++ y en el manejo del entorno para desarrollo de aplicaciones (IDE) propio del compilador que utilize, en este sitio no se explicará el manejo del entorno para desarrollo de aplicaciones de ningún fabricante ya que es mi intención mostrar los aspectos propios de la programación para Windows, sin embargo consulte la documentación de su respectivo compilador. Para programar en Windows existe C++ de Borland, Visual C++ de Microsoft, C++ de Symantec y los entornos algo mas automatizados como Visual Basic ya mencionado arriba.
Como siempre, en caso de alguna duda, sugerencia o comentario que desee hacer respecto al trabajo contenido en este Su sitio, siéntase en confianza y utilize el correo electrónico, me dará mucho gusto oir de Usted.

Volver al principio

Hola mundo

© 1998, 1999 Virgilio Gómez Negrete, Derechos Reservados