Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


Sig.

1.7.5  Programación Windows

§1  Sinopsis

Lo que podríamos denominar programación Windows, es decir, la redacción de programas destinados a correr en los Sistemas Operativos de Microsoft, no es un asunto exclusivo de C++. De hecho, estas aplicaciones pueden ser escritas en muchos otros lenguajes [1]. Sin embargo, la programación que podríamos llamar "nativa" de Windows, la que maneja directamente la API, es C. En realidad, y por razón de sus orígenes, la API está escrita y estructurada para ser utilizada desde el lenguaje de K&R, aunque también puede utilizarse C++ para este menester [2]. El resto de lenguajes de alto nivel utilizados en aplicaciones Windows, utilizan una capa ("Layer") de software más o menos gruesa, interpuesta entre la API y el lenguaje en sí.

Esta última aproximación tiene la ventaja de que los detalles sucios y prolijos de la programación a bajo nivel, que exige tratar con la API, quedan más o menos ocultos al programador. De esta forma la programación de aplicaciones resulta más cómoda y rápida. Sin embargo, en determinados casos la ventaja se  transforma en dificultad. Sobre todo, cuando se pretende realizar ciertas operaciones, o controlar determinados detalles cuyo soporte no está del todo previsto, o lo está de forma deficiente en el lenguaje utilizado [7].

Nota:  la posición al respecto puede sintetizarse en las palabras de Mark Finocchio, ingeniero de Microsoft:  "While it's more convenient to program the controls using the Microsoft Foundation Classes (MFC) or Visual Basic, you must know what's happening behind the scenes to really understand how the controls work. SDK programming is more time-consuming, but it gives you power, speed, understanding, and flexibility" .  Microsoft System Journal Julio 1998 "Control Spy Exposes the Clandestine Life of Windows Common Controls".

En lo que sigue comentaremos brevemente los aspectos más notables del esqueleto de una aplicación C/C++ para Windows en su forma nativa. Es decir, utilizando directamente los recursos de la API del Sistema.

§2  Un programa mínimo

El equivalente C/C++ para Windows del conocido "Hola mundo" podría ser algo así:

#include <windows.h>

int WINAPI WinMain (HINSTANCE hT, HINSTANCE hP, LPSTR lp, int nF) {

   MessageBox(NULL, "Hola mundo!", "Mi primer programa", MB_OK);
   return 0;
}

§2.1 Compilación

Antes de entrar en detalles sobre el programa, comentaremos brevemente el proceso de compilación. Los detalles concretos para construir el ejecutable, dependen del compilador ( 1.4.0). En nuestro caso supondremos que tenemos Borland C++ 5.5 para Window 32 en la unidad E: con el siguiente esquema de directorios:

E:\BorlandCPP\Bin Ficheros binarios (.exe y .dll)
E:\BorlandCPP\Include Ficheros de cabecera (.h)
E:\BorlandCPP\Lib Librerías (.obj y .lib)

Suponiendo que el fuente anterior lo tenemos en D:\LearnC\main.cpp, utilizando una ventana DOS de Windows, nos situamos en el directorio de trabajo (donde reside el fuente):

C:\Windows>D:
D:\>cd LearnC
D:\LearnC>

A continuación establecemos el camino de búsqueda ("Path"), de forma que nuestras órdenes encuentren los binarios correspondientes:

D:\LearnC>set PATH=E:\BorlandCPP\Bin;C:\WINDOWS;C:\WINDOWS\COMMAND;%path%

Hecho esto, ya podemos compilar con la orden:

bcc32 -IE:\BorlandCPP\Include -LE:\BorlandCPP\Lib -P -RT -c main.cpp

bcc32.exe es el compilador; el significado de los argumentos es el siguiente [3]:

-P  Compilar como C++ con independencia de la extensión del fuente (.c; .cpp etc)

-c  Solo compilar

