Вы находитесь на странице: 1из 51

Capítulo 1

LEAME.TXT

Este es un libro para gente familiarizada con el lenguaje de programación C que desea
aprender a escribir aplicaciones para el sistema operativo Microsoft Windows 95. Conocer el
lenguaje C es uno de los tres requisitos para utilizar este libro. El segundo es que haya
instalado Microsoft Visual C++ 4.0 para desarrollo de 32 bits. El tercero es que usted
realmente trabaje con Windows y comprenda los fundamentos de su interfaz de usuario.
Como probablemente ya sabrá, Windows 95 es la encarnación más reciente de un sistema
operativo gráfico introducido por primera vez en noviembre de 1985 para ejecutarse en
máquinas IBM PC y compatibles. En términos de penetración de mercado, Windows casi ha
barrido completamente a la competencia que pudo haber tenido en la década pasada y se ha
convertido en el estándar de facto para PC. Hoy en día, si usted está escribiendo un
programa para PC, está escribiendo un programa para Windows.

Piense en este capítulo como su primer día de clase. A pesar de la tendencia de algunos
profesores en comenzar inmediatamente con el contenido más abrupto del material del
curso, la mayoría de nosotros prefiere una introducción más relajada. Por tanto, en este
capítulo explicaré algunas características históricas de Windows, las reglas básicas de este
libro e, incluso (y espero que sea indulgente conmigo), haré un breve comentario sobre mi
persona y cómo se escribió este libro.

No puedo, sin embargo, garantizar que este capítulo vaya a estar totalmente libre de
preocupaciones. Usted es un programador, usted es un ingeniero de software y, como
cualquier otro ingeniero, su papel es afrontar (y, por suerte, a menudo satisfacer) el difícil
trabajo de convertir el mundo en un lugar más cómodo. Usted está construyendo carreteras y
puentes que acercan a la gente a sus lugares de destino y estas estructuras tienen que ser
robustas, sólidas y rápidas.

EL RETO DEL PROGRAMADOR

En la película Grand Canyon, un padre está ayudando a su hijo de 15 años a aprender a


conducir y le hace esta observación: «Girar a la izquierda en Los Angeles es una de las1
cosas más dificiles que vas a aprender en tu vida». Podría haber dicho lo mismo sobre la
programación para Windows.

No estoy hablando específicamente de los mecanismos de la programación para Windows.


Comenzaré con este espinoso tema en el próximo capítulo. Estoy pensando más en una
filosofía de diseño de programas basada en centrar todos los esfuerzos en hacer las cosas
más fáciles para los usuarios. Este es relativamente un nuevo concepto.
Al principio, los únicos usuarios de las computadoras eran los programadores. Los
programas más antiguos absorbían un conjunto de datos, se entretenían un tiempo con ellos
y luego soltaban alguna salida impresa en papel. Los usuarios principiantes simplemente no
se tenían en cuenta. Incluso cuando los programas llegaron a ser algo más interactivos y
presentaron un indicador de línea de órdenes en un teletipo o una pantalla de vídeo, se
esperaba que los usuarios recordaran órdenes y opciones críticas y poco expresivas.

Quizá la revolución real en el diseño de programas comenzó con los primeros procesadores
de texto interactivos (por ejemplo, WordStar) y hojas de cálculo interactivas (VisiCalc), que
incorporaban formas primitivas del elemento más fundamental en el diseño actual de
interfaces de usuario. Se trata, por supuesto, del menú. El menú en estas primeras
aplicaciones interactivas no estaba bien implementado, pero la idea estaba presente y
lentamente el menú fue haciéndose cada vez más complejo y sofisticado. Mirando hacia
atrás, el menú parece obvio: presenta todas las opciones del programa para que el usuario
pueda activarlas. Por supuesto, en los primeros momentos, la falta de memoria limitaba al
programador impidiéndole diseñar una buena interfaz de usuario. Los programas poco
1
Por ejemplo, el entorno gráfico GEM (Graphical Environment Manager) de Digital Rescareh, en el cual se
ejecutaban las primeras versiones de Ventura Publisher. (N. del T.)

1
amigables con el usuario son más cortos y fáciles de escribir; los programas con una interfaz
de usuario cuidada son más grandes y más difíciles de escribir. En este caso se puede
aplicar el refrán «No es oro todo lo que reluce». Alguien tiene que hacer el trabajo sucio. Y
como programador, usted ha elegido ser esa persona.

Afortunadamente, una buena parte de este duro trabajo ya ha sido hecho para usted por los
diseñadores y programadores del sistema operativo Microsoft Windows.95. Estos héroes
desconocidos han implementado mucho del código requerido para crear objetos modernos
de interfaz de usuario y visualizar la salida del programa usando texto con formato
enriquecido y gráficos. Sin embargo, para hacer esto también tuvieron que crear
necesariamente una completa interfaz de programación de aplicaciones (API: Application
Programming Interface) que puede intimidar bastante a los programadores que se asoman a
Windows por primera vez. Esto no es exclusivo de Windows 95: es cierto en cualquier
interfaz de usuario moderna.

Normalmente, se establecía que un programador necesitaba aproximadamente 6 meses


para trabajar cómodamente en la programación de Windows. (Yo a menudo bromeo que
utilizando mi libro este tiempo puede reducirse a 26 semanas o, incluso, 180 días.) Windows
ha aumentado su complejidad en los últimos anos, pero también hay disponibles
herramientas que le ayudarán en las partes más difíciles, por tanto, la regla de los seis
meses probablemente todavía se puede aplicar.

Le comento todo esto porque no deseo que se sienta infravalorado profesionalmente o


incapaz mentalmente si no consigue aprender todo en poco tiempo. Si usted se asoma

por primera vez a la programación para entornos gráficos, Windows puede ser muy
extraño. Y se va a dar cuenta de ello.

LAS REGLAS BASICAS

Lo que voy a enseñarle en este libro es lo que yo considero una programación «clásica»
de Windows. Utilizo el simple y viejo lenguaje C (no C++) y utilizo directamente la
interfaz de programación de aplicaciones (API) en vez de cualquier «envoltorio» que
oculte la API bajo una interfaz más fácil. A pesar de los avances en Windows 95 frente
a las primeras versiones de Windows, la mayoría de los programas de este libro no
parecen muy diferentes de los programas que se podrían haber escrito (y se escribieron)
hace 10 años para Microsoft Windows versión 1.0.
En un sentido, este libro muestra el camino más duro para la programación Win
dows, pero es también el camino más básico, fundamental, versátil y potente. Literal
mente, usted no puede hacer nada más con Windows utilizando otros enfoques. Al con
trario, aprendiendo la programación clásica de Windows a través de C y las API, puede
entender más claramente cómo interáctúan Windows y su aplicación, y esto a menudo
puede ser un conocimiento muy útil. Este enfoque establece unos conceptos básicos que
usted nunca rechazará. Creame.
Aunque enseño programación Windows clásica, no le recomiendo necesariamente
que se limite a ella. En la actualidad, usted tiene varias opciones que facilitan la progra
mación Windows. Una opción popular es C++, generalmente usada en conjunción
con librerías de clases como Object Windows Library (OWL) de Borland o Microsoft
Foundation Classes (MFC). Otras opciones son Visual Basic de Microsoft y Delphi de
Borland. También hay disponibles productos generadores de código que hacen por usted
el trabajo repetitivo en la programación Windows. Incluso puede crear aplicaciones
Windows utilizando lenguajes de instrucciones sencillas (seripts) como ToolBook de
Asymetrix.

No puedo decirle cuál de estas opciones es la mejor; realmente depende de la aplica


ción que esté escribiendo y cuánto está dispuesto a sacrificar aislándose de¡ entorno.
Otro tema que no se explica en este libro es el uso de los entornos de desarrollo
integrados (IDE: Integrated Development Environment), tal como Microsoft Visual C++
versión 4.0. Estos entornos le suelen ayudar creando recursos (por ejemplo, menús y
cuadros de diálogo), generando archivos make y ofreciéndole un entorno común en el
cual puede escribir, compílar, ejecutar y depurar su código. No tengo nada en contra de

2
los IDE. Pienso que son buenos. Sin embargo, sus tareas a menudo ocultan en vez
de ayudar a aprender la programación clásica de Windows. En pocas palabras, no deseo
enseñarle cómo aprender a crear cuadros de diálogo en un IDE, en vez de eso lo que
deseo es enseñarle a diseñar sus propios cuadros de diálogo y gestionar el proceso de
entrada de información en ellos.
Por esta razón, el código en este libro se muestra como si se creara en un editor
de textos corriente y el programa se compilase desde la antigua línea de órdenes del
MS-DOS. Esto será más obvio cuando el tema a tratar sean los scripts de recursos, que

contienen descripciones de texto de los menús de sus programas, cuadros de diálogo y


otros recursos. Los scripts de recursos de este libro están escritos para ser legibles, lo que
no ocurre normalmente en los scripts de recursos generados por un IDE. Yo hago esto
porque deseo que usted comprenda lo que significan las instrucciones de un script de
recursos. Los archivos make (aquellos que contienen las instrucciones que compilan y
enlazan su programa para crear un ejecutable) son notablemente largos y complejos
cuando se generan por un IDE. Los míos son más simples y cortos, ¡y no me disculpo por
ello! Los únicos recursos de tipo no-texto de este libro son ¡conos, cursores de ratón e
imágenes bitmap, que por su naturaleza especial requieren herramientas para crearlos.
La ventaja de este enfoque es que usted puede simplemente copiar los archivos con
el código fuente a su disco fijo---abrir una ventana con la línea de órdenes MS-DOS, eje
cutar el archivo make para crear un ejecutable y luego activar el ejecutable fuera de la
línea de órdenes.
La mayoría de los programas de este libro son muy cortos, diseñados para demostrar
uno o dos conceptos importantes. En otros casos, se diseccionan para descubrir sus ele
mentos esenciales. Los programas son herramientas de ensenanza y no modelos para
programas Windows completos. Por ejemplo, cualquier programa Windows real debe
tener un único icono, mientras que muy pocos de mis programas hacen esto porque
simplemente sería más confuso. También, es recomendable que las cadenas de texto
usadas en un programa se pongan en un script de recursos para facilitar la traducción a
lenguajes diferentes. De nuevo, hacer esto añadiría más confusión y dificultaría la expli
cación del punto que pretendo enseñar. Mi experiencia me indica que cuanto más corto
sea un programa, más fácil será para un lector estudiarlo cuidadosamente.
Este libro no puede cubrir todos los aspectos de la programación para Windows 95.
Tampoco es el sustituto de la documentación oficial. Después de asimilar el contenido
de este libro, seguramente gastará muchas horas leyendo documentación sobre llamadas
a funciones y características de Windows 95.
La regla básica final para escribir este libro (y que usted debe asumir) es que no voy
a investigar nada sobre aspectos no documentados o no autorizados de la programación
para Windows 95. Aunque esta información suele ser interesante, no pienso que sea muy
significativa excepto para las aplicaciones Windows más extrañas. A medida que he
madurado como programador, he intentado cada vez más no depender de los detalles de
implementación porque pueden cambiar en versiones futuras del sistema operativo. He
preferido considerar el conjunto de funciones API como si estuvieran completamente
descritas por la documentación técnica. Por supuesto, este no es siempre el caso y siem
pre hay algunas cuestiones que la documentación técnica «oficial» no puede resolver.
Por otra parte, también pueden existir errores (bugs). No ignoraré estos problemas.

UNA BREVE HISTORIA DE WINDOWS

Poco después de la introducción del IBM PC en otoño de 198 1, llegó a ser evidente que
el sistema operativo predominante para el PC (y compatibles) sería MS-DOS, cuyas

Léame. TXT 7

siglas vienen de MicroSoft Disk Operating System (sistema operativo de disco de Mi


crosoft). Las primeras versiones de MS-DOS proporcionaban al usuario una iliterfaz
basada en una línea de órdenes, con órdenes como DIR y TYPE, que era capaz de cargar
programas en memoria para su ejecución y ofrecía servicios a estos programas para
acceder a archivos, leer el teclado y escribir al sistema de vídeo (sólo en modo carácter)
y al puerto de impresora,

3
Debido a las limitaciones impuestas por memoria y hardware, los entornos gráficos
sofisticados se desarrollaron lentamente. Apple Computers demostró una alternativa posible
cuando anunció su malogrado Lisa en enero de 1983, y luego definió un estándar para
entornos gráficos con el Macintosh en enero de 1984, el cual (a pesar de su pequeña
cuota de mercado) todavía es considerado el estándar con el cual se miden y comparan
los restantes entornos gráficos.
Windows fue anunciado por Microsoft Corporation en noviembre de 1983 (después
de Lisa y antes de Macintosh) y comenzó a venderse dos años más tarde en noviembre de
1985. Durante los dos años siguientes, la versión Microsoft Windows 1.0 fue seguida de
varias actualizaciones para soportar el mercado internacional y proporcionar controla
dores adicionales de adaptadores de vídeo e impresoras.
Windows versión 2.0 apareció en noviembre de 1987. Esta versión incorporaba
varios cambios en la interfaz de usuario. El más significativo de estos cambios era la
utilización de ventanas superpuestas en vez de las ventanas en cascada de Windows 1.x.
Windows 2.0 también incluía mejoras al teclado y a la interfaz del ratón, particularmente
para menús y cuadros de diálogo.
Hasta este momento, Windows sólo requería un mieroprocesador Intel 8086 u 8088
trabajando en «modo real» para acceder a 1 megabyte (MB) de memoria. Windows/386
(comercializada poco después de Windows 2.0) utilizaba el «modo virtual 86» del mi
eroprocesador 80386 para ejecutar en una ventana y en multitarea algunos programas
MS-DOS que acceden directamente al hardware. Por simetría, Windows versión 2.1 fue
renombrada como Windows/286.
Windows versión 3.0 apareció el 22 de mayo de 1990. Las antiguas versiones Win
dows/286 y Windows/386 se fusionaron en un producto con esta nueva actualización. El
gran cambio en Windows 3.0 era el soporte del modo protegido de los microprocesado
res Intel 80286, 80386 y 80486 2 . Esto dio a Windows y a las aplicaciones Windows
acceso hasta a 16 MB de memoria. Los programas del shell de Windows para ejecutar
programas y mantener archivos fueron completamente reconstruidos. Windows 3.0 fue
la primera versión común en las computadoras de los usuarios, tanto en casa como en la
oficina.
Windows versión 3.1 apareció en abril de 1992. Varias características significativas
eran la tecnología de fuentes TrueType (que trajo a Windows fuentes de contorno esca
lables), multimedia (sonido y música), OLE y cuadros de diálogo comunes. Además,

' Desde hace varios años, Intel suprimió los dígitos «80» en el nombre de los
mieroprocesadores, que
son más conocidos como 286, 386 y 486. (N. del T)

8 Introducción

Windows 3.1 se ejecutaba sólo en modo protegido y requería un procesador 80286


y 80386 con un mínimo de 1 MB de memoria.
Cualquier historia de Windows debe incluir también una mención a OS/2, una alter
nativa a DOS y Windows que fue desarrollado originalmente por Microsoft en colabora
ción con IBM. OS/2 1.0 (sólo en modo carácter) se ejecutaba en un mieroprocesador
Intel 80286 (o superior) y apareció a finales de 1987. El entorno gráfico Presentation
Manager (PM) llegó con OS/2 versión 1.1 en octubre de 1988. PNI fue diseñado ori
ginalmente para ser una versión en modo protegido de Windows, pero la API gráfica
fue cambiada de tal forma, que para los fabricantes de software resultaba muy difícil
contemplar las dos plataformas.
En septiembre de 1990, los conflictos entre IBM y Microsoft alcanzaron su punto
más álgido y el resultado fue que las dos compañías emprendieron su camino de forma
independiente. IBM tomó el control sobre OS/2 y Microsoft convirtió a Windows en el
centro de su estrategia para los sistemas operativos. A pesar de que OS/2 todavía tiene
fervientes admiradores, no ha conseguido la inmensa popularidad de Windows.
Windows NT, presentado en julio de 1993, fue la primera versión de Windows en
soportar el modelo de programación de 32 bits de los microprocesadores Intel 80386,
80486 y Pentium. Windows NT tiene un espacio de direcciones plano de 32 bits y ente
ros de 32 bits. Windows NT también es transportable y se ejecuta en varias estaciones de
trabajo RISC.
Windows 95 (cuyo nombre beta fue Chicago y también se llegó a conocer como

4
Windows 4.0) apareció en agosto de 1995. Igual que Windows NT, Windows 95 también
soporta un modelo de programación de 32 bits (por tanto, requiere un microprocesa
dor 80386 o superior). Aunque carece de algunas características de Windows NT, como
una amplia seguridad y transportabilidad a máquinas RISC, Windows 95 tiene la ventaja
de ejecutarse en máquinas con sólo 4 MB de memoria.
Obviamente, los programas escritos para las versiones Windows de 16 bits anteriores
a Windows NT y Windows 95 normalmente no son transportables de una forma automá
tica y transparente a las nuevas versiones Windows de 32 bits (en los próximos capítulos
haré algunas consideraciones necesarias para crear aplicaciones transportables).
Microsoft ha intentado distinguir sus diferentes plataformas definiendo un conjun
to de API (librería de funciones). La API Win 16 es la que utiliza Windows 3. 1. La API
Win32 que es la que utiliza Windows NT y Windows 95. Pero espere, hay más. Micro
soft permitió a los programadores escribir aplicaciones de 32 bits para Windows 3. 1; las
llamadas a funciones de 32 bits se traducían en llamadas de 16 bits mediante una librería
de enlace dinámico (DLL) '. La API se llamó Win32s («s» de «subconjunto» porque la
API solamente utilizaba funciones en Winl6). También, en un momento la API de Win
dows 95 fue llamada Win32c («c» de «compatible»), pero este término ha sido abando
nado.

1 En la documentación de Microsoft en castellano se utiliza el término «biblioteca de vínculo


dinámi
co» como traducción de DLL. He preferido emplear la expresión «librería de enlace
dinámico» por estar
más extendida entre la comunidad de programadores. (N. del T.)

Léame. TXT 9

En el momento actual, Windows NT y Windows 95 utilizan la API Win32. Sin


embargo, cada sistema operativo posee algunas características no soportadas por el otro.
Los aspectos comunes son considerables, por tanto es posible escribir programas que se
ejecuten en ambos sistemas operativos. También, ya está ampliamente asumido que en el
futuro los dos productos se fusionarán en un unico programa.

UNA BREVE HISTORIA DE ESTE LIBRO

A principios de 1988, la primera edición de Programming Windows fue uno de los pri
meros libros en programación Windows que llegó a las librerías. Mientras me preparaba
para revisar Programming Windows para Windows 95, advertí que 1995 era el décimo
aniversario de Windows y, por tanto, el décimo aniversario de los orígenes de este libro
Este hecho es a la vez estimulante y un poco preocupante.
Cuando recuerdo la historia de este libro, advierto que debo mucho a mi asociación
con mucha gente maravillosa de la industria informática. Así es cómo empezó.
En la primavera de 1985 colaboraba de forma independiente escribiendo artículos
en PC Magazine y pasaba mucho tiempo por sus oficinas en One Park Avenue en Nueva
York. En varias ocasiones nos visitó Steve Balimer de Microsoft (ahora vicepresidente
ejecutivo de ventas y soporte), que nos mostraba la última versión beta de un producto
conocido como Windows. Aquellos de nosotros interesados en Windows nos trasladába
mos a la oficina del editor senior John Dickinson para analizarlo. John era uno de los
pocos compañeros de PC Magazine que tenía una EGA en su máquina y que, por tanto,
podía ejecutar Windows en color. Jugábamos con estas primeras versiones de Windows
durante algún tiempo (normalmente, hasta que nos cansábamos de que se quedara col
gado) y luego esperábamos la próxima visita de Ballmer con una versión más estable.
Un día en la primavera de 1985 le pregunté a John Dickinson cómo se podía escribir
un programa que se ejecutara bajo Windows. John rápidamente abrió un cajón de su
escritorio y sacó varios montones de papeles fotocopiados y cerca de 10 disquetes que
Balimer había dejado algunas semanas atrás.
La pila de hojas y disquetes resultó ser la versión prelirninar del primer Windows
Software Development Kit (SDK), completado con un compilador de C. Me llevé el
paquete a casa, instalé el SDK en un disco Bernoulli (en aquel tiempo trabajaba con un
IBM PC de dos dísquetes), e instantáneamente llegué a ser un programador WindoW1s
aproximadamente después de seis meses de confusión total. Mientras realizaba esta ex
periencia de aprendizaje y me peleaba con la documentación, una idea cruzaba conti

5
nuamente mi cabeza: «Yo podría explicar todo esto mucho mejor que lo hace Microsoft».
Windows versión 1.0 apareció finalmente en noviembre de 1985, pero en aquel
tiempo no había forma de predecir que Windows dominaría un día el mercado. Al con
trario, tenía varios competidores, incluyendo TopView de IBM, GEM de Digital Research
y DESQview de Quarterdeck. El tema de portada de la revista PC Magazine del 25 de
febrero de 1985 hablaba de «Window Wars!» (La guerra de las ventanas). Este fue el
primer tema de portada que escribí para la revista, aunque fui relegado a analizar TopView
en vez de Windows.

10 Introducción

Me llevó casi otro año tener la confianza suficiente para explicar la programación
en Windows en un artículo, lo que ocurrió en el número de diciembre de 1986 de Micro
soft Systems Journal. Creo que este escrito, que presentaba una versión primitiva del
programa WHATSIZE que encontrará en el Capítulo 4, es el primer artículo sobre pro
gramación Windows que apareció en una revista. Ocurrió que conocía al primer editor
de MSJ (Jonathan Lazarus) porque había sido vicepresidente en Ziff-Davis, empresa
editora de PC Magazine. Jon posteriormente se fue a trabajar a Microsoft, donde actual
mente desempeña el cargo de vicepresidente de relaciones estratégicas.
Escribir sobre Windows en MSJ llamó la atención de Microsoft Press, pero de una
forma un tanto rocambolesca. Conocí a Tandy Trower (actualmente director de diseño
de interfaces de usuario en Microsoft) en una conferencia de lenguajes de Microsoft en
Redmond, Washington, en octubre de 1986, y le comenté que me gustaba escribir artículos
de programación Windows en MSJ. El dio mi nombre a Susan Lammers, que era editora
jefe de Microsoft Press. La gente de Microsoft Press ya conocia mi nombre porque yo fui
el primer redactor en revisar la infame primera versión de MS-DOS Encyc1opedia e
informar de que contenía numerosos defectos y errores, lo que le hizo entrar en desven
taja en el mercado y catapultó al éxito a la mucho más completa obra de Ray Duncan.
Durante la feria Comdex Fall de noviembre de 1986 en Las Vegas, me reuní con el
editor de adquisiciones Claudette Moore (ahora un agente de libros informáticos en
Massachusetts) y diseñarnos un esquema del libro. Originalmente, Programming Windows
se concibió como un libro mucho más pequeño, dirigido tanto a programadores como a
usuarios avanzados. A medida que iba trabajando en el libro durante el año siguiente (en
el que tuve que cambiar el enfoque de Windows 1.0 a Windows 2.0), creció en tamaño y
amplió sus objetivos.
Lo que usted tiene en sus manos es la cuarta edición de Programming Windows
«Programación en Windows 95». Lo revisé para Windows 3.0 y luego de nuevo para
Windows 3. 1. Desde que el libro se publicó por primera vez, muchos programadores
Windows me han dicho que Programming Windows fue el punto de inicio con el cual se
enfrentaron a un entorno a menudo extraño. Nada podría agradecer más; no necesaria
mente para colmar mi ego, sino porque he ayudado de alguna forma a conseguir que
Windows sea el éxito que actualmente es.

ALGUNOS REQUISITOS

Muy bien, el primer día de clase está llegando a su fin. En el próximo capítulo em
pezaremos viendo algo del código Windows. Para ello, necesita tener instalado Mi
crosoft Visual C++ 4.0. En su archivo AUTOEXEC.BAT necesita incluir la instrucción
siguiente:

CALL \MSDEV\BIN\WVARS32.BAT

Este es un archivo incluido en VC++ que establece las variables de entorno DOS nece
sarias para compilar programas desde la línea de órdenes de MS-DOS. Simplemente

Léame. TXT 11

establece las trayectorias de unidad y directorio para los archivos de cabecera, archivos
de librerías y archivos binarios. También necesitará utilizar una segunda instrucción
CALL en su archivo AUTOEXEC.BAT para ejecutar el archivo por lotes MSC.BAT,
mostrado en la Figura 1-1. También se encarga de definir variables de entorno que se
usan en los archivos make de los próximos capítulos.

6
MSC.BAT
REM ---------------------------------------------------------------
REM MSC.BAT -- inicializar entorno para NMAKE de MS C/C++ 7.0
REM -------------------------------------------------------------
SET CC=cl
SET CFLAGS=-c -DSTRICT -G3 -Ow -W3 -Zp -Tp
SET CFLAGSMT=-C -DSTRICT -G3 -MT -Ow -W3 -Zp -Tp
SET LINKER=link
SET GUIFLAGS=-SUBSYSTEM:windows
SET DLLFLAGS=-SUBSYS'FEM:,,vindows -DLL
SET GUIL,IBS=-DEFAULTLIB:user32.lib gdi32.1ib winrnm.lib coindlg32.lib comctl32.lib
SET RC=re
SET RCURS=-r -DWIN32

Fígura 1-1. Ejecute este archivo para compilar los programas de este libro.

El archivo MSC.BAT se puede encontrar en el directorio CAPO I del CD-ROM in


cluido en este libro.
En los próximos capítulos describiré lo que hacen estas instrucciones.

Capítulo 2

Hola, Windows 95

Si usted es nuevo en la programación para un entorno gráfico tal como Microsoft Win
dows 95, probablemente lo encontrará muy diferente de cualquier otra cosa que haya
experimentado. Windows tiene la reputación de ser fácil para los usuarios, pero difícil
para los programadores. Es bastante común para los principiantes quedarse perplejos por
la arquitectura de Windows y la estructura de las aplicaciones que se ejecutan bajo el
sistema. Si le pasa esto, no se asuste pensando que ha perdido una parte vital de su
cerebro necesaria para llegar a ser un buen programador Windows. La confusión inicial
es normal y no permita que alguien le diga que no es así.
La programación Windows es extraña, es misteriosa, es retorcida, es delicada, es
incómoda, es fascinante. No es ni obvia ni evidente y puede pasar algún tiempo antes de
que experimente el deseo de gritar «¡Eureka!». Una estimación común es que los progra
madores tienen que pasar una curva de aprendizaje de 6 meses antes de llegar a estar
cómodo en la construcción de programas Windows, e incluso después de ese plazo, el
aprendizaje nunca termina. Mí única esperanza es que este libro pueda reducir algunas
semanas (o quizá un mes o dos) la curva de aprendizaje típica.
Usted puede estar preguntándose: «Si la programacion Windows es tan dificil, ¿por
qué preocuparse?».
Bien, la respuesta es, «Usted probablemente no tenga elección». Después de todo,
Windows ha alcanzado un éxito tan importante en el mercado de los compatibles PC que
la programación para MS-DOS (utilizando modo texto u modo gráfico) ya no es rentable
ni recomendable. Si usted escribe aplicaciones comerciales, los analistas de software de
las revistas de informática prácticamente ignorarán su producto si no está escrito para
Windows 95. Si trabaja en programación especializada para una compañía, sus usuarios
(y sus empleados) se quejarán amargamente si su programa no se integra correctamente
con las aplicaciones Windows que ellos utilizan.
Pero hay mejores razones para elegir Windows como su plataforma.

LA DIFERENCIA WINDOWS
Windows proporciona ventajas significativas tanto a los usuarios como a los programa
dores respecto al convencional entorno MS-DOS. Los beneficios a los usuarios y los

13

7
14 Introducción

beneficios a los programadores son realmente bastante similares porque el trabajo de un


programador es dar a los usuarios lo que ellos necesitan y desean. Windows 95 hace
esto
posible.

Interfaz Gráfica de Usuario (GUI)


Windows es una interfaz gráfica de usuario (GUI: Grapffical User Interface), también
llamada a veces una «interfaz visual» o «entorno gráfico de ventanas». Los conceptos
básicos de este tipo de interfaces datan de la mitad de la década de los setenta, con el
trabajo pionero realizado en el Xerox Palo Alto Research Center (PARC) para máquinas
tales como Alto y Star y entornos como Smalltalk. Este trabajo lo plasmó y popularizó
Apple Computer, Inc. primero en el fracasado Lisa y luego un año más tarde en el mucho
más popular Macintosh, introducido en enero de 1984.
Desde la introducción del Macintosh, las interfaces de usuario gráficas se han ex
pandido como flores salvajes por toda la industria de la informática personal y también
por la industria de la informática no tan personal. Actualmente es bastante obvio que la
interfaz gráfica de usuario es (en palabras de Charles Simonyi de Microsoft) el «gran
consenso» más importante de la industria informática.

Conceptos GUI
Todas las interfaces de usuario gráficas utilizan gráficos en una pantalla de vídeo.
Los gráficos ofrecen mejor utilización de la pantalla, un entorno visual rico para mos
trar información y la posibilidad de un sistema de vídeo WYSIWYG (lo que se ve
es lo que se imprime) de gráficos y texto formateado preparado para un documento
impreso.
En los primeros días, el sistema de vídeo se utilizaba únicamente para mostrar el
texto que el usuario escribía en el teclado. En una interfaz gráfica de usuario, el sistema
de vídeo por sí mismo se convierte en una fuente de entradas del usuario. El sistema de
vídeo muestra varios objetos gráficos en forma de ¡conos y controles de entrada como
botones y barras de desplazamiento. Utilizando el teclado (o más directamente, un dis
positivo de apuntamiento como un ratón), el usuario puede manipular directamente estos
objetos en la pantalla. Los objetos gráficos se pueden arrastrar, los botones se pueden
pulsar y las barras de desplazamiento se pueden desplazar.
La interacción entre el usuario y un programa llega a ser por tanto más íntima. En
vez de un ciclo de información unidireccional desde el teclado al programa y luego al
sistema de vídeo, el usuario interactúa directamente con los objetos de la pantalla.