-RT  Incluir información RTTI.

 Después de algunos mensajes de aviso, anunciando que los parámetros hT, hP, lp y nF de WinMain no son utilizados, se produce el objeto correspondiente (main.obj) en el directorio de trabajo.  La orden al enlazador para que construya un ejecutable Windows32 es la siguiente:

ilink32 -LE:\BorlandCPP\Lib -c -Gn -aa -Tpe c0w32.obj main.obj, , , import32.lib cw32.lib

ilink32.exe es el enlazador. El significado de los argumentos [4]:

/aa  Construir una aplicación Windows 32-bit

/c  Interpretar mayúsculas/minúsculas ("case") como significativo en los símbolos

/Gn Desabilitar enlazado incremental

Fig. 1

/Tpe Construir un ejecutable .EXE

El resultado es la creación del fichero c0w32.exe en el directorio de trabajo con nuestra aplicación.  Al ejecutarlo, aparece en el escritorio una ventana como la de la figura adjunta. Pulsando sobre el botón OK, el proceso termina y se cierra la ventana.

§2.2  Comentario

En los entornos gráficos, como pueden ser Windows de Microsoft, KDE de Linux, o Mac OS de Apple, un icono o una ventana, representan la metáfora de un proceso. En el caso de la ventana, se trata siempre de un proceso en ejecución, que en el caso del escritorio (la ventana maestra), representa el proceso que controla la interacción (interfaz) del usuario con el Sistema. Esta ventana es creada automáticamente al arrancar el Sistema y sirve de base para las ventanas del resto de aplicaciones. Todas las demás son "hijas" de este proceso maestro. Por lo general, cada aplicación de usuario (procesador de textos, hoja de cálculo, cliente de correo, etc. etc.) crea su propia ventana, que deriva del escritorio ("main window" de la aplicación), que a su vez puede crear otras ventanas-hijas (aquí se denominan "child windows") de las que existen tipos muy diversos.

Las aplicaciones Windows suelen incluir distintas ventanas-hijas, algunas de las cuales reciben nombres especiales.  Por ejemplo, la "main window" de una aplicación suele incluir las siguientes: barra de título ("title bar"); barra de menú; ventana de menú ("system menu"); botones de minimizar, maximizar; restaurar y cerrar; barras de desplazamiento horizontal y vertical ("scroll bars") y área de cliente ("cliente area"). 

Nota:  en realidad, en Windows, casi cualquier cosa se materializa en una ventana. Por ejemplo, en la figura 1, el botón etiquetado "OK" es una child window de la ventana principal.

Otra cuestión destacable respecto a las ventanas, es que pueden ser clasificadas en dos grandes grupos según su comportamiento respecto a la ventana ascendiente o propietaria (que las ha creado); se denominan respectivamente ventanas modales y no modales ("modeless").  Las ventanas modales deben ser cerradas para que la aplicación anfitriona pueda continuar su ejecución. Diríamos que retienen el foco hasta que son cerradas. Son, por ejemplo, esos mensajes de aviso que no dejan hacer nada más en la aplicación hasta que se han cerrado. En cambio, las ventanas no modales (modeless), permiten cambiar el foco a cualquier otra ventana, incluyendo su propia ascendiente, antes de que ellas mismas sean terminadas. Por ejemplo, esas ventanas de encontrar/reemplazar en los editores, que permiten escribir en el texto original mientras la ventana aparece superpuesta.

Nota: existe una variedad de las modales, las denominadas modales de sistema ("System modal"), que no permiten hacer nada más, ni siguiera pasar a otra aplicación, mientras que se han cerrado.  Serían por ejemplo esas ventanas de aviso de situaciones críticas, que deben ser cerradas para poder seguir usando el sistema. 


Además de su tradicional función de "salida" de datos, propia de las aplicaciones modo texto (de consola), la ventana de las aplicaciones gráficas es también un dispositivo de entrada de datos para el proceso correspondiente. Esta entrada puede realizarse con auxilio del ratón; con un lápiz (señalador), o directamente con el dedo en el caso de las pantallas táctiles [5].  Esta neva forma de interacción, ha desarrollado nuevos paradigmas que son ya de dominio público. Por ejemplo, el de apuntar y marcar ("Point and click"), o el de arrastrar y soltar ("Drag and drop"). En nuestro caso, debido al diseño esquelético de la aplicación, la funcionalidad de su ventana es mínima. Se reduce a la posibilidad de arrastrarla a cualquier punto del escritorio, y a cerrarla (terminar la aplicación) pulsando con el ratón en su único botón.