Interfaz de usuario coherente


Los usuarios ya no esperan gastar mucho tiempo en aprender cómo utilizar el ordenador
o dominar un programa nuevo. Windows ayuda a este objetivo porque todos los progra
mas Windows tienen fundamentalmente la misma apariencia. El programa ocupa una
ventana (un área rectangular en la pantalla) y se identifica mediante una barra de título.

8
Hola, Windows 95 15

La mayoría de las funciones del programa se activan a través del menú del programa.
Cuando la información es demasiado grande para caber en una única pantalla se solucio
na mediante barras de desplazamiento. Algunas opciones de menú invocan cuadros de
diálogo, en los cuales el usuario introduce información adicional. Un cuadro de diálogo
que aparece en casi todos los programas Windows permite abrir un archivo. Este cuadro
de diálogo parece-el mismo (o muy similar) en varios programas Windows diferentes y
casi siempre se invoca desde la misma opcion de menú.
Una vez que ya conoce cómo utilizar una aplicación Windows, está en buena posi
ción para aprender a usar otra. Los menús y cuadros de diálogo permiten a los usuarios
experimentar con un nuevo programa y explorar sus características. La mayoría de los
programas Windows tienen tanto una interfaz de teclado como una interfaz de ratón.
Aunque la mayoría de las funciones de Windows se pueden controlar a través del tecla
do, utilizar el ratón es a menudo más fácil para muchas acciones.
Desde la perspectiva del programador, para conseguir una interfaz de usuario con
sistente y coherente con las aplicaciones Windows hay que utilizar las rutinas predefini
das en Windows que permiten construir menús y cuadros de diálogo. Todos los menús
tienen las mismas interfaces de teclado y ratón porque Windows (y no el propio progra
ma) se encargan de realizar este trabajo.

Ventajas de la Multitarea

Aunque alguna gente sigue preguntando cuándo es realmente necesaria la multitarea en


un ordenador con un único usuario, los usuarios están realmente preparados para la
multitarea y se pueden beneficiar de ella. La popularidad de los programas residentes
MS-DOS (por ejemplo, Sidekick) lo demostró hace muchos años. Aunque estos progra
mas emergentes no son, hablando estrictamente, programas multitarea, sí que permiten
conmutar o cambiar el contexto rápidamente. Esta conmutación de contexto envuelve
varios de los mismos conceptos que la multitarea.
En Windows, cualquier programa puede llegar a ser un programa emergente resi
dente en RAM. Se pueden ver y ejecutar a la vez varios programas Windows. Cada
programa ocupa una ventana rectangular en la pantalla. El usuario puede mover las
ventanas a cualquier posición de la pantalla, cambiar su tamaño, conmutar entre diferen
tes programas y transferir datos de un programa a otro. Debido a que esto parece algo
similar a un escritorio (por supuesto, en los días previos a que el escritorio fuera domina
do por el propio ordenador), a veces se dice que Windows utiliza la «metáfora del escri
torio» para visualizar múltiples programas.
Las primeras versiones de Windows utilizaban un sistema de multitarca llamado
«no apropiativo» (non-preemptive). Esto significa que Windows no utilizaba el tempori
zador (timer) del sistema para asignar los tiempos de procesador entre los diferentes
programas activos a la vez en el sistema. Los programas por sí mismos tenían que ceder
voluntariamente el control a otros programa para que pudieran ejecutarse. En Win
dows 95, la multitarea es apropiativa (preemptive): los programas por sí mismos pueden
desplegarse en múltiples threads o subprocesos de ejecución que parecen ejecutarse
concurrentemente.

9
10
16 Introducción

Gestión de memoria
Un sistema operativo no puede implementar multitarea sin hacer algo de gestión de
memoria. A medida que se cargan nuevos programas y van terminando los viejos pro
gramas, la memoria se va fragmentando. El sistema tiene que ser capaz de consolidar el
espacio de memoria libre. Esto requiere que el sistema mueva bloques de código y datos
en memoria.
Incluso Windows 1, ejecutándose en un microprocesador 8088, era capaz de reali
zar este tipo de gestión de memoria. En el modo real, esto sólo se puede llevar a cabo
como una hazaña impresionante de ingeniería de software. Los programas que se ejecu
tan en Windows pueden colapsar la memoria, pues un programa puede contener más
código del que se puede almacenar en memoria a la vez. Windows puede descargar
código de la memoria y recargarlo posteriormente desde el archivo EXE del programa.
Un usuario puede ejecutar varias copias, llamadas «Instancias», de un programa; todas
estas instancias comparten el mismo código en memoria. Los programas ejecutándose
en Windows pueden compartir rutinas localizadas en otros archivos llamados «librerías
de enlace dinámico» (~ynamic link libraries). Windows incluye un mecanismo para en
lazar el programa con las rutinas de las librerías de enlace dinámico en tiempo de eje
cución. Windows por sí mismo es básicamente un conjunto de librerías de enlace diná
mico.
Por tanto, incluso en Windows 1, el límite de memoria de 640 kilobyte (KB) de la
arquitectura del PC estaba superado efectivamente sin requerir memoria adicional. Pero
Microsoft no se detuvo aquí: Windows 2 ofreció a las aplicaciones Windows acceso a la
memoria expandida (EMS), mientras que Windows 3 trabajaba en modo protegido para
ofrecer a las aplicaciones Windows acceso de hasta 16 MB de memoria extendida. Y
ahora Windows 95 barre estas viejas restricciones al ser un sistema operativo completa
mente de 32 bits con un espacio de memoria plano'.

Interfaz Gráfica independiente del dispositivo


Windows es una interfaz gráfica y los programas Windows pueden utilizar gráficos y
texto formateado tanto en el sistema de vídeo como en la impresora. Una interfaz gráfica
no es sólo más atractiva en apariencia, sino que también puede impartir un alto nivel de
información al usuario.
Los programas escritos para Windows no acceden directamente al hardware de los
dispositivos gráficos como el sistema de vídeo o la impresora. En vez de ello, Windows
incluye un lenguaje de programación gráfico (llamado Graphics Device Inte~face, o
GDI) que simplifica la visualización de gráficos y texto formateado. Windows virtualiza
el hardware utilizado para mostrar la información. Un programa escrito para Windows

' Un espacio plano de direcciones de memoria (flat address space) significa que el
programador pue
de utilizar toda la memoria de forma lineal, accediendo directamente a cualquier dirección
de memoria sin
recurrir a bloques de segmento ni descriptores (memoria extendida), ni tener que
conmutar bancos de
memoria (memoria expandida). (N. del T)

11
Hola, Windows 95 17

se ejecutará en cualquier tarjeta de vídeo o cualquier impresora para la que exista una
controlador Windows. El programador no necesita determinar el tipo de dispositivo que'
está instalado en el sistema.
Crear una interfaz gráfica independiente de¡ dispositivo en el IBM PC no fue una
tarea sencilla para los ingenieros de Windows. El diseño de] PC estaba basado en el
principio de la arquitectura abierta. Los fabricantes de hardware independientes fueron
animados a desarrollar periféricos para el PC y lo hicieron en gran número. Aunque
habían aparecido varios estándares, los programas de MS-DOS convencionales para el
PC tenían que soportar individualmente varias configuraciones de hardware. Por ejem
plo, es bastante común para un procesador de texto MS-DOS que se venda con uno 0 dos
disquetes llenos de pequeños archivos, cada uno de los cuales utiliza una impresora
determinada. Los programas Windows 95 no requieren estos controladores porque su
soporte es parte de Windows.

El compromiso Windows

La programación para Windows 95 es una apuesta a todo o nada. Por ejemplo, no puede
escribir una aplicación MS-DOS y utilizar Windows para algunos gráficos. Si desea
utilizar alguna parte de Windows, tiene que comprometerse completamente con un pro
grama diseñado para Windows.
La razón de esta afirmación se comprenderá mejor a medida que aprenda la es
tructura de un programa Windows. Cualquier cosa en Windows está interconectada.
Si desea dibujar un gráfico en el sistema de vídeo, necesita algo llamado «handle a
un contexto de dispositivo». Para obtenerlo, necesita un «handle a una ventana». Para
recibir y procesar mensajes necesita un «procedimiento de ventana». Y en ese punto
ya está escribiendo un programa Windows. No se puede volar si no se deja de pisar el
suelo.

Las llamadas a función

Windows 95 soporta aproximadamente mil llamadas a funciones que las aplicaciones


pueden utilizar. Es bastante improbable que llegue a memorizar la sintaxis de todas esas
llamadas. La mayoría de los programadores Windows gastan una buena parte de su
tiempo examinando las diferentes llamadas a funciones, ya sea en libros impresos o en
manuales en pantalla.
Cada función Windows tiene un nombre descriptivo escrito en una combinación de
letras mayúsculas y minúsculas, por ejemplo, CreateWindow. Esta función (como puede
imaginar) crea una ventana para su programa. Otro ejemplo: la función IsClipboardFor
matAvailable determina cuándo el portapapeles contiene datos de un determinado for
mato.
Todas las funciones principales de Windows se declaran en los archivos de cabecera.
El archivo de cabecera principal se llama WINDOWS.H e incluye llamadas a otros archivos
de cabecera. Estos archivos de cabecera se proporcionan en cualquier entorno de progra

12
18 Introducción

mación C que soporte Windows 95 '. Los archivos de cabecera son una parte importante
de la documentación técnica de Windows. Puede que desee imprimir los archivos de
cabecera o utilizar un examinador de archivos para una referencia rápida.
En su programa Windows, puede utilizar las llamadas a funciones Windows gene
ralmente de la misma forma que usa las funciones de la librería C como strIen. La prin
cipal diferencia es que el código para las funciones de la librería C se enlaza con el
código del programa durante el proceso de compilación, mientras que el código para las
funciones Windows se localiza fuera de su programa en librerías de enlace diná
mico (DLL).
Cuando usted ejecuta un programa Windows, se comunica con Windows a través de
un proceso llamado «enlace dinárnico» (dynam¡c linking). Un archivo EXE contiene
referencias a las distintas librerías de enlace dinámico que utiliza y a las funciones
incluidas en las librerías. La mayoría de las DLL se localizan en el subdirectorio
SYSTEM de su directorio Windows. Cuando un programa Windows se carga en memo
ria, las llamadas a función del programa se resuelven como puntos de entrada a las
funciones en las librerías de enlace dinámico, las cuales se cargan en memoria si es que
no lo estaban.
Cuando usted enlaza un programa Windows para producir un ejecutable, tiene que
enlazarlo con unas «librerías de importación» especiales proporcionadas con su entorno
de programación. Estas librerías de importación contienen los nombres de las librerías
de enlace dinámico de todas las funciones Windows, así como información de referencia
para dichas funciones. El enlazador o finker utilizar esta información para construir la
tabla en el archivo EXE que resuelve las llamadas a funciones Windows cuando se
carga el programa.

Programación orientada a objetos

Cuando programa para Windows usted está realmente comprometiéndose con un tipo de
programación orientada a objetos (OOP: Object Oriented Programming). Esto es más
evidente en el objeto con el que está trabajando durante más tiempo en Windows: el
objeto que da a Windows su nombre, el objeto que pronto parecerá asumir característi
cas antropomórficas, el objeto que puede incluso aparecer en sus sueños, el objeto cono
cido como la «ventana».
Como ya mencioné anteriormente, las ventanas son áreas rectangulares de la panta
lla. Una ventana recibe la entrada del usuario desde el teclado o el ratón y visualiza
salida gráfica en su superficie.
Una ventana de aplicación normalmente contiene la barra de título del pro
grama, una línea de menús, bordes para cambiar el tamaño y quiza alguna barra de
desplazamiento. Los cuadros de diálogo son ventanas adicionales. Además, la super-

' Por ejemplo, Microsoft Visual C++, Borland C++, Symantec C++ o PowerBuilder Optima
C++.
(N. del T.)

13
Hola, Windows 95 19

ficie de un cuadro de diálogo contiene siempre ventanas adicionales llamadas «ven


tanas hijas» (child windows). Estas ventanas hijas toman la forma de botones, bo
tones radio, casillas de verificación, campos de entradas de texto, listas y barras de
desplazamiento.
El usuario ve estas ventanas como objetos en la pantalla e interactúa directamente
con estos objetos pulsando un botón, seleccionando un elemento de una lista. Es muy
interesante que la perspectiva del programador sea análoga a la perspectiva del usuario.
La ventana recibe esta entrada del usuario en la forma de «mensajes» a la ventana. Una
ventana también utiliza mensajes para comunicarse con otras ventanas.
Comprender estos mensajes es uno de los obstáculos que usted tendrá que sortear
para llegar a ser un programador Windows.

Arquitectura basada en mensajes


La primera vez que vi una interfaz gráfica de usuario en accion me quedé sorprendido.
La demostración incluía un procesador de textos rudimentario ejecutándose en una ven
tana. El procesador de texto podía reformatear su texto cuando la ventana del programa
cambiaba de tamaño.
Era obvio que el sistema operativo por sí mismo se estaba encargando de gestionar
los detalles de la lógica inherente al cambio de tamaño de la ventana y que el programa
era capaz de responder a esta función del sistema. ¿Cómo sabía el programa cuándo su
ventana cambiaba de tamaño? ¿Cuál era el mecanismo que utilizaba el sistema operativo
para transmitir esta información a la ventana? Mi experiencia de programación anterior
era inútil para entender cómo funcionaba esto.
Es evidente que la respuesta a estas preguntas es fundamental para comprender la
arquitectura utilizada en las interfaces gráficas de usuario. En Windows1, cuando un
usuario cambia el tamaño de una ventana, Windows envía un mensaje al programa indi
cando el nuevo tamaño de la ventana. El programa puede entonces ajustar el contenido
de su ventana para reflejar el nuevo tamaño.
«Windows envía un mensaje al programa.» Espero que usted no lea esta afirmación
sin asombrarse. ¿Qué quiere significar? Estamos hablando de código de un programa, no
de un sistema de correo electrónico. ¿Cómo puede un sistema operativo enviar un men
saje a un programa?
Cuando digo que «Windows envía un mensaje al prograrna», significa que Windows
llama a una función dentro del programa. Los parámetros de esta función describen el
mensaje particular. Esta función que se localiza en su programa Windows se conoce
como el «proceditniento de ventana» (windowprocedure).

El procedimiento de ventana
Usted estará acostumbrado a la idea de un programa que hace llamadas al sistema opera
tivo. Así es como un programa abre un archivo, por ejemplo. Lo que no es tan fácil de
aceptar es la idea de un sistema operativo haciendo llamadas a un programa. Pero esto es
fundamental en la arquitectura orientada a objetos de Windows 95.

14
20 Introducción

Cualquier ventana que crea un programa tiene asociada un procedimiento de venta


na (window procedure). Este procedimiento de ventana es una función que puede estar
en el propio programa o en una librería de enlace dinámico. Windows envia un mensaje
a la ventana llamando al procedimiento de ventana. El procedimiento de ventana realiza
alguna acción dependiendo del mensaje y luego devuelve el control a Windows.
Más exactamente, una ventana siempre se crea basándose en una «clase de ventana»
(window class). La clase de ventana identifica el procedimiento de ventana que procesa
los mensajes a la ventana. Utilizar una clase de ventana permite a múltiples ventanas
estar basadas en la misma clase de ventana y, por tanto, usar el mismo procedimiento de
ventana. Por ejemplo, todos los botones de todos los programas Windows están basados
en la misma clase de ventana. La clase de ventana está asociada con un procedimiento
de ventana (localizado en una librería de enlace dinámico Windows) que procesa los
mensajes para todos los botones Windows.
En programación orientada a objetos, un «objeto» es una combinación de código y
datos. Una ventana es un objeto. El código es el procedimiento de ventana. Los datos son
la información que guarda el procedimiento de ventana y la información que guarda
Windows para cada ventana y cada clase de ventana que existe en el sistema.
Un procedimiento de ventana procesa los mensajes a la ventana. Con frecuencia,
estos mensajes indican a la ventana que se ha producido una entrada del usuario desde
el
teclado o el ratón. De esta forma es, por ejemplo, como sabe un botón cuándo está
siendo
«pulsado». Otros mensajes indican a la ventana cuándo está cambiando su tamaño o
cuándo es necesario redibujar la superficie de la ventana.
Cuando un programa Windows comienza su ejecucion, Windows crea una «cola de
mensajes» para el programa. Esta cola de mensajes almacena los mensajes para todas
las
diferentes ventanas que un programa puede crear. El programa incluye un pequeño trozo
de código llamado «bucle de mensajes» para recuperar esos mensajes desde la cola y
repartirlos a los adecuados procedimientos de ventana. Otros mensajes se envían direc
tamente al procedimiento de ventana sin pasar por la cola de mensajes.
Si está empezando a cansarse de tanta descripción abstracta de la arquitectura de
Windows, quizá le ayudará ver cómo la ventana, la clase de ventana, el procedimiento
de ventana, la cola de mensajes, el bucle de mensajes y los mensajes de ventana se
combinan juntos en el contexto de un programa real. Este es nuestro siguiente apartado.

SU PRIMER PROGRAMA WINDOWS


En su clásico libro The C Programming Language (2. ed., Prentice Hall, 1988), Brian
Kernighan y Dennis Ritchie comienzan la explicación con el ahora famoso programa
«Hola, mundo» (Hello, world):

#include <std¡o.h>
main ()

printf ("Hola, rnundo\n");

15
Hola, Windows 95 21

En este capítulo, mostraré un programa similar escrito para Microsoft Windows 95.
El Programa se llama HOLAWIN y crea una ventana que muestra la cadena de texto
«Hola, Windows 95» y también reproduce un archivo de sonido con mi voz' recitando
las mismas palabras.
Para que no quede asustado por la impresión al ver el código del programa HO
LAWIN, le aviso ahora que el archivo con el código fuente HOLAWIN.C tiene un tama
ño de 80 líneas. La mayoría de estas 80 líneas son redundantes y tendrá que utilizar unas
línea.s similares en casi todos los programas Windows que escriba.
En vez de preguntar por qué el programa «Hola, Windows 95» es tan largo y com
plejo, vamos a preguntar por qué el tradicional programa «Hola, mundo» es tan corto y
simple.

¿Qué es incorrecto en este programa?

El modelo de salida para el programa «Hola, mundo» y otros programas C tradicionales


es una antigua pieza de hardware conocida como el teletipo. El teletipo es parecido a una
máquina de escribir con un rollo de papel continuo. En un pasado no tan lejano, los
programadores se sentaban delante del teletipo y tecleaban órdenes que se plasmaban
en
el papel. La máquina respondía imprimiendo su salida en el papel.
En los primeros días de las terminales y los PC, la metáfora del teletipo se extendió
al sistema de vídeo. El sistema de vídeo se convirtió en un «teletipo de cristal» que
simplemente se desplazaba hacia arriba cuando el texto alcanzaba el final de la pantalla.
¿Cómo puede el programa tradicional «Hola, imindo» mostrar texto sin indicar al
sistema operativo el determinado dispositivo de salida en el que va a aparecer el texto?
Porque sólo hay un dispositivo de salida: la pantalla de vídeo, utilizada como si fuera un
teletipo. Si el usuario desea que la salida vaya a otro sitio, tiene que redireccionarla
desde la línea de órdenes.
¿Cómo puede el programa mostrar texto sin indicar al sistema en qué parte del
dispositivo de salida quiere que aparezca el texto? Porque el texto siempre aparece don
de el cursor está, probablemente en la línea siguiente a aquella en la que ejecutó el
programa. Si desea mostrar «Hola, mundo» en el centro de la pantalla, tiene que usar
código de control dependiente del dispositivo para situar primero el cursor en la posición
deseada.
Imagine que desea ejecutar varios programas «Hola, mundo» a la vez y ver su salida
en pantalla. ¡Qué locura! Las copias del programa interferirían unas con las otras. No
hay nada en la metáfora del teletipo que permita separar la salida de varios programas
ejecutándose concurrentemente.
También es interesante que vea la salida «Hola, mundo» incluso después de que
termine el programa. En vez de eliminarse a sí mismo, el programa deja restos de su
existencia en el sistema de vídeo.

1 En este caso, se trata de la voz del traductor. (N. del T)

16
22 Introducción

El programa «Hola, mundo» es tan simple porque está diseñado para una época más
simple, con computad.oras más simples y dispositivos de salida más simples. Se trata de
un programa totalmente alejado de los programas actuales, que no estájugando el mismo
juego que la competencia.

Los archivos HOLAUN

La Figura 2-1 rriuestra dos de los tres archivos necesarios para crear el programa «HO
LAWIN». Estos son el archivo make HOLAWIN.MAK y el archivo con el código fuente
HOLAWIN.C. El tercer archivo se almacena en el disco CD-ROM con el nombre
HOLAWIN.WAV. Se trata de un archivo de sonido en formato de onda que contiene el
texto hablado.

HOLAWIN.MAK

# -------------------------
# Archivo make HOLAWIN.MAK
# -------------------------

holawin.exe : holawin.obj
$(LINKER) $(GUIFLAGS) -OUT:holawin.exe holawin.obj $(GUILIBS)

holawin.obj : holawin.c
$(CC) $(CFLAGS) holawin.c

HOLAWIN.C

HOLAWIN.C -- Visualiza "Hola, Windows 95" en la ventana


(c) Charles Petzold, 1996
(c) Traducción Jaime de Yraolagoitia
---------------------------------------------------------- ~/

#include <windows.h>

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

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,


PSTR szCmdLine, inL ¡CmdShow)