Desde el punto de vista de la programación C/C++, el primer punto a destacar, es el fichero de cabecera empleado: <windows.h> [6]. Es típico de las aplicaciones Windows y básicamente se encarga de incluir otros ficheros de cabecera adicionales. Sus nombres pueden variar según el compilador, pero por ejemplo, son comunes <stdarg.h>; <windef.h>; <winbase.h>; <wincon.h>; <wingdi.h>; <winuser.h>; <winnls.h>; <winver.h> entre otros.

La siguiente singularidad es la inexistencia de función main ( 4.4.4). En su lugar se utiliza WinMain con el mismo propósito. Los programas que deban correr bajo Windows utilizando la API de su interfaz gráfica (GUI), requieren que el módulo de inicio invoque una función con este nombre en sustitución de la tradicional main (en realidad, es un "capricho" de los diseñadores de Redmond).

La función WinMain, que representa el punto de entrada a estas aplicaciones, acepta un cierto número de parámetros que tampoco se corresponden con los usuales de main. Por ejemplo, el primer argumento no es "argument count", ni el segundo una matriz de punteros a carácter . Naturalmente esto se aparta del Estándar C++, y representa otra de las peculiaridades establecidas por Microsoft para su Sistema Operativo.

Nota: estos parámetros son los mismos en las aplicaciones Windows de 16 bits que en las de 32 bits.

Al programador habitual de C/C++ estándar, también le llaman de inmediato la atención la cantidad de "tipos" particulares que aparecen en el fuente. En nuestro ejemplo encontramos 3 de ellos:  WINAPI; HINSTANCE y LPSTR. Se les identifica fácilmente porque, como es usual en C/C++, están en mayúsculas (WINAPI no es un "tipo" sino una convención de llamada para la función 4.4.6a). El asunto es que la programación Windows ha consagrado su propio estilo de notación con dos particularidades: la primera es la notación húngara para las variables ( 3.2.2). Aunque su adopción no es obligatoria, representa una gran ayuda una vez habituados a ella. La segunda es la utilización de sus propios identificadores para los tipos, mediante los correspondientes typedef y #define incluidos en los ficheros de cabecera ( Ejemplos).

Es igualmente característica de la programación Windows la profusión de constantes manifiestas ( 1.4.1a). Se identifican porque también están en mayúsculas, y porque su tercer o cuarto carácter suele ser el guión bajo ("underscore"); en nuestro caso es MB_OK. Tales constantes se suelen emplear como argumentos de funciones que, como es el caso de MessageBox, que representan la invocación de utilidades y funcionalidades de la GUI. Estas funciones se encuentran alojadas en librerías dinamicas (.dll) que son enlazadas junto con la aplicación. En la mayoría de los casos estas constantes representan valores numéricos enteros, y su nomenclatura se ajusta a ciertas pautas, de forma que las del mismo tipo tienen el mismo prefijo. A continuación se muestran algunas:

Prefijo  Uso
CS_ Definición de estilo de ventana
CW_ Opciones de ventana
DT_ Opción de dibujo de texto
IDI_ Tipo de icono
IDC_ Tipo de cursor
MB_ Opciones de ventana de mensaje
SB_ Eventos ocurridos en las barras de deslizamiento ("Scroll Bars")
WM_ Mensaje del Sistema (Windows) a la aplicación 
WS_ Estilo de ventana

Por ejemplo, el último argumento de MessageBox indica el estilo de la ventana, incluyendo las imágenes que pueden incluirse; los botones; cual de ellos estará activado por defecto (caso de haber más de uno) y otros detalles. Por ejemplo, respecto a MessageBox, el manual de la GUI señala lo siguiente (es un resumen del original inglés):

Valores relativos a los botones:

MB_ABORTRETRYIGNORE  The message box contains three push buttons: Abort, Retry, and Ignore.

MB_OK  The message box contains one push button: OK. This is the default.

MB_OKCANCEL  The message box contains two push buttons: OK and Cancel.

MB_RETRYCANCEL  The message box contains two push buttons: Retry and Cancel.

MB_YESNO  The message box contains two push buttons: Yes and No.

MB_YESNOCANCEL  The message box contains three push buttons: Yes, No, and Cancel.

Valores relativos a los iconos que se incluirán en la ventana:

MB_ICONEXCLAMATION  An exclamation-point icon appears in the message box.

MB_ICONINFORMATION,  An icon consisting of a lowercase letter i in a circle appears in the message box.

MB_ICONQUESTION A question-mark icon appears in the message box.

MB_ICONSTOP,  A stop-sign icon appears in the message box.

Valores relativos al botón por defecto:

MB_DEFBUTTON1 The first button is the default button.

MB_DEFBUTTON2 The second button is the default button.

MB_DEFBUTTON3 The third button is the default button.

MB_DEFBUTTON4 The fourth button is the default button.

Fig. 2

Etc.

En ocasiones, como la presente, estos valores no son excluyentes, de forma que pueden combinarse para conseguir el comportamiento deseado. Esto se realiza componiendo el valor resultante mediante una expresión OR inclusivo de los valores individuales ( 4.9.3). En nuestro caso hemos utilizado un solo argumento (MB_OK) que además es el valor por defecto. Pero podríamos utilizar una valor compuesto.  Por ejemplo, utilizar la siguiente invocación:

MessageBox(NULL, "Hola mundo!", "Mi primer programa",
           MB_YESNOCANCEL | MB_ICONSTOP | MB_DEFBUTTON3);

Cambiando la invocación a MessageBox en el fuente original y compilando de nuevo, se produce la ventana de la figura 2.

  Inicio.


[1]  En concreto, además de C/C++, para el desarrollo de aplicaciones han tenido notable éxito dos de ellos: Visual Basic (un producto de Microsoft) y Delphi un dialecto de Pascal, de Borland-Imprise.  Debemos advertir no obstante, que la mayoría de aplicaciones de cierto porte, están construidas en C++.

[2]  El que pueda ser utilizada desde C++, se debe a que este lenguaje es compatible hacia atrás con C. No porque la API esté diseñada para ser utilizada desde lenguajes orientados a objetos.  De hecho, para utilizarla cómodamente desde C++, utilizando los recursos de la POO, Microsoft ha desarrollado un extenso conjunto de clases que encapsulan la funcionalidad de la API de Windows bajo una envoltura ++. Este conjunto de clases, que acompañan a la familia de compiladores Visual C++ de Microsoft como una librería añadida, es conocida abreviadamente como MFC ("Microsoft Foundation Class Library").

[3]  El compilador Borland C++ 5.0 para Windows, dispone de un total de 136 opciones de compilación distintas. Consulte el manual "Command-line Tools" al respecto (fichero ...\BorlandCPP\Help\bcb5tool.hlp).

[4]  El enlazador ilink32.exe, que acompaña al compilador Borland C++ 5.0, dispone de un total de 55 opciones distintas. Consulte el manual al respecto (señalado en la nota anterior).

[5]  Actualmente, no solo el teclado y la pantalla sirven como dispositivos de entrada de datos a la aplicación desde el operador (humano). También se utilizan otras vías. Por ejemplo, la voz. Se han desarrollado incluso dispositivos que leen el movimiento de los ojos como ayuda a personas con discapacidad.

[6]  Debido a las especiales características de su diseño, este fichero de cabecera debe ser incluido en el fuente antes que ningún otro.

[7]  A este respecto, en la página adjunta puede encontrar una opinión relativa a la utilización de las MFC    MFC Considered Harmful to Programmers

Sig.