sLatic char szAppName[1 = 1'HolaW¡,n11 ;


HWND hwnd
MSG msg
WNDCLASSEX wndc1ass

(continúa)

17
Figura2-1. El programa HOLA WIN.

18
Hola, Windows 95 23

wndc1ass.cbSíze = sizeof (wndc1ass) ;


wndc1ass.style = CS-HREDRAW 1 CS-VREDRAW
wnd,class.lpfnWnd,Proc = WndProc
wndc1ass.cbClsExtra = 0
wndelass.cbWridExtra = 0
wndelass.hInstance = hInstance
wndc1ass.hIcon = LoadIcon (NULL, IDI-APPLICATION~
wndc1ass.heursor = Load.Cursor (NULL, IDC-ARROW) ;
wndc1ass.hbrBackground = (HBRUSH) GetStockObject (WHITE-BRUSH) ;
wndc1ass.1pszMenuName = NULL ;
wndc1ass.IpszClassName = szAppName ;
wndclass.hIconSm = LoadIcon (NULL, IDI---hPPLICATION) ;
RegisterClassEx (&wndc1ass) ;

hwnd = CreateWindow ~szAppNaine, Nombre clase de ventana


`El programa Hola", Barra del 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, // Handle de ventana padre
NULL, Handle a menú de la ventana
hInstance, Handle de instancia del programa
NULL) ; // Parámetros de creación

ShowWindow (hwnd, ¡CmdShow)


UpdateWindow (hwnd~ ;
while (GetMessage (&msg, NULL, 0, 0»

TranslateMessage (&msg)
DispatchMessage (&msg)
return msg.wParam ;

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

HDC hdc
PAINTSTRUCT ps
RECT rect
switch (iMsg)

case M-CREATE :
PlaySound ("holawin.wav", NULL, SND-FILENAME 1 SND~_ASYNC)
return 0 ;

case WH_PAINT:

19
hdc = BeginPaint (hwnd, &ps) ;

(continúa)

20
24 Introducción

GetClienLRect (hwnd, &rect) ;

DrawTexL (hdc, "Hola, Wl.ndows 95", -1, &rect,


DT-SINGLELINE 1 DT_CENTER ! DT---WENTER)

EndPaint (hwnd, &ps) ;


return 0 ;

case W_DESTROY:
PostQuitMessage (0)
re~urn U

return DefWindowProe (hwnd, iMsg, wParam, 1Pararn.) ;

En el Capítulo 9 encontrará otro tipo de archivo común en la programación Windows


llamado el «script de recursos», que suele tener la extensión RC (resource script). Pero
hasta ese momento, la mayoría de los programas de ejemplo usarán simplemente un
archivo make, un archivo con código fuente C y quizá un archivo de cabecera.
Como mencioné anteriormente, la mayoría de HOLAWIN.C es código redundante
que se encuentra en prácticamente todos los programas Windows. Nadie memoriza real
mente toda esta sintaxis para escribir el código redundante; generalmente, los programa
dores Windows comienzan un nuevo programa copiando un programa existente y ha
ciendo los cambios adecuados. Es libre de utilizar de esta forma los programas incluidos
en el CD-ROM.
Si tiene instalados Windows 95 y Microsoft Visual C++ 4.0, y ha ejecutado el archi
vo por lotes VCVARS32.BAT incluido en Visual C++ y el archivo por lotes MSC.BAT
mostrado en el Capítulo 1, debe ser capaz de crear HOLAWIN.EXE ejecutando la si
guiente orden en la línea de órdenes de una ventana DOS:

NMAKE HOLAWIN.MAK

Si todo sale bien, puede ejecutar el programa desde la línea de órdenes de la ventana
DOS escribiendo:

HOLAWIN

El programa crea una ventana de aplicación normal como se muestra en la Figu


ra 2-2. La ventana visualiza el mensaje «Hola, Windows 95» en el centro de su área
cliente 4. Si tiene instalada una tarjeta de sonido también oira un mensaje hablado; y si no
tiene una tarjeta de sonido, ¿a qué está esperando?

4 El área cliente de una ventana es toda la superficie de la ventana excepto la barra de


título, barra de
herramientas, línea de menú, barra de estado y barras de desplazamiento. (N. del T.)

21
22
Cuando se piensa detenidamente, se comprueba que esta ventana tiene una increíble
funcionalidad en sus 80 líneas de código. Usted puede pinchar en la barra de título con el
puntero de] ratón y mover la ventana alrededor de la pantalla. Puede pinchar en las
esquinas de la ventana y modificar su tamaño. Cuando la ventana cambia de tamaño, el
programa repone automáticamente la cadena de texto «Hola, Windows 95» en el nuevo
centro de la pantalla. Puede pulsar el botón maximizar y aumentar HOLAWIN para que
ocupe toda la pantalla. Puede hacer clic en el botón minimizar y quitar la ventana de la
pantalla. Puede invocar todas estas funciones desde el menú de sistema 5 . También puede
cerrar la ventana y terminar el programa seleccionando la opción Cerrar en el menú de
sistema, haciendo clic en el botón cerrar en la parte derecha de la barra de título o
haciendo doble clic en el icono del menú de sistema.
Aunque puede estar satisfecho al ver que HOLAWIN tiene toda la funcionalidad de
un programa Windows normal, seguramente no estará tan contento cuando examine el
código fuente requerido para crear este programa. Pero ármese de valor mientras voy
diseccionando paso a paso este programa y analizándolo exhau sti vani ente.

1 El menú de sistema (también llamado menú de control) se activa pulsando el icono situado
en la
esquina superior izquierda de todas las ventanas y contiene órdenes para realizar las
operaciones más
habituales con una ventana (cerrar, mover, cambiar el tamaño, maximizar y rninimizar). (N.
del T.)

23
26 Introducción

El archivo make
Para facilitar la compilación de programas Windows puede utilizar la utilidad NMAKE
incluida en Microsoft Visual C++ 4.0. Cuando desee cambiar algo en el archivo fuente
HOLAWIN.C, todo lo que necesita es ejecutar NMAKE como se mostró anteriormente
para crear el ejecutable HOLAWIN.EXE actualizado.
Un archivo make está formado por una o más secciones, cada una de las cuales
empieza con una línea justificada a la izquierda -que contiene un archivo de destino, una
coma y uno o más archivos dependientes. Esta línea tiene debajo una o más líneas de
orden indentadas'. Estas órdenes crean el archivo de destino a partir de los archivos
dependientes. Si la fecha y hora de última modificación de cualquiera de los archivos
dependientes es posterior a la fecha y hora de] archivo de destino, NMAKE ejecuta las
líneas de orden indentadas.
Normalmente, NMAKE sólo actualizará el archivo de destino en la primera sección
del archivo make. Sin embargo, si uno de los archivos dependientes es a su vez un archi
vo de destino en otra sección del archivo make, NMAKE actualizará primero ese destino.
El archivo make HOLAWIN.MAK tiene dos secciones. La primera sección ejecuta
el enlazador si HOLAWIN.OBJ se ha modificado posteriormente a HOLAWIN.EXE.
La segunda sección ejecuta el cOmpilador si HOLAWIN.C se ha modificado después de
HOLAWIN.OBJ. Puesto que HOLAWIN.OBJ es un archivo de destino en la primera
sección y un archivo dependiente en la segunda sección, NMAKE comprobará si es ne
cesario actualizar HOLAWIN.OBJ antes de recrear HOLAWIN.EXE. Por tanto, el archivo
make se ejecuta realmente de abajo a arriba. Ejecutar el compilador C crea el módulo
objeto HOLAWIN.OBJ a partir del archivo fuente HOLAWIN.C. Ejecutar el enlazador
(linker) crea el ejecutable HOLAWIN.EXE a partir de HOLAWIN.0B.J.
En el Capítulo 1, expliqué cómo las macro o identificadores del archivo make se
establecen a través de variables del entorno definidas por los archivos por lotes que se
vieron en ese capítulo. La mayoría de las veces esto supone definir varios parámetros o
flags del compilador y nombres de librería del enlazador, por tanto regrese a esa parte
del Capítulo 1 si está interesado en más detalles, .

El archivo fuente C
El segundo archivo de la Figura 2-1 es HOLAWIN.C (véanse páginas anteriores), el
archivo con el código fuente C. ¡Y puede pasar un momento antes de que reconozca que
este programa está escrito en 0
Primero echaremos un vistazo general a HOLAWIN.C antes de entrar en detalles.
El archivo sólo contiene dos funciones: WinMain y WndProe. WinMain es el punto de
entrada al programa, el equivalente a la función estándar main del lenguaje C. Todos los
programas Windows tienen una función WinMain.

` Una línea indentada es una línea cuyo comienzo está tabulado algunos espacios respecto a
la línea
anterior. (N. del T.)

24
Hola, Windows 95 27

WndProe es el «procedimiento de ventana» para la ventana de HOLAWIN. Cual


quier ventana -ya sea grande como la ventana principal de un programa o pequeña
como un botón- tiene asociada un procedimiento de ventana. El procedimiento de ventana
es una forma de agrupar el código que responde a la entrada del usuario (normalmente
desde el teclado o el ratón) y muestra la salida gráfica en la pantalla. Como después
veremos, el procedimiento de ventana hace esto procesando «mensajes» a la ventana.
No se preocupe ahora sobre cómo funciona esto. Tendrá luego mucho tiempo para
dominar
este concepto.
Ningún código en HOLAWIN.C llama directamente a WndProc: WndProc se llama
únicamente desde Windows. Sin embargo, hay una referencia a WndProc en WinMain,
que es la función declarada al comienzo del programa, antes que WinMain.

Las llamadas a funciones Windows


HOLAWIN realiza no menos de 17 llamadas a funciones Windows. A continuación se
enumeran estas funciones (con una breve descripción), en el orden en que ocurren en el
programa:

E. LoadIcon: carga el icono que utilizará el programa.


• LoadCursor: carga el cursor del ratón que utilizará el programa.
• GetStockObject: obtiene un objeto gráfico (en este caso, una brocha para dibujar
el fondo de la ventana).
• RegisterClassEx: registra una clase de ventana para la ventana del programa.
• CreateWindow: crea una ventana basada en la clase de ventana.
• ShowW¡ndow: muestra la ventana en la pantalla.
• UpdateW¡ndow: obliga a la ventana a dibujarse a sí misma.
• GetMessage: recupera un mensaje de la cola de mensajes.
• TranslateMessage: traduce algunos mensajes de teclado.
• DispatchMessage: envía un mensaje al procedimiento de ventana.
• P1aySound: reproduce un sonido.
• BeginPaint: comienza a dibujar la ventana.
• GetClientRect: obtiene las dimensiones del área cliente de la ventana.
• DrawText: visualiza una cadena de texto.
• EndPaint: termina de dibujar la ventana.
• PostQuitMessage: introduce un mensaje «terminar» en la cola de mensajes.
• DefWindowProc: realiza el procesamiento por defecto de los mensajes.

25
28 Introducción

Estas funciones están documentadas en los libros o manuales en pantalla incluidos


1
con su compilador y se declaran en varios archivos de cabecera especificados en
WINDOWS.H.

ldentificadores en mayúsculas
Seguramente habrá advertido que se utilizan varios ideritificadores en mayúsculas en
HOLAWIN.C. Estos identificadores están definidos en los archivos de cabecera de Win
dows. Varios de los identificadores contienen un prefijo de dos o tres letras seguido de
un subrayado:

CS-HREDRAW D`F-VCENTER WM-CREATE


CS-VREDRAW IDC-ARROW WM_DESTROY
CW-USEDEFAULTIDI-APPLICATION WNIPAINT
DT-CENTER SND-ASYNC WM-OVERLAPPEDWINDOW
DT-SINGLELINE SND-FILENAME

En realidad, los ídentificadores son simplemente constantes numéricas. El prefijo indica


una categoría general a la cual pertenece la constante, tal como se indica en esta tabla':

Prefijo Categoría
cs Estilo de clase (class style)
IDI Número ID para un icono
IDC Número ID para un cursor
ws Estilo de ventana (window style)
Cw Opción para crear ventana (create window)
wM Mensaje de ventana (window message)
SNI) Opción de sonido
DT Opción para dibujar texto (draw text)

Casi nunca es necesario recordar constantes numéricas cuando se programa para


Windows. Prácticamente todas las constantes numéricas utilizadas en Windows tienen
un identificador definido en los archivos de cabecera.

' Cuando es necesario, se ha introducido entre paréntesis el nombre en inglés de la categoría


para que
pueda comprender el significado de las letras de cada prefijo. (N. del T.)

26
Hola, Windows 95 29

Tipos de datos nuevos


Otros identificadores utilizados en HOLAWIN.C son tipos de datos nuevos, también
definidos en los archivos de cabecera mediante instrucciones typedef o instrucciones
#define. Esto se realizó originalmente para facilitar la transición de los programas Win
dows desde el original sistema de j6 bits a los futuros sistemas operativos basados en
tecnología de 32 bits (u otra). En realidad, este método no trabaja tan armoniosa y trans
parentemente como todo el mundo piensa, pero el concepto suena bien.
A veces estos tipos de datos nuevos son sólo abreviaturas convenientes. Por ejem
plo, el tipo de dato UINT utilizado por el segundo parámetro de WndProc es simplemen
te un unsigned int, que en Windows 95 es un valor de 32 bits. El tipo de dato PSTR
utilizado para el tercer parámetro de WinMain es un puntero a una cadena de caracteres,
es decir, en lenguaje C tradicional char *.
Otros tipos de datos son menos evidentes. Por ejemplo, el tercer y cuarto parámetro
de WndProc se definen, respectivamente, como WPARAM y LPARAM. El origen de
estos nombres requiere un poco de perspectiva histórica. Cuando Windows era un siste
ma de 16 bits, el tercer parámetro de WndProc se definía como WORD, que era un
entero corto sin signo (unsigned short) de 16 bits, mientras que el cuarto parámetro se
definía como LONG, que era un entero largo con signo (long) de 32 bits. Y ésta es la
razón de los prefijos «W» y «L» en la palabra «PARAM». En Windows 95, WPARAM
está definido como un UINT y LPARAM está definido como un LONG (es decir, el tipo
long estándar en C), por tanto, ambos parámetros del procedimiento de ventana son
valores de 32 bits. Esto puede generar alguna confusión porque el tipo de dato WORD
todavía se define en Windows 95 como un entero unsigned short de 16 bits, por lo que el
prefijo «W» de «PARAM» no es del todo justificado.
La función WndProc devuelve un valor del tipo LRESULT. Este tipo está definido
como un LONG. La función WinMain es del tipo WINAPI (como cualquier función
definida en los archivos de cabecera) y la función WndProc es del tipo CALLBACK.
Ambos identificadores están definidos como - ~stdcall, que indica una secuencia espe
cial para llamadas a funciones que se da entre Windows y sus aplicaciones.
HOLAWIN también utiliza cuatro estructuras de datos (que se verán posteriormente
en este capítulo) definidas en los archivos de cabecera. Estas estructuras de datos son:

Estructura Significado
MSG Estructura mensaje
WN13CLASSEX Estructura clase de ventana
PAINTSTRUCT Estructura dibujo
RECT Estructura rectángulo

Las dos primeras estructuras de datos se utilizan en WinMain para definir dos es
tructuras con nombre insg y wndelass. Las otras dos se utilizan en WndProc para definir
dos estructuras llamadas ps y rect.

27
30 Introducción

Los handles del prograrna

Finalmente, hay tres identificadores en mayúsculas para varios tipos de «handles»:

Identificador Significado

HINSTANCE Handle de instancia (el propio programa)


HWND Handle de ventana
HDC Handle de contexto de dispositivo

Los handles se utilizan con bastante frecuencia en Windows. Antes de que termine
este capítulo, también encontrará HICON (un handle de icono), HCURSOR (un handle
de cursor o puntero del ratón) y HBRUSH (un handle de una brocha gráfica).
Un handle es simplemente un número (normalmente con un tamaño de 32 bits) que
identifica un objeto. Los handles en Windows son similares a los handles de un archivo
utilizados en C convencional o en programación MS-DOS. Un programa casi siempre
obtiene un handle llamando a una función Windows. El programa utiliza el handle en
otras funciones Windows para identificar el objeto. El valor real del handle no es impor
tante para el programa, aunque sí para Windows.

Notación húngara
Puede advertir que algunas de las variables en HOLAWIN.C tienen nombres peculiares.
Por ejemplo, szCmdLine, es uno de los parámetros pasados a WinMain.
Muchos programadores Windows utilizan una convención para nombrar las varia
bles que se conoce como notación húngara, en honor a Charles Simonyi, un legendario
programador de Microsoft. En pocas palabras, en la notación húngara el nombre de la
variable comienza con una letra o letras minúsculas que indican el tipo de dato de la
variable. Por ejemplo, el prefijo sz en szCmdLine significa que es una «cadena de carac
teres que termina con el valor cero» (en inglés, string with zero). El prefijo h en hInstan
ce y hPrevInstance indica que es un «handic». El prefijo i en ¡CmdShow indica que es un
«entero» (en inglés, integer). Los dos últimos parámetros de WndProc también utilizan
notación húngara, aunque, como expliqué anteriormente, wParam debería llamarse pro
piamente u¡Param (de unsigned int). Pero como estos dos parámetros están definidos
usando los tipos de datos WPARAM y LPARAM, he preferido mantener sus nombres
tradicionales.
Cuando se nombran las variables de una estructura puede utilizar el nombre de la
estructura (o una abreviación del nombre de la estructura) en minúsculas como un prefi
jo al nombre de la variable o como el propio nombre completo de la variable. Por ejem
plo, en la función WinMain de HOLAWIN.C la variable msg es una estructura de] tipo
MSG y wndclass es una estructura del tipo WNDCLASSEX. En la función WndProe, ps
es una estructura PAINTSTRUCT y rect es una estructura RECT.

28
Hola, Windows 95 31

La notación húngara le ayuda a evitar errores en su código antes de que se convier


tan en fallos del programa. Como el nombre de la variable describe tanto el uso de la
variable como su tipo de dato, es menos probable que cometa errores durante la creación
del programa con los tipos de datos.
Los prefijos de nombres de variable que generalmente utilizaré en este libro apare
cen en la tabla siguiente:

Prefijo Tipo de dato

c char
by BYTE (unsigned char)
n short
i int
x, y int (usada como coordenada-x o coordenada-y)
cx1 Cy int (usado como longitud x o y; c indica «contador»)
bof BOOL (int)J indicaflag
WWORD (unsigned int)
1 LONG (long)
dw DWORD (unsigned long)
fn función
S cadena (string)
SZ cadena terminada con un byte 0 (string with zero)
h handle
p puntero

El punto de entrada al programa

Una vez finalizado este vistazo general a HOLAWIN.C, podemos empezar ahora el
análisis del programa línea a línea. El código comienza con una instrucción #include
para incluir el archivo de cabecera WINDOWS.H:

#include <windows.h>

WINDOWS.H incluye otros archivos de cabecera que contienen declaraciones de


las funciones Windows, las estructuras, los tipos de datos nuevos y las constantes numé
ricas de Windows.
La instrucción #include tiene a continuación la declaración de WndProe:

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

29
32 Introducción

La declaración es necesaria porque WndProc está referenciado dentro del código de


la función WinMain.
En un programa C escrito para un entorno convencional, el punto de entrada es una
función llamada maín. Este es lugar donde el programa empieza su ejecución. (Real
mente, la función main es el punto de entrada a la parte del programa escrita por el
programador. Normalmente, el compilador C añade código de arranque al principio del
archivo ejecutable. Luego, el código de arranque llama a niain.) El punto de entrada de
un programa Windows es una función llamada WinMain. WinMain siempre se define de
la siguiente forma:

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,


KTR szCmdLine, int ¡CindShow)

Esta función utiliza la secuencia de llamada WINAPI y cuando termina devuel


ve a Windows un entero. La función tiene que llamarse WinMain. Tiene cuatro pará
metros:
El parámetro hInstance se llama «handle de una instancia». Es un número que iden
tifica de forma exclusiva al programa cuando se está ejecutando en Windows, Puede ser
que el usuario esté ejecutando en Windows múltiples copias del mismo programa.
Cada una de estas copias es una «instancia» del programa y cada una tiene un diferente
valor hInstance. El handle de una instancia es comparable al «identificador de tarea»
(lask ID) o «¡dentíficador de proceso» (process ID) habitual en los sistemas operativos
multítarea.
El parámetro hPrevIttstance (instancia previa) ahora está anticuado. En las versío
nes anteriores de Windows se utilizaba para el handle de instancia de la última instancia
del mismo programa que estaba todavía activa. Si no se estaban ejecutando otras copias
del mismo programa cuando se activaba el programa, entonces hPrevInstance era 0 o
NULL. En Windows 95, este parámetro siempre es NULL.
El parámetro szCmdLine es un puntero a una cadena terminada en 0 que contiene
cualquier parámetro pasado al programa en la línea de órdenes (si es que se ha ejecutado
desde la línea de órdenes del DOS). Puede ejecutar un programa Windows con un pará
metro de línea de órdenes incluyendo el parámetro después del nombre de programa en
la línea de órdenes del MS-DOS, o tecleando el nombre de programa y el parámetro en
el cuadro de diálogo Ejecutar del menú Inicio.
El parámetro ¡CmdShow es un número que indica cómo se visualiza inicialmente en
Windows la ventana del programa. Este número es asignado por cualquier otro progra
ma que lance el programa a ejecutar. Los programas no necesitan examinar este número
con frecuencia, pero lo pueden hacer si lo desean. En la mayoría de los casos es un 1 o
un 7. Pero es mejor no tomar este valor como 1 ó 7, sino como SW-SHOWNORMAL
(definido como 1 en los archivos de cabecera de Windows) o SW-SHOWMINNOACTIVE
(definido como 7). El prefijo SW en estos identificadores significa «mostrar ventana»
(show wíndow). Y los valores indican cuándo se desea ejecutar el programa en pantalla
normal o ejecutarlo en una ventana minimizada.

30
Hola, Windows 95 33

Registrar la clase de ventana


Una ventana siempre se crea a partir de una clase de ventana. La clase de ventana ¡den
tifica el procedimiento de ventana que procesa los mensajes a la ventana. Esto es impor
tante, por eso lo repetiré: Una ventana siempre se crea a partir de una clase de ventana.
La clase de ventana identifica el procedimiento de ventana que procesa los mensajes a la
ventana.
Se puede crear más de una ventana basada en la misma clase de ventana. Por ejem
plo, todos los botones en Windows se crean basándose en la misma clase de ventana. -
La
clase de ventana define el procedimiento de ventana y otras características de las venta
nas que se crean basadas en esa clase. Cuando usted crea una ventana, puede definir
características adicionales de la ventana que son exclusivas a esa ventana.
Antes de crear una ventana para su programa, tiene que registrar una clase de venta
na llamando a la función RegisterClassEx. Esta es una versión extendida (y de ahí el
sufijo «Ex») de la función RegisterClass de versiones anteriores de Windows; de todas
formas, RegisterClass sigue trabajando en Windows 95.
La función RegisterClassEx requiere un único parámetro: un puntero a una estructu
ra del tipo WNDCLASSEX. La estructura WNDCLASSEX se define en los archivos de
cabecera de Windows de la siguiente forma:

typedef struct tagWNDCLASSEX

UINT cbSize
UINT style ;
WNEPROC lpfnWndProc
int cbClsExtra
int cbWndExtra
HINSTANCEhInstance
HICON hTcon ;
HCURSOR hCursor
HBRUSH hbrBackground
LKSTR lpszMenuName
LKSTR IpszClassName
HICON hIconSm

WNDCLASSEX

Conviene hacer algunos comentarios sobre los tipos de datos y la notación húngara.
Los prefijos LP y 1p significan «puntero largo» (long pointer), que es una herencia de
Windows 16 bits, donde los programadores tenían que distinguir entre puntero cortos
(short o near) de 16 bits y punteros largos (long ofar) de 32 bits. En Windows 95, todos
los punteros tienen un tamaño de 32 bits. He intentado eliminar todos los prefijos 1 en los
punteros de los ejemplos de este libro, pero es muy probable que los continúe viendo en
otros listados Windows.
También notará que se utiliza la notación húngara. Por ejemplo, el prefijo 1pfn signi
fica «puntero largo a función» (longpointer to afunction). El prefijo cb significa «con
tador de bytes». El prefijo hbr es «handle de una brocha» (handle to a brush).

31
32
34 Introducción

En WinMain, tiene que definir una estructura del tipo WNDCLASSEX, general
mente, como ésta:

WNDCLASSEX wndc1ass ;

Luego, tiene que definir los 12 campos de la estructura y llamar a RegisterClassEx:

Regi~LerClassEx (&wndc1ass) ;

Los dos campos más importantes son el penúltimo y el tercero. El penúltimo es el


nombre de la clase de ventana (que en los programas que sólo crean una ventana se
suele
definir con el mismo nombre del programa). El tercer campo (1pfn WndProc) es la direc
ción del procedimiento de ventana usado para todas las ventanas creadas a partir de esta
clase (que en HOLAWIN.C es la función WndProc). Los otros campos describen carac
terísticas de todas las ventanas basadas en dicha clase de ventana.
El campo cbSize es el tamaño de la estructura. La instrucción:

wndc1ass.style = CS_HREDRAW 1 CS-VREDRAW ;

combina dos identificadores de «estilo de clase» con un operador OR a nivel de bits. En


los archivos de cabecera de Windows los identificadores que comienzan con el prefijo
CS se definen como constantes de 32 bits con un bit definido a 1 y los demás a 0. Por
ejemplo, CS-VREDR^ se define como 00001 y CS-HREDRAW se define como
00002. Los identificadores definidos de esta forma se conocen con el nombre de ¡den
tificadores oflags de bit. Usted puede combinar estos identificadores mediante el opera
dor OR a nivel de bits del lenguaje C.
Estos dos identificadores de estilo de clase indican que todas las ventanas creadas a
partir de esta clase se redibujan completamente cuando cambia el tamaño horizontal
(CS-HREDRAW) o vertical (CS - VREDRAW) de la ventana. Si cambia de tamaño la
ventana de HOLAWIN advertirá que la cadena de texto se redibuja para situarse en el
nuevo centro de la ventana. Estos dos identificadores aseguran que esto ocurra. Luego
veremos brevemente cómo el procedimiento de ventana se entera de este cambio en el
tamaiño de la ventana.
El tercer campo de la estructura WNDCLASSEX se inicializa con la instrucción

w_ndc1assApfnWndProc = WndProc ;

Esto establece que el procedimiento de ventana de esta clase de ventana es WndProc,


que es la segunda función en HOLAWIN.C. Este procedimiento de ventana procesa
todos los mensajes para todas las ventanas creadas en base a esta clase de ventana.
Como
he mencionado anteriormente, el prefijo 1pfn en el nombre del campo es la notación
húngara de «puntero largo a una función» (longpointer to afunction).
Las dos instrucciones siguientes:

wndclass.cbClsExtra = 0

33
wndc1ass.cbWndExtra = 0

34
Hola, Windows 95 35

reservan algún espacio extra en la estructura de la clase y en la estructura de la ventana


que Windows mantiene internamente. Un programa puede usar este espacio para sus
propias necesidades. El programa HOLAWIN no utiliza esta característica, por tanto se
especifica el valor 0. En otro caso, como indica la notación húngara, los campos se
tendrían que definir con un «contador de bytes».
El campo siguiente es simplemente el handle de instancia del programa (que es uno
de los parámetros a WinMain):

wndclass.hInstance = hInstance ;

La instrucción

wndclass.hicon = LoadIcon (NULL, IDI_APPLICATION) ;

y la instrucción

wndc1ass.hIconSm = LoadIcon (NULL, IDI-APPLICATION) ;

definen el icono utilizado para todas las ventanas creadas basándose en esa clase de
ventana. El icono es una imagen pequeña en mapa de bits (bitmap) que aparece en la
barra de tareas de Windows y en la parte izquierda de la barra de título de la ventana.
Posteriormente en este libro aprenderá a crear ¡conos personalizados para sus
programas
Windows. Por ahora, adoptaremos un enfoque sencillo y utilizaremos un icono
predefinido.
Para obtener un handle a un icono predefinido, tiene que llamar a la función LoadIcon
con el primer parámetro definido a NULL. (Cuando cargue su propio icono personaliza
do, este parámetro debe identificar el handle de instancia del programa.) El segundo
parámetro es un identificador que comienza con IDI («1D de un icono») y que está
definido en los archivos de cabecera de Windows. El icono IDI APPLICATION es
simplemente un pequeño dibujo de una ventana. La función LoadIcon devuelve un handle
a este icono. No tendremos que preocuparnos realmente del valor de este handle. Se
utiliza simplemente para establecer el valor de los campos hIcon y hIconSm. Estos cam
pos se definen en la estructura "DCLASSEX para ser del tipo HICON, es decir, «handle
de icono».
La instrucción:

wndclass.hCursor = LoadCursor (NULL, IDC ARROW) ;

es muy similar a las dos instrucciones anteriores. La función LoadCursor carga un cur
sor de ratón predefinido conocido como IDC - ARROW y devuelve un handle a este
cursor. Este handle se asigna al campo hCursor de la estructura WNDCLASSEX. Cuan
do el cursor del ratón se sitúe sobre el área cliente de una ventana creada basándose en
esta clase de ventana, el cursor se convierte en una flecha pequeña.
El siguiente campo especifica el color de fondo del área cliente de las ventanas
creadas basándose en esta clase de ventana. El prefijo hbr del nombre de campo hbrBac
kground significa «handle a una brocha» (handle to a brush). Una brocha (brush) es un

35
36
36 Introducción

término gráfico que designa un patrón de puntos coloreados utilizados para rellenar un
área de la ventana. Windows tiene varias brochas estándares o en «stock». La llamada a
GetStockObject de la siguiente instrucción devuelve un handle a una brocha blanca-

wnclclass.hbrBackground = GetStockObject (WHITE-BRUSH) ;

Esto significa que el fondo del área cliente de la ventana será blanco sólido, que es
la opción elegida normalmente.
El campo siguiente establece el menú de la clase de ventana. HOLAWIN no tiene
menú, por tanto este campo recibe el valor NULL:

wndclass.ipszMenuName = NULL ;

Finalmente, la clase ha de tener un nombre. Para un programa pequeño, este nombre


puede ser el propio nombre del programa, que es la cadena de caracteres «HolaWin»
almacenada en la variable szAppName.

wndc1ass.1pszClassName = szAppNarre ;

Cuando se han definido los 12 campos de la estructura, HOLAWIN registra la clase


de ventana llamando a RegisterClassEx. El único parámetro de esta función es un punte
ro a la estructura WNDCLASSEX:

RegisterClassEx (&wndc1ass) ;

Crear la ventana
La clase de ventana define características generales de una ventana, permitiendo a la
misma clase de ventana ser utilizada para crear diferentes ventanas. Cuando usted real
mente crea una ventana llamando a CreateWindow, puede establecer otros aspectos más
detallados sobre esa ventana en particular.
Los programadores que comienzan a trabajar en Windows se confunden a veces con
la distinción entre la clase de ventana y la ventana, y en por qué todas las características
de una ventana no se pueden establecer de una vez. En realidad, dividir la información
de esta manera es muy conveniente. Por ejemplo, todos los botones de una ventana se
crean basándose en la misma clase de ventana. El procedimiento de ventana asociado
con en esta clase de ventana está localizado dentro del propio sistema Windows. La clase
de ventana es responsable de procesar la entrada de teclado o ratón sobre los botones y
definir la apariencia visual de dichos botones en pantalla. Todos los botones trabajan de
la misma forma en este aspecto. Pero no todos los botones son iguales. Pueden tener
diferentes tamaños, diferentes posiciones en la pantalla y diferentes cadenas de texto.
Estas últimas características son parte de la definición de la ventana.
En vez de usar una estructura de datos tal como hace RegisterClassEx, la llamada a
CreateWindow requiere que toda la información se pase como parámetros a la función.
Esta es la llamada a la función CreateWindow que se realiza en HOLAWIN.C:

37
Hola, Windows 95 37

hwnd = createwindow (szAppName, Nombre clase de ventana


"El programa Hola", Título de ventana
WS_OVERLAPPEDWINDOW, Estilo de ventana
CW~_USEDEFAULT, Posición x inicial
CW_~USEDEFAULT,/1 Posición y inicial
CIUSEDEFAULT, Tamaño x inicial
CW-USEDEFAULT, Tamaño y inicial
NULL, // Handle de ventana padre
NULL, Handle de menú de ventana
hInstance, Handle de instancia del programa
NULL) ; Parámetros creación

Para facilitar la lectura, he utilizado el símbolo // para comentarios de una línea que
describen los parámetros de la función CreateWindow.
El parámetro descrito como «nombre de la clase de ventana» es szAppName, que
contiene la cadena «HolaWin» -el nombre de la clase de ventana que hemos registrado
anteriormente. De esta forma se asocia la ventana con la clase de ventana.
La ventana creada por este programa es una ventana normal superpuesta con
una barra de título, un menú de sistema (menú de control) a la izquierda de la barra
de título; ¡conos minimizar, maximizar y cerrar en la derecha de la barra de título;
y un borde de la ventana que permite modificar su tamaño. Este es un estilo estándar de
las ventanas, y su nombre es WS - OVERLAPPEDWINDOW, que aparece en el paráme~
tro «estílo de ventana». El «título de ventana» es el texto que aparecerá en la barra de
título.
Los parámetros «posición x inicial» y «posición y inicial» establecen la posición
inicial de la esquina superior izquierda de la ventana, relativa a la esquina superior
izquierda de la pantalla. Usando el identificador CW - USEDEFAULT para estos pará
metros, estamos indicando que deseamos que Windows utilice la posición por defecto
para una ventana superpuesta. (CW - USEDEFAULT está definido como Ox8OOOOOOO.)
Por defecto, las ventanas superpuestas que se visualizan posteriormente se colocan des
plazadas un valor horizontal y vertical respecto a la esquina superior izquierda de la
pantalla. Similarmente, los parámetros «tamaño x inicial» y «tamaño y inicial» especifi
can el ancho y la altura de la ventana. De nuevo, el identificador CW - USEDEFAULT
indica que deseamos que Windows utilice un tamaño por defecto para la ventana.
El parámetro etiquetado como «handle de la ventana padre» se define a NULL por
que esta ventana no tiene ventana padre. (Cuando existe una relación padre-hijo entre
dos ventanas, la ventana hijo siempre aparece en la superficie de su padre.) El «handle
de instancia del programa» se define al handle de instancia pasado al programa como
parámetro de WinMain. Finalmente, un puntero a «parámetros de creación» está defini
do a NULL. Puede utilizar este parámetro para apuntar a algunos datos que puede desear
más tarde referenciar en su programa.
La llamada a CreateWindow devuelve un handle a la ventana creada. Este handle se
guarda en la variable hwnd, que está definida como del tipo HWND (handle de ventana,
handle to a window). Todas las ventanas de Windows tienen un handle. Su programa
utilizar el handle para identificar la ventana. Muchas funciones Windows requieren un
parámetro hwnd para que Windows sepa sobre qué ventana se aplica la función. Si un

38
38 Introducción

programa crea varias ventanas, cada una tiene un handle diferente. El handle de ventana
es uno de los handles más importantes que gestiona Windows.

Visualizar la ventana
Después de llamar a la función CreateWindow, la ventana se ha creado internamente en
Windows. Sin embargo, la ventana no aparece todavía en la pantalla. Se necesitan dos
llamadas a función. La primera es:

ShowW¡ndow (hwnd, ¡CmdShow) ;

El primer parámetro es el handle de la ventana que se acaba de crear con Create


Window.
El segundo parámetro es el valor ¡CmdShow pasado como parámetro a WinMain. Esto
determina cómo se mostrará inicialmente la ventana en la pantalla. Si ¡CmdShow
es SW-SHOWNORMAL (igual a l), la ventana se visualiza normal. Si ¡CmdShow es
SW-SHOWMINNOACTIVE (igual a 7), entonces la ventana no se ve, pero su nombre e
icono aparecen en la barra de tareas 1.
La función ShowW¡ndow coloca la ventana en la pantalla. Si el segundo parámetro
de ShowW¡ndow es SW - SHOWNORMAL, el área cliente de la ventana se borra con la
brocha de fondo especificada en la clase de ventana. La llamada a función:

UpdateW¡ndow (hwnd) ;

obliga luego a que se dibuje el área cliente de la ventana. Esto se realiza enviando al
procedimiento de ventana (la función WndProc en HOLAWIN.C) un mensaje WM-PAINT.
Pronto explicaremos cómo WndProc actúa con este mensaje.

El bucle de mensajes
Después de llamar a UpdateWindow, la ventana se ve completamente en pantalla. El
programa tiene que tomar ahora el control para leer la posible entrada de ratón o teclado
del usuario. Windows mantiene una «cola de mensajes» para cada programa ejecutándo
se en Windows. Cuando se produce un evento de entrada, Windows traduce el evento en
un «mensaje» que coloca en la cola de mensajes del programa.
Un programa recupera los mensajes de la cola de mensajes ejecutando un bloque de
código conocido como el «bucle de mensajes»:

while (GetMessage (&msg, NULL, 0, 0))

TranslateMessage (&msg)
Dispatchmessage (&msg)

return msg.wParam ;

' Es decir, se ejecuta pero en modo minimizado. (N. del T.)

39
Hola, Windows 95 39

La variable msg es una estructura del tipo MSG, que está definida en los archivos de
cabecera de Windows de la siguiente forma:

typedef struct tagMSG

HWND hwnd
UINT message ;
WPARAM wParam
LPARAM lParam
DWORD time ;
POINT pt ;
MSG

El tipo de dato POINT es otra estructura, definida así:

typedef struct tagPOTNT

LONG x
LONG y

POINT ;

La llamada a GetMessage que comienza el bucle de mensajes recupera un mensaje


de la cola de mensajes:

GetMessage (&Msg, NULL, 0, 0) ;

Esta llamada pasa a Windows un puntero a la estructura NISG llamado msg. Los
parárnetros segundo, tercero y cuarto se definen a NULL o 0 para indicar que el progra
ma desea todos los mensajes de todas las ventanas creadas por el programa. Windows
rellena los campos de la estructura de mensaje con los valores correspondientes al si
guiente mensaje de la cola de mensajes. Los campos de esta estructura son:

• hwnd: el handle de la ventana sobre la cual se ha efectuado la entrada que


causó el mensaje. En el programa HOLAWIN, éste es el mismo handle que el
valor hwnd devuelto por CreateWindow, pues es la única ventana que tiene
el programa.
• message: el identificador del mensaje. Se trata de un número que identifica el
mensaje. Para cada mensaje hay un identificador exclusivo definido en los archi
vos de cabecera de Windows que empieza con el prefijo WNI («mensaje de ven
tana», window message). Por ejemplo, si mueve el puntero del ratón sobre el área
cliente de HOLAWIN y pulsa el botón izquierdo del ratón, Windows pone en la
cola de mensajes un mensaje con campo message igual a WNI-LBUTTONDOWN,
que es el valor 0020 l.
• wJ`aram: un parámetro de mensaje de 32 bits, cuyo valor y significado dependen
del mensaje específico.

40
40 Introducción

• IParam.- otro parámetro de mensaje de 32 bits que depende del mensaje.


• time: la hora en que el mensaje fue situado en _la cola de mensajes.
• pt: las coordenadas del ratón en el momento en que se situó el mensaje en la cola
de mensajes.

Si el campo message del mensaje recuperado en la cola es cualquier cosa excepto


WM-QUIT (que es igual a OxOO 12), entonces GetMessage devuelve un valor distinto de
0. Un mensaje WM-QUIT obliga al programa a salir del bucle de mensajes. Luego, el
programa termina, devolviendo el miembro wParam de la estructura msg.
La instrucción:

TranslateMessage (&rnsg)

devuelve la estructura msg a Windows para una traducción del teclado. (Trataré esto
más tarde en el Capítulo 5.) La instrucción:

DispatchMeesage (&msg~ ;

pasa de nuevo a Windows la estructura msg. Luego, Windows envía el mensaje al proce
dimiento de ventana adecuado para que se procese, es decir, Windows llama al procedi
miento de ventana. El procedimiento de ventana en HOLAWIN es la función WndProc.
Después de que WndProc procesa el mensaje, lo devuelve a Windows, que está todavía
dando servicio a la llamada a DispatchMessage. Cuando Windows regresa a HOLAWIN
después de la llamada a DispatchMessage, el bucle de mensajes continúa con la siguien
te llamada a GetMessage.

El procedimiento de ventana
Todo lo que he descrito de forma tan exhaustiva en realidad es redundante: se ha regis
trado la clase de ventana, se ha creado la ventana, se ha visualizado la ventana en panta
lla y el programa ha entrado en el bucle de mensajes para recuperar mensajes desde la
cola de mensajes.
La acción real ocurre en el procedimiento de ventana, que determina lo que la ven
tana muestra en su área cliente y cómo la ventana responde a la entrada del usuario.
En HOLAWIN, el procedimiento de ventana es la función llamada WndProc. Un
procedimiento de ventana puede tener cualquier nombre (siempre que no coincida con
algún otro nombre, por supuesto). Un programa Windows puede contener más de un
procedimiento de ventana. Un procedimiento de ventana siempre está asociado con una
particular clase de ventana que usted ha registrado llamando a RegisterClassEx. La fun
ción CreateWindow crea una ventana según una clase de ventana particular. Se puede
crear más de una ventana basada en la misma clase de ventana.
Un procedimiento de ventana se define siempre de la siguiente forma:

LRESULT CALLBACK WndProc (HWND hwnd, UINT ¡Msg, WPARAM wParam, LPARAM
lParam)

41
Hola, Windows 95 41

Advierta que los cuatro parámetros del procedimiento de ventana son los mismos
que los primeros cuatro parámetros de la estructura MSG.
El primer parámetro es hwnd, el handle de la ventana que recibe el mensaje. Este es
el mismo handle devuelto por la función CreateWindow. Para un programa como HO
LAWIN, que sólo crea una ventana, éste es el único handle de ventana que el programa
conoce. Si un programa crea múltiples ventanas basadas en una misma clase de ventana
(y, por tanto, con el mismo procedimiento de ventana), entonces hwnd identifica la ven
tana en particular que recibe el mensaje.
El segundo parámetro es un número (exactamente, un entero sin signo o UINT) que
identifica el mensaje. Los últimos dos parámetros (un WPARAM llamado wParam y un
LPARAM llamado lParam) proporcionan más información sobre el mensaje. Estos pa
rámetros reciben el nombre de «parámetros mensaje» y su contenido es específico según
el tipo de mensaje.

Procesar los mensajes


Cada mensaje que recibe un procedimiento de ventana se identifica con un número,
que es el parámetro ¡Msg del procedimiento de ventana. Los archivos de cabecera de
Windows definen identificadores comenzando por el prefijo WM (~ensaje de venta
na», window message) para cada parámetro mensaje.
Normalmente, los programadores Windows utilizan una construcción switch
y case para determinar qué mensaje está recibiendo el procedimiento de ventana y
cómo procesarlo correctamente. Cuando un procedimiento de ventana procesa un
mensaje, debe devolver 0. Todos los mensajes que el procedimiento de ventana no pro
cesa tienen que pasarse a la función Windows con nombre DefwindowProc. El va
lor devuelto por DefW¡ndowProc tiene que devolverse a su vez al procedimiento de
ventana.
En HOLAWIN, WndProc sólo procesa tres mensajes: WM-CREATE, WM-PAINT
y WNI-DESTROY. El procedimiento de ventana se estructura así:

switch (iMsg)

case W~t_CREATE :
[procesar mensaje WCREATE]
return 0 ;

case WM_PAINT:
[procesar mensaje W_PAINTI
return 0 ;

case WI~._DESTROY:
[procesar mensaje rYMDESTROYI
return 0 ;

return DefWindowProc (hwnd, iMsg, wParam, lParam) ;

42
42 Introducción

Es esencial llamar a DefiVindowProc para gestionar por defecto todos los mensajes
que no se tienen en cuenta en su procedimiento de ventana.

Reproducir un archivo de sonido


El primer mensaje que recibe un procedimiento de ventana -y el primero que WndProc
elige procesar- es WM-CREATE. WndProc recibe este mensaje mientras Windows
está procesando la función CreateWindow en WinMain. Es decir, cuando HOLAWIN
llama a Create Window, Windows hace lo que tiene que hacer y, durante esos momentos,
Windows llama a FVndProc con el primer parámetro definido al handle de la ventana y el
segundo parámetro definido a WM - CREATE. WndProc procesa el mensaje WM - CREATE
y devuelve el control a Windows. Ahora Windows puede regresar desde CreateWindow
a HOLAWIN para continuar ejecutando WinMain.
A menudo, un procedimiento de ventana realiza una inicialización de la ventana
durante el procesamiento de WM - CREATE. HOLAWIN elige procesar este mensaje
reproduciendo un archivo en formato onda llamado HOLAWINMAV. Para ello utiliza
la función P1aySound. El primer parámetro es el nombre del archivo. También puede ser
un alias definido en la sección Sonidos del Panel de control o un recurso del programa.
El segundo parámetro sólo se utiliza si el archivo de sonido es un recurso. El tercer
parámetro especifica varías opciones. En el ejemplo, he indicado que el primer paráme
tro es un nombre de archivo y que el sonido se va a tocar asíncronamente, es decir, la
llamada a la función P1aySound se devuelve tan pronto como el archivo de sonido co
mience a escucharse sin esperar a que termine.
WndProc concluye el procesamiento de WM-CREATE devolviendo el valor 0 al
procedimiento de ventana.

El mensaje WM-PAINT
El segundo mensaje que procesa WndProc es WM - PAINT. Este mensaje es extremada
mente importante en la programación Windows. Informa a un programa cuándo parte o
todo el área cliente de una ventana es «no válida» y se tiene que redibujar.
¿Cómo llega a ser no válido un área cliente? Cuando la ventana se crea por primera
vez, todo el área cliente es no válido porque el programa no ha dibujado todavía nada en
pantalla. El primer mensaje WM - PAINT (que normalmente se genera cuando el progra
ma llama a UpdateW¡ndow en WinMain) indica al procedimiento de ventana que dibuje
algo en el área cliente.
Cuanto usted cambia el tamaño de HOLAWIN, el área cliente también llega a ser no
válido. Recordará que el parámetro de «estilo» de la estructura wndc1ass de HOLAWIN
estaba definido con los identificadores (o flags) CS-HREDRAW y CS - VREDRAN.
Esto le indica a Windows que invalide la ventana entera cuando cambie de tamaño.
Luego, el procedimiento de ventana recibe un mensaje WM - PAINT.
Cuando minimiza HOLAWIN y luego restaura la ventana a su tamaño anterior,
Windows no guarda el contenido del área cliente, pues en un entorno gráfico esto sería
necesitar mucha memoria. En vez de ello, Windows invalida la ventana. El procedimien

43
Hola, Windows 95 43

to de ventana recibe un mensaje WM-PAINT y restaura por sí mismo el contenido de la


ventana.
Cuando mueve las ventanas del escritorio de Windows y se superponen entre sí,
Windows no graba el área de una ventana que ha quedado cubierta por otra ventana.
Cuando se intenta activar esa ventana cubierta, se activa como no válida, lo cual quiere
decir que el procedimiento de ventana recibe un mensaje WM_PAINT para redibujar el
contenido de la ventana.
El procesamiento de WM-PAINT casi siempre empieza con una 1 ]amada a BeginPaint:

hdc = BeginPaint (hwnd, &ps)

y termina con una llamada a EndPaint:

EndPaint (hwnd, &ps) ;

En ambos casos, el primer parámetro es un handle a la ventana del programa y el


segundo parámetro es un puntero a una estructura del tipo PAINTSTRUCT. La estructu
ra PAINTSTRUCT contiene alguna información que un procedimiento de ventana pue
de utilizar para dibujar el área del cliente. (Explicaré los campos de esta estructura en el
próximo capítulo.)
Durante la llamada a BeginPaint, Windows borra el fondo del área cliente, si es que
no había sido borrada. Y borra el fondo utilizando la brocha especificada en el campo
hbrBackground de la estructura WNDCLASSEX usada para registrar la clase de venta
na. En el caso de HOLAWIN se trata de una brocha blanca del «stock», lo que quiere
decir que Windows borra el fondo coloreándolo de blanco. La llamada a BeginPaint
-valida todo el área cliente y devuelve un «handle de dispositivo de coritexto». Un dis
positivo de contexto es un dispositivo de salida físico (por ejemplo, una pantalla de
vídeo) y su controlador de dispositivo. Usted necesita el handle de un dispositivo de
contexto para visualizar texto y gráficos en el área cliente de una ventana. Con el handle
de dispositivo de contexto devuelto por BeginPaint no es posible dibujar fuera del área
cliente, incluso si lo intenta. EndPaint libera el handle de dispositivo de contexto para
que ya no sea válido.
Si un procedimiento de ventana no procesa los mensajes WM_PAINT (que es muy
raro), estos mensajes tienen que pasarse a DefWindowProc. DejWindowProc sim
plemente llama a BeginPaint y EndPaint consecutivamente para que el área cliente se
valíde.
Después de llamar a BeginPaint, WndProc llama a GetClientRect:

GetClientRect (hwnd, &rect) ;

El primer parámetro es el handle de la ventana del programa. El segundo parámetro


es un puntero a una variable llamada rect, definida como de tipo RECT en WndProc.
RECT es una estructura «rectángulo» definida en los archivos de cabecera de Win
dows. Tiene cuatro campos LONG llamados left, top, right y bottom. GetClientRect
define estos cuatro campos con las dimensiones del área cliente de la ventana. Los cam

44
44 Introducción

pos left y top siempre están a 0. Los campos right y bottom se definen al ancho y la altura
del área cliente en pixeIs (puntos).
WniProc no hace nada con la estructura RECT excepto pasar un puntero a dicha
estructura como cuarto parámetro de la función DrawText:

DrawText (hdc, "Hola, Windows 95", -1, &rect,


DT_SINGLELINE 1 DT CENTER 1 DT_VCENTER) ;

Como su nombre indica, DrawText dibuja texto. Ya que esta función dibuja algo, el
primer parámetro es un handle al dispositivo de contexto devuelto por BeginPaint. El
segundo parámetro es el texto a dibujar y el tercer parámetro se define a -1 para indicar
que la cadena de texto se termina con un byte 0.
El último parámetro es una serie de identificadores oflags definidos en los archivos
de cabecera de Windows. En este caso indican que el texto se debe ver como una única
línea centrada horizontal y verticalmente dentro del rectángulo especificado por el cua
tro parámetro. Por tanto, esta llamada a función hace que la cadena «Hola, Windows 95»
aparezca centrada en el área cliente.
Cuando el área cliente sea no válido (por ejemplo, cuando cambie el tamaño de la
ventana), WndProc recibe un nuevo mensaje WM-PAINT. WndProc obtiene el nuevo
tamaño de la ventana llamando a GetClientRect y muestra el texto en el nuevo centro de
la ventana.

El mensaje WM-DESTROY
El mensaje WM - DESTROY es otro mensaje importante. Este mensaje indica que Win
dows está en el proceso de destruir una ventana como respuesta a una orden del usuario.
El mensaje es resultado de que el usuario ha hecho clic en el botón Cerrar, o ha seleccio
nado Cerrar en el menú de sistema del programa, o ha pulsado Alt-F4.
HOLAWIN responde a este mensaje llamando a:

PostQuitMessage (0) ;

Esta función introduce un mensaje WM-QUIT en la cola de mensajes del programa,


Mencioné anteriormente que GetMessage devuelve un valor distinto de 0 para cualquier
mensaje diferente a WM-QUIT que recupera desde la cola de mensajes. Cuando Get
Message recupera un mensaje WM-QUIT, GetMessage devuelve 0. Esto hace que Win
Main salga del bucle de mensajes y termine la ejecución del programa.

LOS OBSTACULOS DEL PROGRAMADOR WINDOWS

Incluso con mi explicación de HOLAWIN, la estructura y comportamiento del programa


probablemente serán todavía algo misterioso. En un pequeño programa C escrito para un
entorno convencional, el programa entero puede almacenarse en la función main. En

45
Hola, Windows 95 45

HOLAWIN, WinMain sólo contiene el código redundante necesario para registrar la


clase de ventana, crear la ventana y recuperar y repartir (dispatch) los mensajes de
la cola de mensajes.
Toda la acción real del programa se produce en el procedimiento de ventana. En
HOLAWIN esta acción no es muy grande: simplemente reproduce un archivo de sonido
y visualiza una cadena de texto en su ventana. Pero en capítulos posteriores, aprenderá
que casi todo lo que hace un programa Windows es en respuesta a un mensaje a un
procedimiento de ventana. Este es uno de los principales obstáculos conceptuales que
tiene que aprender a sortear para comenzar a escribir programas Windows.

No me llames, yo te llamaré

Como he mencionado anteriormente, los programadores están acostumbrados a la idea


de llamar al sistema operativo para hacer algo. Por ejemplo, los programadores C utili
zan la funciónfopen para abrir un archivo. Las funciones de libreria proporcionadas con
el compilador tienen código que llama al sistema operativo para abrir el archivo. Y así
funciona todo, sin problemas.
Pero Windows es diferente. Aunque Windows tiene cerca de mil funciones que se
pueden invocar, Windows también hace llamadas a su programa, especialmente al pro
cedimiento de ventana que hemos llamado WndProe. El procedimiento de ventana se
asocia con una clase de ventana que el programa registra llamando a RegisterClassEx.
Una ventana creada de acuerdo con esta clase utiliza dicho procedimiento de ventana
para procesar todos los mensajes de la ventana. Windows envia un mensaje a la ventana
llamando al procedimiento de ventana.
Windows llama a WndPt-oc cuando se está creando por primera vez una ventana.
Windows llama a WndProc cuando la ventana es posteriormente destruida. Windows
llama a WndProe cuando la ventana ha cambiado de tamaño, se ha movido o se ha
minimizado. Windows llama a WndProc cuando se ha seleccionado un elemento de un
menú. Windows llama a WndProc cuando una barra de desplazamiento se manipula o
cuando se pulsa un botón del ratón. Windows llama a WndProc para indicar cuándo tiene
que redibujar su área cliente.
Todas estas llamadas se realizan en forma de mensajes. En la mayoría de los progra
mas Windows, el grueso del programa está dedicado a gestionar estos mensajes. Los
casi
200 mensajes que Windows puede enviar a un procedimiento de ventana están todos
identificados con nombres que empiezan con las letras «WM» y están definidos en los
archivos de cabecera de Windows.
Realmente, la idea de una rutina incluida dentro de un programa que es llamada
desde fuera del programa no es extraña en la programación normal. La función signal
de C puede capturar la pulsación de las teclas Ctrl-Pausa (Orl~Break). También puede
tener experiencia en interceptar interrupciones hardware en ensamblador o utilizando
una de las instrucciones ON de Microsoft BASIC. El controlador Microsoft Mouse tiene
un método que los programas no-Windows pueden utilizar para notificar la actividad del
ratón.

46
46 Introducción

En Windows, este concepto se extiende abarcándolo todo. Todo lo que ocurra en


una ventana se envía al procedimiento de ventana en forma de un mensaje. El procedi
miento de ventana luego responde a este mensaje de alguna forma o pasa el mensaje a
DejWindowProc para su procesamiento por defecto.
Los parámetros wParam y lParam del procedimiento de ventana no se utilizan en
HOLAWIN excepto como parámetros a DeflVindowProc. Estos parámetros dan al pro
cedimiento de ventana información adicional sobre el mensaje. El significado de los
parámetros varía según el mensaje.
Veamos un ejemplo. Cuando el área cliente de una ventana cambia de tamaño, Win
dows llama al procedimiento de ventana de la ventana. El parámetro hwnd del procedi
miento de ventana es el handle de la ventana que cambia de tamaño. El parámetro ¡Msg
es WM-SIZE. El parámetro wParam para un mensaje WM - SIZE es el valor SIZENOR
MAL, SIZEICONIC, SIZEFULLSCREEN, SIZEZOOMSHOW o SIZEZ00NIHIDE
(definidos en los archivos de cabecera de Windows como constantes con los valores 0
a 4). El parámetro wParam indica cuándo la ventana está siendo minimizada, maximiza
da u oculta (como resultado de otra ventana que se ha maximizado). El parámetro IPa
ram contiene el nuevo tamaño de la ventana. El nuevo ancho (un valor de 16 bits) y la
nueva altura (otro valor de 16 bits) se combinanjuntos en el valor lParam de 32 bits. Los
archivos de cabecera de Windows incluyen macros para ayudarle a extraer estos dos
valores de lParam. Haremos esto en el próximo capítulo.
A veces los mensajes generan otros mensajes como resultado del procesamiento de
DefWindowProc. Por ejemplo, suponga que ejecuta HOLAWIN y selecciona Cerrar en
el menú de sistema utilizando el teclado o el ratón. DefWindowProc procesa esta entrada
de teclado o ratón. Cuando detecta que usted ha seleccionado la opción Cerrar, envía un
mensaje WM - SYSCOMMAND al procedimiento de ventana. WndProc pasa este men
saje a DejWindowProc. DefWindowProc responde enviando un mensaje WM-CLOSE
al procedimiento de ventana. De nuevo, WndProc pasa este mensaje a DejwindowProc.
DefWindowProc responde al mensaje WM - CLOSE llamando a DestroyWindow. Des
troyWindow hace que Windows envíe un mensaje WM - DESTROY al procedimiento de
ventana. Finalmente, WndProe responde a este mensaje llamando a PostQuitMessage
para poner un mensaje WM-QUIT en la cola de mensajes. Este mensaje obliga a salir
del bucle de mensajes en WinMain y terminar el programa.

Mensajes en la cola y mensajes fuera de la cola


He hablado sobre Windows enviando mensajes a una ventana, lo que significa que
Windows
llama al procedimiento de ventana. Pero un programa Windows también tiene un bucle
de mensajes que recupera mensajes a partir de una cola de mensajes llamando a
GetMes
sage y repartiéndolos al procedimiento de ventana llamando a DispatchMessage.
¿Crean los programas Windows una pila de mensajes (igual que un programa nor
mal crea una pila o cola con las entradas de teclado) y luego dirigen esos mensajes a
alguna parte? ¿0 reciben los mensajes directamente desde fuera del programa? Bien,
ambas respuestas son correctas.

47
Hola, Windows 95 47

Los mensajes pueden introducirse en la cola o permanecer fuera de ella. Los mensa
jes en la Cola son aquellos que son situados en la cola de mensajes del programa por
Windows y recuperados y repartidos por el bucle de mensajes. Los mensajes que están
fuera de la cola son enviados directamente a la ventana cuando Windows llama al proce
dimiento de ventana. El resultado es que el procedimiento de ventana obtiene todos los
mensajes de la ventana -tanto los que se introducen en la cola como los que no lo
hacen-. Estructuralmente, los programas Windows son muy límpios porque tienen un
único punto central de procesamiento de mensajes. Se dice que los mensajes de la cola se
mandan a la cola de mensajes, mientras que los mensajes fuera de la cola se envían al
procedimiento de ventana.
Los mensajes que se introducen en la cola son principalmente aquellos que se pro
ducen debido a una entrada del usuario en forma de pulsaciones de tecla (por ejemplo,
WM - KEYDOWN o WM-KEYUP), caracteres del teclado (WM-CHAR), movimientos
del ratón (WM-MOUSEMOVE ) y clies de los botones del ratón (WM - LBUTTONDOWN).
Entre los mensajes en cola también se encuentran el mensaje del temporizador
(WM-TIMER), el mensaje redibujar (WM-PAINT) y el mensaje terminar (WM-QUIT).
Los mensajes fuera de la cola son todos los demás. En ocasiones, los mensajes fuera de
la cola se generan a partir de mensajes de la cola. Cuando usted pasa un mensaje fuera de
la cola a DefW¡ndowProc dentro del procedimiento de ventana, a menudo Windows
procesa el mensaje enviando al procedimiento de ventana otros mensajes.
Obviamente, este proceso es complejo, pero afortunadamente la mayoría de la com
plejidad es un problema de Windows antes que un problema de nuestro programa. Desde
la perspectiva del procedimiento de ventana, estos mensajes vienen de una forma orde
nada y sineronizada. El procedimiento de ventana puede hacer algo con estos mensajes
o ignorarlos. Por esta razón, el procedimiento de ventana recibe el nombre de «el último
hook». Los mensajes notifican al procedimiento de ventana de casi todo lo que afecta a
la ventana.
Frecuentemente, los mensajes fuera de la cola se generan llamando a ciertas funcio
nes de Windows o enviando explícitamente un mensaje a través de la función SendMes
sage. (Los mensajes también se pueden situar en la cola de mensajes con PostMessage.)
Por ejemplo, cuando WinMain llama a CreateWindow, Windows crea la ventana y
durante el proceso envía un mensaje WM-CREATE al procedimiento de ventana. Cuan
do WinMain llama a ShowW¡ndow, Windows envía los mensajes WM-SIZE y
WM-SHOWWINDOW al procedimiento de ventana. Cuando WinMaín llama a Upda
te Window, Windows envía el mensaje WM - PAINT al procedimiento de ventana.
Los mensajes no son como las interrupciones hardware. Mientras esté procesando
un mensaje en un procedimiento de ventana, el programa no será interrumpido por otro
mensaje. Sólo cuando el procedimiento de ventana llama a una función que genera un
nuevo mensaje, entonces el procedimiento de ventana procesará el mensaje antes de que
la función regrese.
El bucle de mensajes y el procedimiento de ventana no se ejecutan coneurrentemen
te. Cuando el procedimiento de ventana está procesando un mensaje de la cola, es el
resultado de una llamada a DispatchMessage en WinMain. DispatchMessage no termina
hasta que el procedimiento de ventana ha procesado el mensaje.

48
49
48 Introducción

Pero advierta que el procedimiento de ventana tiene que ser reentrante. Es decir,
Windows a menudo llama a WndProc con un mensaje nuevo como resultado de WndProc
llamando a DejWindowProc con un mensaje anterior. En la mayoría de los casos, el
hecho de que el procedimiento de ventana sea reentrante no presenta problemas, pero
debe tener cuidado.
Por ejemplo, suponga que define una variable mientras está procesando un men
saje en el procedimiento de ventana, y luego llama a una función Windows. Des
pués de regresar de esa función, ¿puede estar seguro de que la variable es todavía la
misma? No necesariamente -no si la función Windows particular que llamó ha ge
nerado otro mensaje y el procedimiento de ventana cambió la variable mientras procesa
ba el segundo mensaje-. Esta es una de las razones por las que ciertas opciones de
optimización de los compiladores tienen que desactivarse cuando se compilan progra
mas Windows.
En algunos casos, el procedimiento de ventana tiene que conservar la información
que obtiene de un mensaje y usarla mientras está procesando otro mensaje. La informa
ción tiene que guardarse en variables definidas como static en el procedimiento de ven
tana o guardarse en variables globales.
Por supuesto, comprenderá mucho mejor todos estos conceptos cuando los procedi
mientos de ventana se amplíen para procesar más mensajes.

Programe con límpieza


Windows 95 es un entorno multitarea apropiativa (preemptive). Esto significa que
cuando un programa está haciendo una tarea larga, Windows puede permitir al usua
rio cambiar el control a otro programa. Esta es una buena característica y es una
de las ventajas de Windows 95 sobre las versiones anteriores de Windows basadas
en DOS.
Sin embargo, debido a la forma en que está estructurado Windows, esta multitarea
apropiativa (preemptive) no siempre trabaja de la forma que usted puede desear. Por
ejemplo, suponga que su programa tarda un minuto en procesar un mensaje particular.
Sí, el usuario puede cambiar a otro programa. Pero el usuario no puede hacer nada con
su
programa. El usuario no puede mover la ventana de su programa, ni modificar su tama
ño, ni minimizarla, ni cerrarla, nada. Esto es así porque su procedimiento de ventana
tiene que realizar estas funciones, pero está ocupado haciendo un trabajo que lleva su
tiempo. Puede parecer como si el procedimiento de ventana no atendiera esas operacio
nes de mover o cambiar el tamaño de la ventana, pero sí que las tiene en cuenta. Esto es
parte M trabajo de DefWindowProc, que tiene que ser considerado parte de su procedi
miento de ventana.
Si su programa necesita realizar tareas que llevan mucho tiempo mientras procesan
mensajes particulares, hay formas de hacerlo amistosamente que describiré en el Capítu
lo 14. Incluso con multitarea preemptive, no es una buena idea dejar su ventana inerte y
fija en la pantalla. Esto molesta a los usuarios y empezarán a pensar que el programa es
sucio y no está bien diseñado.

50
Hola, Windows 95 49

La curva de aprendizaje
Sí, corno seguramente habrá deducido de este capítulo, la programación Windows
es ciertamente algo diferente de la programación para un entorno convencional como
MS-DOS. Nadie defenderá que la programación para Windows es fácil.
Cuando comencé a aprender la programación para Windows, decidí hacer lo que
siempre había hecho cuando aprendía un nuevo sistema operativo o un nuevo lenguaje:
escribir un sencillo programa de volcado hexadecimal para ver el contenido de un archi
vo. En el entorno convencional MS-DOS, un programa de este tipo requiere procesa
miento de la línea de órdenes, gestión básica de entrada y salida de archivos y presenta
ción de salida en pantalla. Sin embargo, mi programa de volcado hexadecimal para Windows
se convirtió pronto en un monstruo. Necesitaba que aprendiera menús, cuadros de diálo
go, barras de desplazamiento y otros objetos por el estilo. Como primer programa Win
dows, definitivamente no era el más indicado, principalmente porque le dediqué dema
siado tiempo.
No obstante, cuando terminé el programa, era muy diferente de cualquier otro pro
grama de volcado hexadecimal que había escrito. En -vez de obtener el nombre del archi
vo como un parámetro en la línea de órdenes, WINDUMP (como llamé al programa)
presentaba una lista mostrando todos los archivos del directorio activo. En vez de escri
bir su salida a la pantalla como un sencillo teletipo, WINDUMP tenía barras de despla
zamiento, por lo que permitía moverse a cualquier parte del archivo. Como una opción
extra, incluso podía ejecutar dos copias de WINDUMP para comparar archivos uno al
lado del otro. En resumen, WINDUMP era el primer programa de volcado hexadecimal
que había escrito del que estaba orgulloso.
Lo que tiene que preguntarse a sí mismo es lo siguiente: ¿Deseo que mis programas
utilicen una interfaz de usuario moderna y productiva, que incluya menús, cuadros de
diálogo, barras de desplazamiento y gráficos? Si su respuesta es sí, entonces la pregunta
que surge es: ¿deseo escribir por mí mismo todo este código para menús, cuadros de
diálogo, barras de desplazamiento y gráficos? ¿0 prefiero aprovechar todo el código que
ya tiene Windows? En otras palabras, ¿es más fácil aprender a usar 1000 llamadas a
funciones o crear usted mismo todas las funciones? ¿es más fácil orientar su mente a la
arquitectura basada en mensajes de Windows o utilizar la entrada del usuario de un
modelo tradicional?
Si piensa escribir usted mismo su propia interfaz de usuario, tiene que cerrar este
libro y empezar su trabajo inmediatamente. En caso contrario, el resto de nosotros va
mos a aprender a visualizar y desplazar texto en una ventana.

51

Вам также может понравиться