Você está na página 1de 232

- co

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Pgina em branco

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Programao Windows:
C e Win32 API com
nfase em Multimdia

Andr Kishimoto

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Pgina em branco

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Andr Kishimoto

Programao Windows:
C e Win32 API com
nfase em Multimdia

So Paulo, 2006
1a edio

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Programao Windows: C e Win32 API com nfase em Multimdia


2006-2012, Andr Kishimoto
Todos os direitos reservados e protegidos por lei. Nenhuma parte deste livro
pode ser utilizada ou reproduzida sob qualquer forma ou por qualquer meio,
nem armazenada em base de dados ou sistema de recuperao sem permisso
prvia e por escrito do autor, com exceo de citaes breves em artigos
crticos e anlises. Fazer cpias de qualquer parte deste livro constitui violao
das leis internacionais de direitos autorais.
O autor no assume qualquer responsabilidade por danos resultantes do uso
das informaes ou instrues aqui contidas. Tambm fica estabelecido que o
autor no responsabiliza-se por quaisquer danos ou perdas de dados ou
equipamentos resultantes, direta ou indiretamente, do uso deste livro.

ISBN 85-906129-1-0
Andr Kishimoto
kishimoto@tupinihon.com
http://www.tupinihon.com

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

todos aqueles que tm fora de vontade


em aprender e superar novos desafios.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Pgina em branco

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Agradecimentos
Agradeo meus pais e minha famlia, por sempre terem me apoiado e
pelas oportunidades que sempre me deram durante minha vida. Sou muito
grato por ter um grande amor na minha vida, Natlia, que sempre foi amiga e
companheira, nos nossos momentos mais felizes e mesmo durante as nossas
brigas. Agradeo tambm meus ex-professores dson Rego Barros e Srgio
Vicente Pamboukian, por proporem tarefas onde pude aplicar meus
conhecimentos que so demonstrados nesse trabalho e por darem a idia e
incentivo a escrever um livro sobre programao grfica; amigos e colegas que
apoiaram meu trabalho e que sempre ajudaram na medida do possvel, e os
profissionais e hobbyistas da rea que compartilham seus conhecimentos,
atravs de livros, artigos e Internet. todos vocs, sou muito grato pela ajuda e
fora que sempre me deram.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Pgina em branco

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Sobre o Autor
Andr Kishimoto comeou a programar quando tinha 12 anos,
desenvolvendo pequenos programas em Basic e PCBoard Programming Language
(sistema para gerenciamento de BBSs). Desde o incio da sua jornada autodidata pela programao, sempre teve interesse em multimdia, criando
animaes em ASCII e ANSI tanto em Basic quanto em Clipper. Aps alguns
anos, aprendeu a trabalhar no modo 13h (VGA) via Pascal ponto de partida
para usar imagens mais sofisticadas e a ter interesse em aprender a programar
em linguagem C e C++.
Especialista em Computao Grfica (SENAC-SP) e bacharel em
Cincia da Computao (Universidade Presbiteriana Mackenzie), desenvolveu
advergames e jogos para dispositivos mveis Java, Brew, iOS e Android.
Atualmente programador snior da Electronic Arts e professor de
Jogos Digitais da Universidade Cruzeiro do Sul.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Pgina em branco

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Sobre a verso gratuita do e-book


O material desse e-book foi elaborado h quase uma dcada e desde a
data de seu lanamento (2006) diversas pessoas se interessaram e adquiriram o
material.
Por causa do apoio e interesse dessas pessoas que hoje esse material
est disponvel gratuitamente para voc (caso voc tenha pago pelo material,
por favor me avise pois algum est se aproveitando da gente). Talvez eu tenha
demorado um pouco mais que o ideal para deixar o contedo acessvel para
todos, mas, como diz o velho ditado, antes tarde do que nunca.
De l pra c, muita coisa mudou o sistema operacional Windows teve
vrias edies, os computadores hoje so 64-bit, temos a plataforma .Net e o
Microsoft Visual C++ que antes era somente pago, hoje possui verses
gratuitas.
Atualmente tambm temos a diferena que o MS-Windows no est
mais sozinho: com a popularidade do iPhone e iPad e preos mais acessveis de
computadores Apple, mais pessoas (e desenvolvedores) possuem o Mac OS
rodando em suas mquinas.
Embora existam todas essas mudanas, o contedo desse e-book
continua vlido afinal, a API do Windows sofreu alteraes mas o seu core
continua existindo, tanto que os exemplos criados para o e-book rodam nas
mquinas atuais com Windows 7.
Outro ponto importante que o material aborda uma API usada para
desenvolver aplicaes nativas e que faz a ponte entre software, sistema
operacional e hardware, conceito aplicado em outros sistemas como Linux,
Mac OS, iOS e Android. Ou seja, conceitos como funo callback, mensagens
do sistema, acesso ao dispositivo grfico, bitmaps, udio e timers so comuns
em todos os sistemas e APIs atuais.
Sobre o cdigo-fonte do e-book: h trechos do e-book que citam
cdigo no CD-ROM. Resolvi no modificar o texto do e-book e, ao invs de
CD-ROM, todos os arquivos atualmente esto disponveis em
https://github.com/akishimoto/progw32api.
Como disse todos que adquiriram o e-book antes da sua verso
gratuita: espero que esse material lhe seja til no seu dia-a-dia, seja para algo
profissional ou como hobby. E agradeo antecipadamente o interesse no meu
trabalho!
- O Autor, Maro de 2012

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Pgina em branco

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Sumrio
Introduo
Convenes utilizadas no livro
O que voc precisa saber
O que voc ir aprender
Recursos necessrios

1
2
3
3
4

Captulo 1 Iniciando
Win32 API, Platform SDK, MFC???
Notao hngara e nomenclatura de variveis
Seu primeiro programa
A #include <windows.h>
Entendendo o programa
A caixa de mensagem

5
5
6
8
9
10
12

Captulo 2 As Peas do Programa


Definindo a classe
Registrando a classe
Criando a janela
O loop de mensagens
Processando mensagens
Enviando mensagens

15
15
20
21
25
28
38

Captulo 3 Arquivos de Recursos


IDs
cones personalizados
Novos cursores
Bitmaps e sons
Informaes sobre a verso do programa
Definindo menus e teclas de atalho
Usando menus e teclas de atalho
Modificando itens do menu
Caixas de dilogo
Criando e destruindo caixas de dilogo
Processando mensagens das caixas de dilogo

41
42
42
45
46
46
54
57
62
63
74
75

Captulo 4 GDI, Textos e Eventos de Entrada


GDI e Device Context

82
82

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Processando a mensagem WM_PAINT


Grficos fora da WM_PAINT
Gerando a mensagem WM_PAINT
Validando reas
Objetos GDI
Obtendo informaes de um objeto GDI
Escrevendo textos na rea cliente
Cores RGB COLORREF
Modificando atributos de texto
Trabalhando com fontes
Verificando o teclado
Outra forma de verificar o teclado
Verificando o mouse
Verificando o mouse, II

85
87
89
91
91
94
95
99
100
103
111
117
118
121

Captulo 5 Grficos com GDI


Um simples ponto
Canetas e pincis
Criando canetas
Criando pincis
Combinao de cores (mix mode)
Traando linhas retas
Traando linhas curvas
Desenhando retngulos
Desenhando elipses
Desenhando polgonos
Inverso de cores e preenchimento de reas
Um simples programa de desenho

123
123
125
125
127
128
130
133
137
140
142
143
146

Captulo 6 Bitmaps
O que so bitmaps?
Bitmaps no Windows: DDB e DIB
Carregando bitmaps
Obtendo informaes de um bitmap
DC de memria
DC particular de um programa
Mostrando bitmaps
Mostrando bitmaps invertidos
DIB Section

148
148
150
151
153
154
157
157
161
164

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Manipulando os bits de um bitmap: tons de cinza e contraste

166

Captulo 7 Regies
O que so regies?
Criando regies
Desenhando regies
Operaes com regies
Regies de corte
Criando janelas no-retangulares

170
170
170
171
173
175
177

Captulo 8 Sons e timers


Reproduzindo sons
A biblioteca Windows Multimedia
MCI
Reproduo de mltiplos sons
Reproduzindo msicas MIDI
Timers

181
181
182
183
185
188
189

Captulo 9 Arquivos e Registro


Criando e abrindo arquivos
Fechando arquivos
Escrita em arquivos
Leitura em arquivos
Excluindo arquivos
Registro do Windows
Abrindo e fechando chaves do registro
Criando e excluindo chaves do registro
Gravando, obtendo e excluindo valores do registro

193
193
195
195
197
198
199
201
203
205

Captulo 10 Consideraes Finais

208

Bibliografia

209

ndice Remissivo

210

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Pgina em branco

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Introduo

Introduo
A idia de escrever um livro sobre programao Windows teve incio
em 2002, durante uma aula de Estrutura de Dados na faculdade. Nessa aula,
todos os alunos tinham que entregar um trabalho sobre implementao de
filas, e o projeto consistia em implementar uma simulao de fbrica: quando o
usurio quisesse, o programa deveria criar diferentes tipos de matria-prima,
que seriam processados por uma suposta mquina, na qual, dependendo da
matria-prima que fosse processada, um produto diferente seria criado.
Nesse trabalho, o professor nos tinha dado total liberdade sobre a
implementao visual, desde que o programa executasse o que fora pedido.
Durante a entrega, todos estavam curiosos em saber como cada um tinha
implementado sua fbrica de produtos. Estvamos no segundo semestre, e o
que tnhamos aprendido na faculdade at ento era o bsico da programao
em C. Como sempre, havia alguns alunos com mais conhecimento que outros,
e muitos trabalhos entregues eram interessantes porm, todos feitos em
modo texto. O nico trabalho em modo grfico tinha sido o meu (um ano
antes de entrar para a faculdade, eu j havia iniciado meus estudos em
programao C e Windows), e todos ficaram surpresos quando viram o
trabalho, inclusive o professor.
Na ocasio, conversei com o professor sobre escrever uma biblioteca
grfica e junto anexar um documento sobre como utilizar as funes da
biblioteca. Ele, me dando o conselho que seria interessante liberar o cdigofonte, e no apenas criar uma biblioteca com a descrio das funes, sugeriu
que eu pensasse na idia de escrever um livro sobre programao grfica para
Windows. Era algo que eu nunca havia pensado, e essa idia me fez imaginar
como seria o trabalho de escrever um livro, as dificuldades, o que traria de
benefcio para mim e como o livro ajudaria as pessoas.
Embora ele no tinha me desafiado, eu aceitei a idia como um desafio.
Escrever um livro sobre programao Windows. Comecei a esboar as
primeiras pginas do futuro livro nas semanas seguintes, pedindo sugestes e
dicas para o professor (que co-autor dos livros Delphi para Universitrios e
C++ Builder para Universitrio, ambos lanados pela editora Pginas e Letras).
Na poca, por diversos motivos, acabei desistindo da idia de escrever o livro.
Foi aps um ano, ento, que voltei com a idia; dessa vez, para concretiz-la.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Programao Windows: C e Win32 API com nfase em Multimdia

Em 2003, estava cursando uma matria onde o assunto principal era a


criao de interfaces grficas em Windows e Linux. Durante esse curso, pude
notar que quase 98% da classe no tinha a mnima noo de como criar um
programa grfico sem o uso do Visual Basic, Delphi (e Kylix) ou C++ Builder.
Na poca, achei isso um absurdo, mas hoje vejo que no posso pensar dessa
maneira, pois ainda so raros os livros sobre programao Windows (utilizando
a linguagem C/C++ e Win32 API) disponveis na lngua portuguesa um dos
nicos lanados at o momento o do professor dessa matria (Desenvolvendo
interfaces grficas utilizando Win32 API e Motif, Srgio Vicente D. Pamboukian,
da editora Scortecci). Alm disso, outro fator que impede as pessoas de
aprenderem a programar para Windows em C o alto custo dos livros
importados (alm da prpria lngua inglesa ser um problema para muitos),
invivel para muitos.
Depois de constatar tal fato, resolvi que realmente deveria escrever um
livro sobre o assunto, em portugus, para que todas as pessoas interessadas
pudessem ter por onde comear. Foi assim que surgiu esse livro, que tem a
inteno de ensinar o leitor a criar programas com nfase em multimdia para
ambiente Windows, atravs da linguagem C e da Win32 API. Espero que meu
objetivo seja atingido!
- O Autor

Convenes utilizadas no livro


Para melhor compreenso durante a leitura do livro, so utilizados
diferentes estilos de escrita e alguns avisos:
Estilos de escrita:
-

Textos em itlico indicam palavras que merecem destaque por serem


termos tcnicos ou palavras em ingls (com exceo de nomes de
produtos, empresas e/ou marcas);

Comandos de programao, como nomes de funes e variveis,


no meio dos textos, so escritas com fonte diferente, como no
exemplo: char teclaPressionada;

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Introduo

Partes de cdigo de programao ou mesmo listagem de cdigofonte de programas-exemplos aparecem como abaixo:

#include <stdio.h>
void main(void)
{
printf(Texto exemplo\n);
}

Avisos:
-

Nota: faz um breve comentrio sobre a teoria explicada ou alerta o


leitor sobre algo importante sobre o assunto;

Dica: fornece dicas para que o leitor possa melhorar o seu


aprendizado;

C++ explicado: contm explicaes quando conceitos da


linguagem C++ so utilizados no livro.

O que voc precisa saber


Antes de comear a leitura desse livro, voc precisa estar familiarizado
com o ambiente Windows (95 ou superior) e saber programar em linguagem C.
Assim como em qualquer criao de algoritmos e programas, essencial
tambm que voc tenha conhecimento e noo de lgica de programao.
Nota: apesar da linguagem C ser a nica requisitada, os cdigos do livro
esto escritos em C++ (arquivo com extenso .cpp) para aproveitar alguns
recursos da linguagem. Entretanto, isso no ir atrapalhar no entendimento
dos programas, pois os cdigos C e C++ do livro so muito semelhantes e
as sintaxes C++ sero explicadas no decorrer do livro.

O que voc ir aprender


Durante a leitura do livro, voc aprender como criar programas
Windows a partir do zero, utilizando linguagem C e Win32 API (Application
Programming Interface, um conjunto de funes as quais so utilizadas para
diversas aes de um programa Windows), atravs de explicaes e

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Programao Windows: C e Win32 API com nfase em Multimdia

demonstraes com exemplos prticos (programas que encontram-se no CDROM). Com os exemplos, voc ir construir pequenos programas a cada
captulo, exercitando diferentes funes de um programa multimdia Windows.

Recursos necessrios
Para criar os programas-exemplo desse livro ser necessrio ter um
compilador C/C++ 32-bit que crie arquivos executveis para Windows
instalado no computador. Existem diversos compiladores no mercado, tais
como Dev-C++, lcc-Win32, Inprise/Borland C++ Builder e Microsoft Visual
C++. Escolha um que voc se adapte melhor.
Dica: lembre-se de consultar o manual ou ajuda do compilador/ambiente
de programao que voc estiver trabalhando, pois aprender a usar as
ferramentas ir ajudar bastante e lhe salvar de futuras dores de cabea.
Os programas-exemplo necessitam do sistema operacional Microsoft
Windows 95 ou superior para serem executados, requerendo as mesmas
configuraes que os compiladores exigem do computador.
Nota: os programas-exemplo do livro foram criados com o Microsoft
Visual C++.Net 2002 e testados sob o sistema operacional Microsoft
Windows XP Professional, porm eles podem ser editados e compilados
em qualquer outro compilador para Windows 32-bit.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 1 Iniciando

Captulo 1 Iniciando
A criao de programas para Windows um pouco diferente da
programao de aplicativos console para MS-DOS, sendo primeira vista algo
mais complexo, pois o prprio Windows em si um sistema mais complexo e
avanado que o MS-DOS.
O Windows executa os programas atravs do processamento de
mensagens, que ocorre da seguinte maneira: o programa que est sendo
executado aguarda o recebimento de uma mensagem do Windows e quando o
mesmo recebe a mensagem (por uma funo especial do Windows), espera-se
que o programa execute alguma ao para processar essa mensagem.
Existem diversas mensagens que o Windows pode enviar ao programa;
por exemplo, quando o usurio modifica o tamanho da janela do programa,
um clique no boto do mouse, a finalizao do programa, enfim, para cada
ao realizada pelo usurio (e conseqentemente pelo Windows), uma
mensagem enviada para o programa processar. Obviamente, no toda
mensagem que dever ser processada; se o seu programa utilizar somente o
teclado, podemos descartar todas as mensagens enviadas sobre as aes do
mouse.
Nota: na programao Windows, o sistema quem inicia a interao com
seu programa (ao contrrio do que ocorre em programas MS-DOS) e
apesar de ser possvel fazer chamadas de funes da Win32 API em
resposta a uma mensagem, ainda o Windows quem inicia a atividade.

Win32 API, Platform SDK, MFC???


Caso voc faa uma pesquisa na Internet sobre programao para
Windows, provavelmente obter milhares de resultados com essas siglas. Nesse
livro, somente a Win32 API (Application Programming Interface, ou Interface de
Programao de Aplicativos) e o Platform SDK (Software Development Kit, ou Kit
de Desenvolvimento de Softwares) so utilizados para criar os programas. Na
verdade, a Win32 API faz parte do Platform SDK (que composto de
bibliotecas, cabealhos e funes para programao Windows), e atravs da
utilizao do Platform SDK que podemos criar os programas para Windows.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Programao Windows: C e Win32 API com nfase em Multimdia

A MFC, sigla de Microsoft Foundation Class, um conjunto de classes


C++ criado pela Microsoft para simplificar a vida do programador. Porm,
toda MFC foi baseada no Platform SDK e em classes, tornando-se mais
complexa para programadores C. Ainda, no suportada por todos os
compiladores e linguagens (restringindo sua programao para determinados
compiladores, sendo esses, na grande maioria, comerciais).
A razo da escolha do uso da Win32 API no livro o fato que ela
baseado na linguagem C (ao contrrio da MFC, baseada na linguagem C++),
sendo acessvel tanto para o programador C quanto ao programador C++. Ao
aprender a utilizar a Win32 API, voc poder fazer tudo o que faria com a
MFC e tambm utilizar suas funes em outros ambientes de programao,
como o Inprise/Borland Delphi ou Microsoft Visual Basic.
C++ explicado: a MFC composta de diversas classes, que podem ser
vistas como uma espcie de struct com suporte a funes e uma grande
quantidade de recursos para programao orientada a objetos (assunto o
qual no ser discutido no livro).

Notao hngara e nomenclatura de variveis


Antes de partirmos para a explicao do primeiro programa-exemplo
do livro, precisamos aprender um conceito muito importante quanto
programao Windows: a notao hngara, um conjunto de convenes para
nomear variveis criado por um programador da Microsoft, o hngaro Charles
Simonyi (por isso o uso do termo notao hngara).
De uma maneira bem resumida, a notao hngara diz que as variveis
devem ser formadas por duas partes: a primeira, com todas as letras em
minsculo representando o tipo da varivel; e a segunda, com a primeira letra
em maisculo e as outras em minsculo, distinguindo as variveis do mesmo
tipo.
Por exemplo, se quisermos declarar uma varivel do tipo int chamada
contanumero, devemos declar-la da seguinte forma: int iContaNumero, ao invs
de int contanumero. O prefiro i no nome da varivel indica que ela do tipo
int.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 1 Iniciando

Todas as funes e variveis utilizadas pela Win32 API seguem a


notao hngara, por isso a necessidade de conhecer esse conceito. A Tabela
1.1 mostra as especificaes da notao hngara. (Note que diversos tipos de
dados no so comuns da linguagem C; eles foram definidos no cabealho
windows.h).
Prefixo

Tipo de dado

b,f
by
c
cx,cy
dw
fn
h
i
l
lp
msg
n
s
sz,str
w
x,y

BOOL (int) ou FLAG


BYTE (unsigned char)
char, WCHAR ou TCHAR
tamanho de x e y (c de count)
DWORD (unsigned long)
funo
handle
int
LONG (long)
ponteiro long de 32-bit
message (mensagem)
short ou int (referncia nmero)
string
string terminado com byte 0
UINT (unsigned int) ou WORD (unsigned word)
coordenadas int x e y
Tabela 1.1: Os prefixos da notao hngara.

Existe tambm uma conveno para nomenclatura de funes (que


tambm utilizada para variveis, quando a notao hngara descartada),
onde a primeira palavra da funo escrita toda em minscula e a primeira
letra de cada palavra extra no nome da funo escrita em maiscula, por
exemplo:
void testar();
void obterResultado();

Porm, essa uma conveno adotada para programas em C++ e Java,


sendo que a Win32 API adota uma conveno (que tambm ser adotada nesse
livro) onde a primeira letra de cada palavra da funo deve ser escrita em
maiscula e o restante em minscula:
void CapturarTela();
void WinMain();

No caso de constantes ou definies, os nomes devem ser escritos com


todas as letras em maiscula e as palavras devem ser separadas por underscore
(_). Exemplo:
const int PI = 3.1415926535897932384626433832795;

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Programao Windows: C e Win32 API com nfase em Multimdia

#define WINDOW_WIDTH 640

Seu primeiro programa


Feito uma breve introduo viso de programao para Windows,
vamos iniciar, como todo primeiro exemplo, com um simples programa no
estilo Hello World!, mostrando apenas uma mensagem na tela. A Listagem 1.1
a seguir um dos menores programas Windows possveis de se escrever:
//-------------------------------------------------------------------------// prog01.cpp - Programa Windows estilo "Hello World!"
//-------------------------------------------------------------------------//-------------------------------------------------------------------------// Bibliotecas
//-------------------------------------------------------------------------#include <windows.h>
//-------------------------------------------------------------------------// WinMain() -> Funo principal
//-------------------------------------------------------------------------int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MessageBox(NULL, "Esse o Primeiro Programa-Exemplo!", "Prog 01", MB_OK);
return(0);
}
Listagem 1.1: Um programa mnimo em Windows.

O resultado da execuo desse programa ser o seguinte (Figura 1.1):

Figura 1.1: Seu primeiro programa.

C++ explicado: nesse primeiro programa-exemplo, existe uma sintaxe da


linguagem C++, que so os comentrios. Em C, comentrios podem ser
escritos somente entre /* e */. Em C++, existe uma outra sintaxe de
comentrio conhecida por comentrios de linha, que so escritos aps o
uso de // (duas barras seguidas). O contedo aps essas duas barras

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 1 Iniciando

considerado comentrio pelos compiladores e seu trmino o final da


linha.

A #include <windows.h>
Para que voc possa comear a criar um programa para Windows, o
primeiro passo a ser feito incluir o arquivo de cabealho windows.h no seu
programa. Esse arquivo de cabealho contm definies, macros e estruturas
para escrever cdigos portveis entre as verses do Microsoft Windows.
Ao visualizar o cdigo-fonte dos cabealhos que so inclusos junto
com o windows.h, podemos verificar centenas de definies e macros, como por
exemplo:
#define TRUE 1
#define FALSE 0
typedef int BOOL

Portanto, no estranhe caso voc encontre uma varivel do tipo BOOL e


ela receba um valor TRUE ou FALSE, pois como podemos ver no trecho de
cdigo acima, a varivel nada mais do que um int, e TRUE e FALSE so 1 e 0, da
mesma maneira que utilizamos esses valores e variveis como uma espcie de
flag/tipo booleano em linguagem C.
Nota: na Win32 API, foram criados novos tipos de variveis, como LONG,
LPSTR e HANDLE. Todos esses tipos so modificaes dos tipos padres da
linguagem C (LONG, por exemplo, um inteiro de 32 bits), e devem ser
utilizados para compatibilidade, pois no futuro um LONG poder ser de 64
bits, suportando os novos processadores e sistemas operacionais. Assim,
facilitar a portabilidade de um sistema para outro.

Entendendo o programa
Como voc pode notar, no existe mais uma funo main() no cdigo
do programa, sendo essa substitudo pela funo WinMain(). A funo WinMain()
a funo principal de qualquer programa Windows e deve ser inclusa
obrigatoriamente, pois chamado pelo sistema como ponto inicial do
programa. Diferente da funo main(int argv, char *argc[]), ela recebe quatro
parmetros e possui o seguinte prottipo:

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

10

Programao Windows: C e Win32 API com nfase em Multimdia

int WINAPI WinMain(


HINSTANCE hInstance,
hInstance // identificador para a atual instncia do programa.
HINSTANCE hPrevInstance,
// identificador para a instncia anterior do
hPrevInstance
programa.
LPSTR lpCmdLine,
lpCmdLine // um ponteiro para a linha de comando do programa.
int nCmdShow // especifica como a janela do programa deve ser mostrada.
);

Nota: enquanto a funo main(int argv, char *argc[]) pode ser declarada
apenas como main() sem parmetros, a funo WinMain(HINSTANCE
hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) deve
sempre ser declarada com todos seus quatro parmetros, mesmo que esses
no sejam utilizados.
No Windows, possvel que diversas instncias de um mesmo
programa estejam sendo executadas ao mesmo tempo; assim, ao ser executado,
o Windows cria um identificador (handle) para a instncia atual do programa em
HINSTANCE hInstance (o hInstance pode ser considerado como uma identidade
nica para cada instncia do programa) para que o Windows e o programa
possam sincronizar corretamente as informaes e mensagens.
O parmetro HINSTANCE hPrevInstance sempre ser NULL para programas
com tecnologia Win32 (ou seja, Windows 95 e verses superiores). Esse
parmetro era utilizado nas verses mais antigas do Windows (Win16), porm
agora tornou-se obsoleto e consta como parmetro para fins de
compatibilidade de cdigo.
O parmetro LPSTR lpCmdLine tem a mesma funo do char *argc[] da
funo main() de um programa DOS, armazenando a linha de comando do
programa (excluindo o nome do programa) na varivel lpCmdLine. A diferena
entre eles que a varivel *argc[] armazena vetores de strings, enquanto
lpCmdLine armazena a linha de comando como uma nica e extensa string.
O ltimo parmetro, int nCmdShow, utilizado para identificar o estado
em que a janela do programa ser iniciada (maximizada, minimizada, normal,
etc). A Tabela 1.2 a seguir mostra os valores que esse parmetro pode receber:
Valor
SW_HIDE
SW_MINIMIZE

Descrio
Esconde a janela e ativa outra janela.
Minimiza a janela especificada e ativa a janela
de nvel mais alto na listagem do sistema.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 1 Iniciando
SW_RESTORE

SW_SHOW
SW_SHOWMAXIMIZED
SW_SHOWMINIMIZED
SW_SHOWMINNOACTIVE
SW_SHOWNA
SW_SHOWNOACTIVATE
SW_SHOWNORMAL

11

Ativa e mostra a janela. Se a janela est


minimizada ou maximizada, o sistema
restaura o tamanho e posio original (idem
ao SW_SHOWNORMAL).
Ativa a janela e a mostra no seu tamanho e
posio atual.
Ativa a janela e a mostra maximizada.
Ativa a janela e a mostra como um cone.
Mostra a janela como um cone.
Mostra a janela no seu estado atual.
Mostra a janela em sua mais recente posio e
tamanho.
Ativa e mostra a janela. Se a janela est
minimizada ou maximizada, o sistema
restaura o tamanho e posio original (idem
ao SW_RESTORE).

Tabela 1.2: Valores para o parmetro int nShowCmd da WinMain().

A funo WinMain() sempre ser do tipo WINAPI (algumas pessoas


utilizam a definio APIENTRY ao invs de WINAPI, porm ambas tm o mesmo
significado), fazendo com que ela tenha uma propriedade diferente na
conveno de chamada da funo. Como padro, todas as funes do seu
programa sempre utilizam a conveno de chamada de C. A conveno de
chamada de funes difere em como os parmetros so passados e
manipulados para a pilha de memria e para os registradores do computador.
O retorno da funo WinMain() do tipo int, o qual deve ser retornado
o valor de sada que est contido no parmetro wParam da fila de mensagens se a
WinMain() for finalizada normalmente com a mensagem WM_QUIT (ser discutida
no captulo 2), ou deve retornar zero se a WinMain() terminou antes de entrar
no loop de mensagens.
Nota: no se preocupe se o ltimo pargrafo ficou meio obscuro para voc
nesse momento, pois irei falar sobre mensagens e lao de mensagens no
prximo captulo. Apenas expliquei o retorno da WinMain() pois sempre
necessrio que ela retorne algo, e como no programa no existe um lao de
mensagens, o retorno zero.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

12

Programao Windows: C e Win32 API com nfase em Multimdia

A caixa de mensagem
Vamos passar agora para o cdigo dentro da funo WinMain(). A
funo MessageBox() uma funo da Win32 API que mostra uma caixa de
mensagem para o usurio com alguns botes e cones pr-definidos.
int MessageBox(
HWND hWnd, // identificador da janela-pai
LPCTSTR lpText, // ponteiro para texto da caixa de mensagem
LPCTSTR lpCaption, // ponteiro para ttulo da caixa de mensagem
UINT uType // estilo da caixa de mensagem
);

O primeiro parmetro HWND hWnd identifica a janela-pai da caixa de


mensagem, ou seja, para qual janela do sistema a caixa de mensagem pertence.
Se o parmetro for NULL, a caixa de mensagem no pertence a nenhuma janela.
Nota: o tipo de varivel HWND armazena um identificador de janela, que
pode ser considerado como uma varivel int contendo um nmero
exclusivo para cada janela criada no Windows. Assim, para manipularmos
ou obter as informaes de uma janela, utilizamos esse identificador. Voc
observar que na programao Windows eles sempre sero utilizados e que
existem diferentes tipos de identificadores.
Os prximos dois parmetros, do tipo LPCTSTR, so ponteiros de string;
seus contedos sero utilizados para mostrar o texto da caixa de mensagem e o
ttulo da caixa de mensagem, respectivamente. Olhando para o programaexemplo em execuo e seu cdigo-fonte, possvel verificar como esses
parmetros funcionam no MessageBox().
O ltimo parmetro define que tipo de boto e cone aparecer na caixa
de mensagem. Existem diversos flags para esse parmetro que podem ser
combinados atravs do operador | (ou bit-a-bit). Os principais flags esto
listados na Tabela 1.3 abaixo.
Valor
MB_ABORTRETRYIGNORE
MB_OK
MB_OKCANCEL

Descrio
A caixa de mensagem contm trs botes:
Anular, Repetir e Ignorar.
A caixa de mensagem contm um boto OK
(esse o padro)
A caixa de mensagem contm os botes OK e

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 1 Iniciando

MB_RETRYCANCEL
MB_YESNO
MB_YESNOCANCEL
MB_ICONEXCLAMATION
MB_ICONINFORMATION
MB_ICONQUESTION
MB_ICONSTOP
MB_DEFBUTTON1

MB_DEFBUTTON2
MB_DEFBUTTON3
MB_DEFBUTTON4

13

Cancelar.
A caixa de mensagem contm os botes
Repetir e Cancelar.
A caixa de mensagem contm os botes Sim e
No.
A caixa de mensagem contm os botes Sim,
No e Cancelar.
Um cone de ponto de exclamao aparecer
na caixa de mensagem.
Um cone com a letra i aparecer na caixa
de mensagem.
Um cone de ponto de interrogao aparecer
na caixa de mensagem.
Um cone de sinal de parada aparecer na
caixa de mensagem.
O primeiro boto da caixa de mensagem o
boto padro (default), a menos que
MF_DEFBUTTON2, MF_DEFBUTTON3 ou MF_DEFBUTTON4
seja especificado.
O segundo boto da caixa de mensagem o
boto padro.
O terceiro boto da caixa de mensagem o
boto padro.
O quarto boto da caixa de mensagem o
boto padro.

Tabela 1.3: Os flags que podem ser utilizados no MessageBox().

Caso voc queira apresentar uma caixa de mensagem com o ttulo


Erro!, na qual a janela-pai tenha como identificador o nome da varivel hWnd,
com a mensagem Arquivo no foi salvo. Salvar antes de sair?, os botes Sim e No
e tambm um cone com ponto de interrogao, utilize o seguinte cdigo:
MessageBox(hWnd, Arquivo no foi salvo. Salvar antes de sair?, Erro!,
MB_YESNO | MB_ICONQUESTION);

Dica: tenha sempre em mos o arquivo de ajuda do Platform SDK, pois


ele o melhor guia de consulta para as funes da Win32 API. Na internet
possvel encontrar esses arquivos, que tambm est incluso em alguns
compiladores. Outra tima referncia o MSDN (Microsoft Developer
Network), que pode ser consultado online pelo site http://www.msdn.com.
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

14

Programao Windows: C e Win32 API com nfase em Multimdia

A funo MessageBox() retorna um valor inteiro, que pode ser utilizado


para verificar qual boto foi clicado pelo usurio; assim podemos fazer um
algoritmo apropriado para cada escolha. Os valores retornados pela funo
esto listados na Tabela 1.4.
Valor
IDABORT
IDCANCEL
IDIGNORE
IDNO
IDOK
IDRETRY
IDYES

Descrio
Boto Anular foi pressionado.
Boto Cancelar foi pressionado.
Boto Ignorar foi pressionado.
Boto No foi pressionado.
Boto OK foi pressionado.
Boto Repetir foi pressionado.
Boto Sim foi pressionado.
Tabela 1.4: Valores retornado pela funo MessageBox().

Nota: caso a caixa de mensagem contenha o boto Cancelar, a funo


retorna IDCANCEL se a tecla ESC for pressionada ou se o boto Cancelar for
clicado. Se a caixa de mensagem no tiver o boto Cancelar, pressionar ESC
no ter efeito algum a caixa de mensagem ser fechada, porm, nenhum
valor ser retornado pela funo.
A linha aps a chamada da funo MessageBox() indica o fim da
execuo do programa, retornando o valor zero. Sempre que um programa
terminar antes de entrar num lao de mensagens, ele deve retornar zero.
Como primeiro programa-exemplo, podemos perceber que h diversos
detalhes e opes para a criao de programas Windows. A seguir, veremos
como codificar um verdadeiro programa Windows, criando sua janela e
obtendo e respondendo algumas mensagens do sistema.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 2 As Peas do Programa

15

Captulo 2 As Peas do Programa


Agora que voc j aprendeu sobre a funo WinMain(), est na hora de
aprofundar o cdigo dentro dela, criando uma programa com as principais
etapas que necessitam ser realizadas para que voc monte sua primeira janela
Windows com a Win32 API, como mostra a Figura 2.1. A listagem do cdigofonte do segundo programa-exemplo encontra-se no final do captulo (arquivo
prog02.cpp no CD-ROM), aps a explicao passo-a-passo das etapas da criao
da janela/programa.

Figura 2.1: Um programa Windows criado com todas as etapas principais.

Definindo a classe
A primeira etapa para a criao da janela do seu programa declarar
uma classe da janela. Apesar de ser chamada de classe, esse novo tipo de
dado uma struct que armazena as informaes sobre a janela do programa.
Sua estrutura definida como:
typedef struct _WNDCLASSEX {
UINT cbSize; // tamanho da estrutura, em bytes
UINT style;
style; // estilo da classe
WNDPROC lpfnWndProc; // ponteiro para a funo que
int cbClsExtra; // bytes extras a serem alocados
janela
int cbWndExtra; // bytes extras a serem alocados
janela
HANDLE hInstance; // identificador da instncia da
HICON hIcon; // identificador do cone

processa mensagens
depois da estrutura da
depois da instncia da
janela

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

16

Programao Windows: C e Win32 API com nfase em Multimdia

HCURSOR hCursor; // identificador do cursor


HBRUSH hbrBackground; // identificador da cor de fundo da janela
LPCTSTR lpszMenuName; // nome do menu do programa
LPCTSTR lpszClassName; // nome da classe da janela
HICON hIconSm; // identificador do cone na barra de ttulo
} WNDCLASSEX;

Aps declarar uma varivel do tipo WNDCLASSEX, inicializamos todos os


membros da estrutura. Cada membro tem um mtodo para sua inicializao,
com exemplos demonstrados logo abaixo e tambm inclusos no cdigo-fonte
do segundo programa-exemplo.
O membro cbSize deve ser inicializado como
especifica qual o tamanho da estrutura.

sizeof(WNDCLASSEX),

pois

WNDCLASSEX.cbSize = sizeof(WNDCLASSEX);

O membro style usado para definir as propriedades de estilo da


janela, como desabilitar o item Fechar ALT+F4" do menu de sistema, aceitar
duplo-clique do mouse ou configurar as opes de atualizao de imagem da
janela. Existem diversos flags que podem ser combinados com o operador | (ou
bit-a-bit), conforme a Tabela 2.1.
WNDCLASSEX.style = CS_HREDRAW | CS_VREDRAW;

Para que o programa possa processar as mensagens enviadas pelo


Windows, o membro lpfnWndProc apontada para a funo WindowProc(), uma
funo onde todos as mensagens do Windows so processadas para o seu
programa (ser comentada mais tarde nesse captulo). Note que WindowProc()
quando apontada por lpfnWndProc escrita sem os parnteses, como no
exemplo:
WNDCLASSEX.lpfnWndProc = (WNDPROC)WindowProc;

Os membros cbClsExtra e cbWndExtra geralmente no so utilizados;


servem para reservar alguns bytes extras na estrutura e/ou na instncia da
janela para armazenar dados, mas muito mais prtico reservar memria
atravs de outras variveis. Portanto, ambos os membros recebem zero.
WNDCLASSEX.cbClsExtra = 0;
WNDCLASSEX.cbWndExtra = 0;

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 2 As Peas do Programa

Valor
CS_DBLCLKS
CS_HREDRAW

CS_NOCLOSE
CS_OWNDC
CS_VREDRAW

17

Descrio
Envia mensagens de duplo-clique do mouse
para o programa.
Redesenha toda a janela se um ajuste de
movimento ou tamanho foi feito na horizontal
da janela.
Desabilita o menu Fechar ALT+F4 do menu
da janela.
Aloca um contexto de dispositivo para cada
janela da classe.
Redesenha toda a janela se um ajuste de
movimento ou tamanho foi feito na vertical da
janela.
Tabela 2.1: Alguns estilos de janela.

Dica: novamente, sempre consulte a documentao do Platform SDK /


Win32 API, onde voc encontrar todos os valores que podem ser
passados para as variveis e funes.
O membro hInstance armazena a instncia do programa e recebe o
parmetro hInstance da funo WinMain().
WNDCLASSEX.hInstance = hInstance;

Os membros hIcon e hIconSm so quase idnticos: o primeiro serve para


definir o cone que ser utilizado para o arquivo executvel, atalho e tambm
para quando o usurio pressionar ALT+TAB para alternar entre os programas
em execuo. O segundo serve para definir o cone que utilizado na barra de
ttulo e tambm na barra de tarefas do Windows. Se hIconSm for NULL, o cone
de hIcon ser utilizado para ambos os membros.
Para carregar cones, utilizamos a funo LoadIcon() da Win32 API:
HICON LoadIcon(
HINSTANCE hInstance, // identificador da instncia do programa
LPCTSTR lpIconName // nome do cone ou identificador do recurso de cone
);

Nessa funo, o parmetro HINSTANCE hInstance identificado somente


se o cone que for usado est num arquivo de recursos (ou seja, um cone

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

18

Programao Windows: C e Win32 API com nfase em Multimdia

personalizado). No caso, devemos enviar o parmetro hInstance da WinMain() e


o nome do cone em LPCTSTR lpIconName.
Caso o cone a ser utilizado seja um dos pr-definidos pelo sistema, o
parmetro hInstance dever ser NULL e lpIconName receber um dos valores da
Tabela 2.2. Exemplo:
WNDCLASSEX.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WNDCLASSEX.hIconSm = LoadIcon(NULL, IDI_ASTERISK);

Valor
IDI_APPLICATION
IDI_ASTERISK
IDI_ERROR
IDI_EXCLAMATION
IDI_HAND
IDI_INFORMATION
IDI_QUESTION
IDI_WARNING
IDI_WINLOGO

Descrio
cone padro (parecido com um cone de
programas MS-DOS).
Idem a IDI_INFORMATION.
cone crculo vermelho com um X.
Idem a IDI_WARNING.
Idem a IDI_ERROR.
cone com ponto de exclamao num balo
branco.
cone com ponto de interrogao num balo
branco.
cone com ponto de exclamao numa placa
amarela.
cone com o logotipo do Windows.
Tabela 2.2: cones pr-definidos pelo sistema.

O membro hCursor utilizado para carregar o cursor de mouse padro


no programa. Para isso, utilizamos a funo LoadCursor() da Win32 API:
HCURSOR LoadCursor(
HINSTANCE hInstance, // identificador da instncia do programa
LPCTSTR lpCursorName // nome do cursor ou identificador do recurso de
cursor
);

A funo LoadCursor() trabalha semelhante LoadIcon(). O primeiro


parmetro deve ser identificado se o cursor utilizado for extrado de um
arquivo de recursos, caso contrrio, ser NULL. Quando hInstance NULL,
significa que o cursor a ser utilizado um dos cursores pr-definidos pelo
sistema e lpCursorName receber um dos valores da Tabela 2.3. Exemplo:
WNDCLASSEX.hCursor = LoadCursor(NULL, IDC_UPARROW);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 2 As Peas do Programa

Valor
IDC_APPSTARTING
IDC_ARROW
IDC_CROSS
IDC_HELP
IDC_IBEAM
IDC_NO
IDC_SIZEALL
IDC_SIZENESW
IDC_SIZENS
IDC_SIZENWSE
IDC_SIZEWE
IDC_UPARROW
IDC_WAIT

19

Descrio
Cursor padro com pequena ampulheta.
Cursor padro.
Cursor em forma de cruz.
Cursor seta e ponto de interrogao.
Cursor de texto (I-beam).
Cursor com smbolo de proibido.
Cursor com setas na vertical e horizontal.
Cursor com setas na diagonal para direita.
Cursor com setas na vertical.
Cursor com setas na diagonal para esquerda.
Cursor com setas na horizontal.
Cursor com seta para cima.
Cursor de ampulheta.
Tabela 2.3: Cursores pr-definidos pelo sistema.

Nota: as funes LoadIcon() e LoadCursor() retornam valores do tipo HICON


e HCURSOR, respectivamente (derivados da estrutura HANDLE). Todas as
funes que tm retorno do tipo HANDLE (ou derivados) retornam o
identificador (handle) do tipo especificado se a funo foi executada
corretamente ou retornam NULL no caso da execuo do algoritmo da
funo falhar.
O prximo membro, HBRUSH hbrBackground, define a cor do fundo da
janela atravs de um identificador de pincel (brush). Pincis e identificadores
grficos sero discutidos em captulos mais avanados, portanto no entrarei
em detalhes nesse momento. Por enquanto, basta saber que o Windows utiliza
pincis e canetas (varivel do tipo HPEN) para desenhar grficos no programa e
que por isso um pincel precisa estar associado janela (no caso, para pintar o
fundo dela com alguma cor). possvel criar pincis ou utilizar os padres do
Windows; como esse assunto ser tratado mais pra frente, no exemplo desse
captulo usaremos apenas os padres j existentes.
WNDCLASSEX.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);

Para utilizar os pincis padres, foi utilizado a funo GetStockObject(),


que retorna um identificador para objetos grficos pr-definidos (ver prottipo
da funo abaixo) e recebe como parmetro o tipo do objeto pr-definido,
conforme a Tabela 2.4.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

20

Programao Windows: C e Win32 API com nfase em Multimdia

HGBIOBJ GetStockObject(
int fnObject // tipo de objeto pr-definido
};

Nota:

no

comando

WNDCLASSEX.hbrBackground

(HBRUSH)GetStockObject(BLACK_BRUSH),

perceba que foi feito um type-casting


antes do nome da funo. Esse type-casting necessrio, pois a funo
GetStockObject() retorna um identificador de objeto grfico genrico
(HGDIOBJ), enquanto o membro hbrBackground do tipo HBRUSH. Sem essa
converso, ocorreria um erro de compilao.
Valor

Descrio
Pincel preto.
Pincel cinza escuro.
Pincel cinza.
Pincel transparente (idem a NULL_BRUSH).
Pincel cinza claro.
Pincel transparente (idem a HOLLOW_BRUSH).
Pincel branco.

BLACK_BRUSH
DKGRAY_BRUSH
GRAY_BRUSH
HOLLOW_BRUSH
LTGRAY_BRUSH
NULL_BRUSH
WHITE_BRUSH

Tabela 2.4: Pincis pr-definidos do Windows.

O membro LPCTSTR lpszMenuName indica qual ser o menu atribudo


classe da janela. A criao e utilizao de menus sero estudadas mais adiante,
no captulo sobre arquivos de recursos. Por ora, no iremos utilizar nenhum
menu e usamos a seguinte atribuio:
WNDCLASSEX.lpszMenuName = NULL;

Resta agora apenas um membro, LPCTSTR lpszClassName. Este utilizado


para especificar o nome da classe da janela, que ser utilizado como referncia
para o Windows e funes Win32 API que necessitam informaes dessa
classe. Para esse membro, atribumos uma string:
WNDCLASSEX.lpszClassName = Nome da Classe;

Registrando a classe
Com a classe da janela j inicializada, a prxima etapa registr-la para
que o Windows permita que voc crie janelas a partir das informaes
fornecidas dentro da classe. preciso registrar a classe antes de tentar criar

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 2 As Peas do Programa

21

qualquer janela! Para isso, utilizamos a funo RegisterClassEx(), que tem o seguinte
prottipo:
ATOM RegisterClassEx(
CONST WNDCLASSEX *lpwcx // endereo da estrutura com os dados da classe
);

A funo recebe apenas um parmetro, CONST WNDCLASSEX *lpwcx, que


um ponteiro para a classe da janela que foi criada anteriormente. Ela retorna
zero se o registro da classe falhou ou retorna o valor de um ATOM que identifica
exclusivamente a classe que est sendo registrada.
Nota: o tipo ATOM um inteiro que faz referncia um banco de dados de
strings definida e mantida pelo Windows; como uma identidade nica de
cada programa que est sendo executado, assim como o nome da classe de
uma janela.

Criando a janela
Depois de definir a classe da janela e registr-la, podemos ento criar a
janela principal do programa. Para isso, utilizamos a seguinte funo:
HWND CreateWindowEx(
DWORD dwExStyle, // estilos extras da janela
LPCTSTR lpClassName, // ponteiro string para o nome da classe registrada
LPCTSTR lpWindowName, // ponteiro string para o ttulo da janela
DWORD dwStyle, // estilo da janela
int x, // posio horizontal da janela
int y, // posio vertical da janela
int nWidth, // largura da janela
int nHeight,
nHeight, // altura da janela
HWND hWndParent, // identificador da janela-pai
HMENU hMenu, // identificador do menu
HINSTANCE hInstance, // identificador da instncia do programa
LPVOID lpParam // ponteiro para dados de criao da janela
);

Muitos desses parmetros so auto-explicveis, como int x, int y, int


Para eles, basta informar em valores inteiros a posio (x,
y) onde a janela ser inicialmente criada e a largura e altura da mesma.
nWidth, int nHeight.

O parmetro LPCTSTR lpClassName deve ser o mesmo especificado no


membro lpszClassName da classe da janela. J LPCTSTR lpWindowName indica o
texto que ir como ttulo da janela (aparece na barra de ttulo e na barra de
tarefas do Windows).
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

22

Programao Windows: C e Win32 API com nfase em Multimdia

Como a janela a principal do programa, no existe nenhum


identificador da janela-pai (a no ser que levemos em conta o prprio
Windows) e, portanto, HWND hWndParent deve ser NULL (ou HWND_DESKTOP se
levarmos em conta o Windows como janela-pai).
O parmetro HMENU hMenu recebe o identificador do menu principal do
programa, mas sempre iremos deix-lo como NULL pois no vamos utilizar
menus por ora, e, ao utilizarmos, carregaremos os menus atravs de funes da
Win32 API.
HINSTANCE hInstance armazena o identificador da instncia do programa
e deve receber o parmetro hInstance da WinMain().

O ltimo parmetro da funo, LPVOID lpParam, no utilizado em


grande parte dos programas; serve para recursos avanados que para nossas
aplicaes no tero importncia, portanto esse parmetro deve receber NULL.
Deixei para o final a explicao de dois parmetros, DWORD dwExStyle e
Ambos servem para modificar as propriedades do estilo da
janela, como barra de ttulo, menu do sistema, alinhamento, entre outros. O
parmetro dwStyle especifica o estilo da janela e dwExStyle especifica
propriedades extras quanto ao estilo. Os principais valores que dwStyle podem
receber so fornecidos na Tabela 2.5; a Tabela 2.6 contm os principais valores
que podem ser recebidos por dwExStyle. Lembre-se que em ambos os casos,
so possveis combinar os valores atravs do operador | (ou bit-a-bit).

DWORD dwStyle.

Estilo
WS_BORDER
WS_CAPTION
WS_CHILD
WS_CLIPCHILDREN

WS_DISABLED

Descrio
Cria uma janela com borda fina.
Cria uma janela com barra de ttulo (inclui o
estilo WS_BORDER).
Cria uma janela-filho. Esse estilo no pode ser
utilizado junto com o estilo WS_POPUP.
Exclui a rea ocupada pelas janelas-filho
quando necessrio fazer atualizao da
janela-pai. Esse estilo usado quando se cria
uma janela-pai.
Cria uma janela inicialmente desabilitada.
Uma janela desse estilo no pode receber

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 2 As Peas do Programa

WS_DLGFRAME
WS_HSCROLL
WS_MAXIMIZE
WS_MAXIMIZEBOX

WS_MINIMIZE
WS_MINIMIZEBOX

WS_OVERLAPPED
WS_OVERLAPPEDWINDOW

WS_POPUP
WS_POPUPWINDOW

WS_SIZEBOX
WS_SYSMENU

WS_TABSTOP

WS_VISIBLE
WS_VSCROLL

23

entradas do usurio.
Cria uma janela com borda tpica de caixas de
dilogo. No possui barra de ttulo.
Cria uma janela com barra de rolagem
horizontal.
Cria uma janela inicialmente maximizada.
Cria uma janela que contm o boto de
Maximizar. No pode ser combinado com o
estilo WS_EX_CONTEXTHELP e o estilo WS_SYSMENU
deve ser especificado.
Cria uma janela inicialmente minimizada.
Cria uma janela que contm o boto de
Minimizar. No pode ser combinado com o
estilo WS_EX_CONTEXTHELP e o estilo WS_SYSMENU
deve ser especificado.
Cria uma janela com borda e barra de ttulo.
Cria uma janela com os estilos WS_OVERLAPPED,
WS_CAPTION,
WS_SYSMENU,
WS_THICKFRAME,
WS_MINIMIZEBOX e WS_MAXIMIZEBOX.
Cria uma janela pop-up. No pode ser utilizado
com o estilo WS_CHILD.
Cria uma janela pop-up com os estilos
WS_BORDER, WS_POPUP e WS_SYSMENU. Os estilos
WS_POPUPWINDOW
e WS_CAPTION devem ser
combinados para deixar a janela visvel.
Cria uma janela que contm uma borda de
ajuste de tamanho.
Cria uma janela que tem o menu de sistema
na barra de ttulo. O estilo WS_CAPTION tambm
deve ser especificado.
Especifica um controle que pode receber o
cursor do teclado quando o usurio pressiona
a tecla TAB. Ao pressionar a tecla TAB, o
cursor do teclado muda para o prximo
controle com o estilo WS_TABSTOP.
Cria uma janela inicialmente visvel.
Cria uma janela com barra de rolagem
vertical.
Tabela 2.5: Principais estilos da janela.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

24

Programao Windows: C e Win32 API com nfase em Multimdia

Estilo
WS_EX_ACCEPTFILES
WS_EX_CLIENTEDGE
WS_EX_CONTROLPARENT
WS_EX_MDICHILD
WS_EX_TOOLWINDOW

WS_EX_TOPMOST

Descrio
A janela com esse estilo aceita arquivos
arrastados para ela.
Cria uma borda afundada na janela.
Permite o usurio navegar entre as janelasfilho usando a tecla TAB.
Cria uma janela-filho MDI.
Cria uma janela de ferramentas flutuante;
contm uma barra de ttulo menor que a
normal e utiliza uma fonte menor para o
ttulo. Esse estilo de janela no aparece na
barra de tarefas ou quando o usurio aperta
as teclas ALT+TAB.
Especifica que a janela criada deve
permanecer acima de todas as outras janelas
do sistema, mesmo que essa seja desativada.
Tabela 2.6: Principais estilos extras da janela.

A funo CreateWindowEx() retorna um identificador para a janela criada,


que do tipo HWND. Para armazenar o identificador da janela, declaramos a
seguinte varivel:
HWND hWnd = NULL;

E logo em seguida, chamamos e armazenamos o retorno da funo


na nova varivel hWnd com o seguinte comando:

CreateWindowsEx()

hWnd = CreateWindowEx(parmetros);

Nota: a funo CreateWindowEx() utilizada no somente para criar a janela


principal do programa, mas tambm para criar botes, caixas de textos,
textos estticos (label), caixas de verificao, etc, pois todos esses controles
so considerados janelas pela Win32 API. Acostume-se com o uso do
termo window (janela) para todos esses controles, e no apenas para a
janela principal do programa (tambm conhecida como formulrio ou
form em ambientes de programao como Inprise/Borland Delphi ou
Microsoft Visual Basic).
Depois de criada a janela, essa deve ser mostrada para o usurio,
atravs da chamada funo ShowWindow(), que tem o prottipo:
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 2 As Peas do Programa

25

BOOL ShowWindow(
HWND hWnd, // identificador da janela
int nCmdShow // estado da janela
);

O primeiro parmetro da funo recebe o identificador da janela que


ser mostrado, no caso, devemos enviar a varivel hWnd anteriormente criada. O
segundo parmetro, int nCmdShow, indica o estado inicial da janela. Lembra-se
do ltimo parmetro da funo WinMain()? Ele utilizado aqui, onde
repassamos seu valor para a funo ShowWindow(). Assim, a chamada funo
deve ser feita como no exemplo:
ShowWindow(hWnd, nCmdShow);

O retorno dessa funo zero se a janela estava anteriormente


escondida ou um valor diferente de zero se a janela estava previamente visvel.
Alm da funo ShowWindow(), quando o programa executado,
chamamos outra funo, UpdateWindow(), para que ela envie uma mensagem
WM_PAINT diretamente ao programa, indicando que preciso mostrar o contedo
da janela. O prottipo da funo :
BOOL UpdateWindow(
UpdateWindow(
HWND hWnd // identificador da janela
);

O nico parmetro da funo recebe o identificador da janela que ser


atualizado. Se a funo falhar, ela retorna zero; caso contrrio, o retorno ser
um valor diferente de zero.

O loop de mensagens
A prxima etapa criar um loop onde sero verificadas todas as
mensagens que o Windows enviar para a fila de mensagens do programa. Essa
etapa consiste em trs passos: em primeiro lugar, o programa deve receber a
mensagem que est na fila; em seguida, traduz cdigos de teclas virtuais ou
aceleradoras (de atalho) em mensagens de caracteres/teclado, para finalmente
despachar as mensagens para a funo que processam elas. Porm, antes do
loop, declaramos uma varivel do tipo MSG que armazenar a mensagem atual,
com as seguintes informaes:
typedef struct tagMSG {
HWND hWnd; // identificador da janela que recebe as mensagens

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

26

Programao Windows: C e Win32 API com nfase em Multimdia

UINT message; // nmero da mensagem


WPARAM wParam; // informao adicional da mensagem
LPARAM lParam; // informao adicional da mensagem
DWORD time; // horrio que a mensagem foi postada
POING pt; // posio do cursor quando a mensagem foi postada
} MSG;

Nota: teclas virtuais ou aceleradoras so cdigos independentes do sistema


para vrias teclas, que incluem as teclas de funo F1-F12, setas e
combinaes de teclas, como CTRL+C ou ALT+A, por exemplo. Sem a
traduo dessas teclas, o programa no ir processar diversos eventos
envolvendo o teclado, como o acesso de menus (caso seja feito via teclado)
ou atalhos como acessar o arquivo de ajuda pela tecla F1.
Durante toda a codificao, iremos manipular a varivel MSG somente
atravs das funes GetMessage(), TranslateMessage() e DispatchMessage(). A
verificao de qual mensagem foi enviada e o processamento dela ser feito
pela funo WindowProc(), que ser explicada logo mais.
Vamos comear pela obteno da mensagem a ser processada, com a
funo GetMessage():
BOOL GetMessage(
LPMSG lpMsg, // ponteiro para estrutura de mensagem
HWND hWnd, // identificador da janela
UINT wMsgFilterMin,
wMsgFilterMin, // primeira mensagem
UINT wMsgFilterMax // ltima mensagem
);

O primeiro parmetro recebe um ponteiro para a varivel do tipo


para que a sua estrutura seja preenchida automaticamente pela funo.

MSG

O parmetro HWND hWnd receber o identificador da janela de onde as


mensagens esto sendo obtidas. Normalmente, deixamos esse parmetro como
NULL, pois assim podemos processar qualquer mensagem que pertena ao
programa, e no somente uma janela.
Os dois ltimos parmetros so utilizados para especificar o intervalo
inicial (wMsgFilterMin) e o final (wMsgFilterMax) do valor das mensagens que
sero processadas. Indicando zero para esses parmetros, a funo processar
todas as mensagens disponveis.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 2 As Peas do Programa

27

A funo pode retornar trs valores diferentes: zero se a mensagem


obtida for WM_QUIT; -1 caso tenha ocorrido um erro; ou um nmero diferente de
zero caso no tenha ocorrido nenhuma das alternativas anteriores.
Depois de obtida a mensagem, as mensagens de teclas virtuais sero
traduzidas para mensagens de caracteres com a funo TranslateMessage():
BOOL TranslateMessage(
CONST MSG *lpMsg // ponteiro para estrutura de mensagem
);

O nico parmetro da funo recebe um ponteiro para a varivel do


tipo MSG para que sua mensagem seja traduzida (caso a mensagem seja de teclas
virtuais). O retorno diferente de zero se a mensagem foi traduzida (uma
mensagem de ao de teclado foi enviada fila de mensagens) ou zero se no
foi traduzida.
Para finalizar a codificao do loop, devemos enviar a mensagem
obtida para a funo que processa as mensagens do programa, atravs da
funo DispatchMessage():
LONG DispatchMessage(
CONST MSG *lpmsg // ponteiro para estrutura de mensagem
);

O parmetro CONST MSG *lpmsg recebe um ponteiro para a estrutura de


mensagem MSG indicando que essa estrutura ser enviada ao processador de
mensagens. O retorno da funo especifica o valor retornado pelo processador
de mensagens; esse valor depende da mensagem que foi enviada, porm
geralmente o valor retornado pode ser ignorado.
O loop de mensagens codificado conforme a Listagem 2.1:
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
Listagem 2.1: O loop de mensagens.

Note que, no comando while(), verificado se a funo GetMessage()


retorna um valor maior que zero, pois ela tambm pode retornar 1 no caso de
erro.
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

28

Programao Windows: C e Win32 API com nfase em Multimdia

Dica: o loop de mensagens (e, conseqentemente, o programa) pra de ser


executado quando GetMessage() retornar o valor WM_QUIT.
Para uma melhor visualizao e entendimento de como o loop de
mensagens e a funo WindowProc() se comunicam, veja a Figura 2.2.

Figura 2.2: Comunicao entre o loop de mensagens e a WindowProc().

Processando mensagens
Para o funcionamento do nosso programa, preciso que as mensagens
enviadas pelo Windows sejam processadas, e isso feito atravs da funo
WindowProc(), que uma funo j definida para todos os programas (essa a
tal funo especial que foi mencionada no segundo pargrafo do captulo 1).
Seu prottipo tem o seguinte aspecto:
LRESULT CALLBACK WindowProc(
HWND hWnd, // identificador da janela
UINT uMsg, // identificador da mensagem
WPARAM wParam, // primeiro parmetro da mensagem
LPARAM lParam // segundo parmetro da mensagem
);

Essa uma funo diferente de todas as outras do seu programa, pois


voc no faz nenhuma chamada ela; o Windows faz por voc. Por esse
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 2 As Peas do Programa

29

motivo, a funo tem o retorno do tipo LRESULT CALLBACK, significando que ela
chamada pelo sistema e retorna ao Windows. O valor de retorno o
resultado do processamento da mensagem, o qual depende da mensagem
enviada.
Quanto aos seus parmetros, a funo WindowProc() recebe um
identificador da janela principal (HWND hWnd), a mensagem a ser processada, UINT
uMsg (note que essa mensagem no a mesma do loop de mensagens a do
loop uma varivel do tipo MSG), e dois parmetros (WPARAM wParam e LPARAM
lParam) que podem conter informaes adicionais sobre a mensagem por
exemplo, na mensagem de movimento de mouse (WM_MOUSEMOVE), wParam indica
se algum boto do mouse est pressionado e lParam armazena a posio (x, y)
do cursor do mouse.
Existem centenas de mensagens que o seu programa poder receber
pelo Windows, porm nem sempre todas so verificadas (a Tabela 2.7 lista as
principais mensagens que so utilizadas/processadas). Para essas, devemos
deixar o prprio Windows process-las, atravs do uso de uma funo
chamada DefWindowProc(), que uma funo de processamento de mensagens
padro do Windows. Ela recebe os mesmos parmetros da WindowProc() e
processa qualquer mensagem que no foi feita pelo seu programa, assegurando
que todas as mensagens sejam verificadas e processadas.
Mensagem
WM_ACTIVATE
WM_CHAR
WM_CLOSE
WM_COMMAND

WM_CREATE

WM_DESTROY

Descrio
Enviada quando a janela ativada.
Enviada quando uma mensagem WM_KEYDOWN
traduzida pela funo TranslateMessage().
Enviada quando a janela fechada.
Enviada quando o usurio seleciona um item
de um menu, quando um controle (boto,
scrollbar, etc) envia uma mensagem para a
janela-pai ou quando uma tecla de atalho
ativada.
Enviada quando a janela criada pela funo
CreateWindowEx(). Essa mensagem enviada
funo de processamento de mensagens aps a
janela ser criada, mas antes dela se tornar
visvel.
Enviada quando a janela destruda. Essa
mensagem enviada funo de

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

30

Programao Windows: C e Win32 API com nfase em Multimdia

WM_ENABLE

WM_KEYDOWN

WM_KEYUP
WM_LBUTTONDOWN

WM_LBUTTONUP

WM_MBUTTONDOWN

WM_MBUTTONUP

WM_RBUTTONDOWN

WM_RBUTTONUP

WM_MOUSEMOVE
WM_MOVE
WM_PAINT
WM_QUIT
WM_SHOWWINDOW
WM_SIZE
WM_TIMER

processamento de mensagens aps a janela ser


removida da tela.
Enviada quando o programa modifica o estado
disponvel/no disponvel de uma janela. Essa
mensagem enviada para a janela que est
tendo seu estado modificado.
Enviada quando uma tecla que no do
sistema pressionada, ou seja, quando a tecla
ALT no est pressionada.
Enviada quando uma tecla que no do
sistema solta.
Enviada quando o usurio pressiona o boto
esquerdo do mouse quando o cursor est
dentro da janela do programa.
Enviada quando o usurio solta o boto
esquerdo do mouse quando o cursor est
dentro da janela do programa.
Enviada quando o usurio pressiona o boto
central do mouse quando o cursor est dentro
da janela do programa.
Enviada quando o usurio solta o boto central
do mouse quando o cursor est dentro da
janela do programa.
Enviada quando o usurio pressiona o boto
direito do mouse quando o cursor est dentro
da janela do programa.
Enviada quando o usurio solta o boto direito
do mouse quando o cursor est dentro da
janela do programa.
Enviada quando o cursor do mouse movido.
Enviada aps a janela ser movida.
Enviada quando a janela precisa ser atualizada.
Enviada quando o programa chama a funo
PostQuitMessage().
Enviada quando a janela for escondida ou
restaurada.
Enviada depois que a janela mudou de
tamanho.
Enviada quando um Timer definido no

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 2 As Peas do Programa

31

programa expira.
Tabela 2.7: Principais mensagens enviadas ao programa.

Segue a codificao (Listagem 2.2) demonstrando o corpo bsico da


funo WindowProc() e como processar as mensagens:
//------------------------------------------------------------------------// WindowProc() -> Processa as mensagens enviadas para o programa
//-------------------------------------------------------------------------LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
// Variveis para manipulao da parte grfica do programa
HDC hDC = NULL;
PAINTSTRUCT psPaint;
// Verifica qual foi a mensagem enviada
switch(uMsg)
{
case WM_CREATE: // Janela foi criada
{
// Retorna 0, significando que a mensagem foi processada corretamente
return(0);
} break;
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{
/* Devemos avisar manualmente ao Windows que a janela j foi
atualizada, pois no um processo automtico. Se isso no for feito, o
Windows no ir parar de enviar a mensagem WM_PAINT ao programa. */
// O cdigo abaixo avisa o Windows que a janela j foi atualizada.
hDC = BeginPaint(hWnd, &psPaint);
EndPaint(hWnd, &psPaint);
return(0);
} break;
case WM_CLOSE: // Janela foi fechada
{
// Destri a janela
DestroyWindow(hWnd);
return(0);
} break;
case WM_DESTROY: // Janela foi destruda
{
// Envia mensagem WM_QUIT para o loop de mensagens
PostQuitMessage(WM_QUIT);
return(0);
} break;
default: // Outra mensagem
{

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

32

Programao Windows: C e Win32 API com nfase em Multimdia

/* Deixa o Windows processar as mensagens que no foram verificadas na


funo */
return(DefWindowProc(hWnd, uMsg, wParam, lParam));
}
}
}
Listagem 2.2: Exemplo da funo WindowsProc().

No exemplo acima, foram verificadas apenas quatro mensagens,


WM_CREATE, WM_PAINT, WM_CLOSE e WM_DESTROY. Note que sempre quando uma
mensagem for processada, devemos retornar zero, indicando que a mensagem
j foi processada e que o Windows no precisa tentar process-la novamente.
J as mensagens que no foram processadas so passadas para a funo
DefWindowProc(), onde o Windows faz o trabalho do processo das mensagens.
Quando enviada uma mensagem WM_CLOSE para a janela, o programa
destri a janela atravs da funo DestroyWindow(), o que acaba gerando outra
mensagem, a WM_DESTROY.
BOOL DestroyWindow(
HWND hWnd // identificador da janela a ser destruda
);
DestroyWindow() recebe como parmetro o identificador da janela que
ser destruda. A funo tambm destri o menu da janela, timers e limpa a fila
de mensagens, alm de gerar a mensagem WM_DESTROY. No processamento da
mensagem WM_DESTROY, chamamos a funo PostQuitMessage().
VOID PostQuitMessage(
int nExitCode // cdigo de sada
);

Essa funo indica ao sistema que uma foi feito um pedido para que o
programa termine. O parmetro int nExitCode especifica o cdigo de sada do
programa e utilizado como o parmetro wParam da mensagem WM_QUIT
(lembre-se que aps o loop de mensagens receber WM_QUIT, o programa
finalizado com a WinMain() retornando o valor de msg.wParam).
O processo da mensagem WM_PAINT ser discutido no captulo 4, que
introduz a utilizao da parte grfica do Windows (GDI Graphics Device
Interface).

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 2 As Peas do Programa

33

Agora vamos juntar todo o conhecimento obtido nesse captulo e criar


o programa demonstrado no incio, conforme a Listagem 2.3:
//-------------------------------------------------------------------------// prog02.cpp Esqueleto completo de um programa Windows
//-------------------------------------------------------------------------//-------------------------------------------------------------------------// Bibliotecas
//-------------------------------------------------------------------------#include <windows.h>
//-------------------------------------------------------------------------// Definies
//-------------------------------------------------------------------------// Nome da classe da janela
#define WINDOW_CLASS
"prog02"
// Ttulo da janela
#define WINDOW_TITLE
"Prog 02"
// Largura da janela
#define WINDOW_WIDTH
320
// Altura da janela
#define WINDOW_HEIGHT
240
//-------------------------------------------------------------------------// Prottipo das funes
//-------------------------------------------------------------------------LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
//-------------------------------------------------------------------------// WinMain() -> Funo principal
//-------------------------------------------------------------------------int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// Cria a classe da janela e especifica seus atributos
WNDCLASSEX wcl;
wcl.cbSize = sizeof(WNDCLASSEX);
wcl.style = CS_HREDRAW | CS_VREDRAW;
wcl.lpfnWndProc = (WNDPROC)WindowProc;
wcl.cbClsExtra = 0;
wcl.cbWndExtra = 0;
wcl.hInstance = hInstance;
wcl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
wcl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wcl.lpszMenuName = NULL;
wcl.lpszClassName = WINDOW_CLASS;
wcl.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
// Registra a classe da janela
if(RegisterClassEx(&wcl))
{
// Cria a janela principal do programa
HWND hWnd = NULL;
hWnd = CreateWindowEx(

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

34

Programao Windows: C e Win32 API com nfase em Multimdia


NULL,
WINDOW_CLASS,
WINDOW_TITLE,
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
(GetSystemMetrics(SM_CXSCREEN) - WINDOW_WIDTH) / 2,
(GetSystemMetrics(SM_CYSCREEN) - WINDOW_HEIGHT) / 2,
WINDOW_WIDTH,
WINDOW_HEIGHT,
HWND_DESKTOP,
NULL,
hInstance,
NULL);
// Verifica se a janela foi criada
if(hWnd)
{
// Mostra a janela
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Armazena dados da mensagem que ser obtida
MSG msg;
// Loop de mensagens, enquanto mensagem no for WM_QUIT,
// obtm mensagem da fila de mensagens
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
// Traduz teclas virtuais ou aceleradoras (de atalho)
TranslateMessage(&msg);
// Envia mensagem para a funo que processa mensagens (WindowProc)
DispatchMessage(&msg);
}

// Retorna ao Windows com valor de msg.wParam


return(msg.wParam);
}
// Se a janela no foi criada
else
{
// Exibe mensagem de erro e sai do programa
MessageBox(NULL, "No foi possvel criar janela.", "Erro!", MB_OK |
MB_ICONERROR);
return(0);
}
}
// Se a classe da janela no foi registrada
else
{
// Exibe mensagem de erro e sai do programa
MessageBox(NULL, "No foi possvel registrar
"Erro!", MB_OK | MB_ICONERROR);
return(0);
}

classe

// Retorna ao Windows sem passar pelo loop de mensagens


return(0);
}

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

da

janela.",

Captulo 2 As Peas do Programa

35

//-------------------------------------------------------------------------// WindowProc() -> Processa as mensagens enviadas para o programa


//-------------------------------------------------------------------------LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
// Variveis para manipulao da parte grfica do programa
HDC hDC = NULL;
PAINTSTRUCT psPaint;
// Verifica qual foi a mensagem enviada
switch(uMsg)
{
case WM_CREATE: // Janela foi criada
{
// Retorna 0, significando que a mensagem foi processada corretamente
return(0);
} break;
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{
/* Devemos avisar manualmente ao Windows que a janela j foi
atualizada, pois no um processo automtico. Se isso no for feito, o
Windows no ir parar de enviar a mensagem WM_PAINT ao programa. */
// O cdigo abaixo avisa o Windows que a janela j foi atualizada.
hDC = BeginPaint(hWnd, &psPaint);
EndPaint(hWnd, &psPaint);
return(0);
} break;
case WM_CLOSE: // Janela foi fechada
{
// Destri a janela
DestroyWindow(hWnd);
return(0);
} break;
case WM_DESTROY: // Janela foi destruda
{
// Envia mensagem WM_QUIT para o loop de mensagens
PostQuitMessage(WM_QUIT);
return(0);
} break;
default: // Outra mensagem
{
/* Deixa o Windows processar as mensagens que no foram verificadas na
funo */
return(DefWindowProc(hWnd, uMsg, wParam, lParam));
}
}
}
Listagem 2.3: O programa completo para criar a janela.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

36

Programao Windows: C e Win32 API com nfase em Multimdia

C++ explicado: observe o cdigo da funo WinMain(), onde ocorre a


declarao das variveis HWND hWnd e MSG msg no meio da funo. Em C++,
permitido declarar variveis em qualquer parte do cdigo, e no
necessariamente no comeo da funo, como na linguagem C.
Nesse programa, foram declaradas quatro #define para facilitar um
pouco a construo do programa, pois caso haja necessidade de modificar o
nome da classe da janela, o ttulo e/ou o tamanho da janela, podemos
modificar essas #define, que so utilizadas em diferentes lugares do cdigo.
Nota: a classe da janela poderia ser declarada e diretamente inicializada,
eliminando a necessidade de digitar diversas linhas de atribuio aos
membros da classe:
WNDCLASSEX wcl = {
sizeof(WNDCLASSEX),
CS_OWNDC | CS_HREDRAW | CS_VREDRAW,
(WNDPROC)WindowProc,
0,
0,
hInstance,
LoadIcon(NULL,IDI_APPLICATION),
LoadCursor(NULL,IDC_ARROW),
(HBRUSH)GetStockObject(WHITE_BRUSH),
NULL,
WINDOW_CLASS,
LoadIcon(NULL,IDI_APPLICATION)
};

O programa verifica se a classe da janela foi registrada e tambm se no


ocorreram erros para criar a janela principal do programa. Caso alguma das
duas etapas tenha falhado, uma mensagem de erro emitida ao usurio e o
programa finaliza sem passar pelo loop de mensagens.
Ao invs de pr-determinarmos uma posio (x, y) inicial da janela,
para efeitos de esttica, podemos iniciar o programa com sua janela bem no
meio da tela, bastando utilizar uma simples frmula que calcula a posio
centralizada.
Para isso, devemos obter as configuraes de largura e altura utilizadas
pelo computador, usando a funo GetSystemMetrics(), que foi chamada duas
vezes dentro da funo CreateWindowEx():

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 2 As Peas do Programa

37

HWnd = CreateWindowEx(
...
(GetSystemMetrics(SM_CXSCREEN) - WINDOW_WIDTH) / 2,
(GetSystemMetrics(SM_CYSCREEN) - WINDOW_HEIGHT) / 2,
...);

A funo GetSystemMetrics() retorna diversos valores sobre a


configurao do sistema. O seu prottipo mostrado a seguir:
int GetSystemMetrics(
int nIndex // valor da configurao a ser retornado
);

A funo retorna zero se ocorreu algum erro ou ento retorna o valor


da configurao que foi requisitado no parmetro int nIndex. O parmetro da
funo pode receber diversos valores, como mostra a Tabela 2.8. Todas as
dimenses retornadas pela funo so em pixels (pontos); os valores que
iniciam com SM_CX* so largura e os que comeam com SM_CY* so altura.
Valor
SM_CLEANBOOT

SM_CMONITORS

SM_CMOUSEBUTTONS
SM_CXBORDER,
SM_CYBORDER

SM_CXCURSOR,
SM_CYCURSOR

Descrio
Valor que especifica como o sistema foi
iniciado:
0 Boot normal
1 Boot em modo de segurana
2 Boot em modo de segurana com rede
Nmero de monitores no desktop (apenas
para Windows NT 5.0 ou superior e Windows
98 ou superior).
Nmero de botes do mouse, ou zero se no
h mouse instalado.
Largura e altura da borda da janela.
Equivalente ao valor de SM_CXEDGE e SM_CYEDGE
para janelas com visual 3D.
Largura e altura do cursor.

SM_CXEDGE,
SM_CYEDGE

Dimenses de uma borda 3D.

SM_CXFIXEDFRAME,
SM_CYFIXEDFRAME

Espessura do quadro em volta do permetro


de uma janela que tem ttulo, mas no
redimensionvel. SM_CXFIXEDFRAME a largura da
borda horizontal e SM_CYFIXEDFRAME a altura
da borda vertical.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

38

Programao Windows: C e Win32 API com nfase em Multimdia

SM_CXFULLSCREEN,
SM_CYFULLSCREEN
SM_CXMAXIMIZED,
SM_CYMAXIMIZED
SM_CXMIN,
SM_CYMIN

Largura e altura da rea de uma janela em tela


cheia.
Dimenses padres
de
uma
janela
maximizada.
Largura e altura mnima de uma janela.

SM_CXMINIMIZED,
SM_CYMINIMIZED

Dimenses de uma janela normal minimizada.

SM_CXSCREEN,
SM_CYSCREEN

Largura e altura da tela do monitor.

SM_CXSIZE,
SM_CYSIZE

Largura e altura de um boto na barra de


ttulo.
Altura de uma rea de ttulo.
TRUE para mouse instalado ou FALSE caso
contrrio.
O bit menos significante acionado se h rede
detectada.

SM_CYCAPTION
SM_MOUSEPRESENT
SM_NETWORK

Tabela 2.8: Alguns valores de configurao do sistema que podem ser obtidos com GetSystemMetrics().

Enviando mensagens
Quando os usurios utilizam nossos programas, eles esto
indiretamente gerando mensagens a serem processadas (cliques de mouse, uso
do teclado, mudana de posio ou tamanho da janela, etc). Ns, como
programadores, podemos enviar mensagens explicitamente para serem
processadas pela WindowProc().
Um exemplo do envio de mensagens pode ser a seguinte: quando o
usurio pressiona a tecla F3 (gerando a mensagem WM_KEYDOWN, como veremos
no captulo 4), o texto da barra de ttulo do nosso programa muda para F3
pressionado. Nesse exemplo, o usurio est gerando apenas a mensagem
WM_KEYDOWN quando aperta a tecla; a mudana do texto da barra de ttulo deve
ser feita via programao. Existe uma mensagem, WM_SETTEXT, que pode ser
enviada ao programa para mudar o texto da janela. Mas como enviar
mensagens fila de mensagens do programa?
Podemos utilizar duas funes: SendMessage() e PostMessage(). A
primeira funo envia a mensagem especificada diretamente para a
WindowProc() e no retornada at que a mensagem seja processada. A segunda
coloca a mensagem na fila de mensagens e retorna imediatamente
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 2 As Peas do Programa

39

(independente da mensagem j ter sido processada ou no). Mensagens


enviadas com PostMessage() so enviadas WindowProc() pelo loop de
mensagens.
LRESULT SendMessage(
HWND hWnd, // identificador da janela-destino
UINT Msg, // mensagem a ser enviada
WPARAM wParam, // informao adicional da mensagem
LPARAM lParam // informao adicional da mensagem
);

Essa funo recebe o identificador da janela-destino da mensagem


(pode ser a janela principal do programa, uma caixa de texto, um boto, etc) no
primeiro parmetro. A mensagem que ser enviada informada no segundo
parmetro; o terceiro (wParam) e o quarto (lParam) parmetro podem receber
informaes adicionais da mensagem (caso a mesma necessite). O retorno da
funo indica o resultado do processamento da mensagem e depende da
mensagem enviada.
BOOL PostMessage(
HWND hWnd, // identificador da janela-destino
UINT Msg, // mensagem a ser enviada
WPARAM wParam, // informao adicional da mensagem
LPARAM lParam // informao adicional da mensagem
);

A funo PostMessage() recebe os mesmos parmetros da funo


porm, retorna um valor diferente de zero se no houver erros,
ou zero caso contrrio.
SendMessage(),

No exemplo citado nesse tpico, faramos a codificao da Listagem


2.4 para modificar o texto da barra de ttulo do programa. No se preocupe
sobre a mensagem WM_KEYDOWN, pois ela ser estudada no captulo 4.
LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg)
{
// mensagens...
case WM_KEYDOWN: // Obtm tecla virtual
{
// Verifica se tecla pressionada foi F3
if(wParam == VK_F3)
// Envia mensagem WM_SETTEXT para a janela principal (hWnd)
SendMessage(hWnd, WM_SETTEXT, (WPARAM)0, (LPARAM)"F3 pressionado");
return(0);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

40

Programao Windows: C e Win32 API com nfase em Multimdia


} break;
// mensagens...

}
}
Listagem 2.4: Enviando mensagens.

A mensagem WM_SETTEXT tem uma informao adicional em lParam, que


recebe o texto que ser utilizado na barra de ttulo. Em wParam no h nenhuma
informao e devemos passar zero para ela.
Chegamos ao fim desse captulo. No prximo, veremos como trabalhar
com os arquivos de recursos, adicionando ao programa cones/cursores
personalizados, imagens, sons, menus e caixas de dilogos.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

41

Captulo 3 Arquivos de Recursos


A maioria dos programas para Windows possui menus, cones
personalizados (alguns incluem at cursores modificados) e caixas de dilogo
(janelas como a da formatao de fonte em um editor de textos). Todos esses
componentes (e mais alguns) do programa podem ser utilizados atravs do uso
de arquivos de recursos (tambm conhecidos como scripts de recursos).
Arquivos de recursos podem ser criados em qualquer editor de textos
no formato ASCII (como o Bloco de Notas), dentro da IDE do seu
compilador, quando o mesmo possuir um editor de recursos (caso do
Microsoft Visual C++ e Dev-C++) ou atravs de um programa editor de
recursos. No caso de editores de recursos com interface visual (clique-earraste), o contedo do arquivo gerado automaticamente pelo editor.
Esses arquivos tm extenso .rc e o contedo definido com palavraschave em ingls, indicando os recursos que sero utilizados pelo programa. Os
arquivo so ento compilados, criando-se arquivos binrios com extenso .res,
que so anexados ao final do programa executvel, podendo ser carregados em
tempo de execuo (veja o esquema da Figura 3.1).

Figura 3.1: Incluso dos recursos no programa executvel.

Vamos aprender como criar um arquivo de recursos sem usar nenhum


editor visual; assim, voc poder entender a estrutura do arquivo e como
funcionam os editores.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

42

Programao Windows: C e Win32 API com nfase em Multimdia

IDs
Os recursos so reconhecidos pelo programa atravs de nmeros
inteiros e positivos, definidos num arquivo de cabealho .h. Esses nmeros so
conhecidos como sendo os IDs dos recursos. A Win32 API possui algumas
funes que no aceitam variveis-identificadores (handles) como parmetro, e
sim IDs de controles (botes, caixas de texto, etc) e recursos (cones, menus,
etc), como a funo LoadIcon().
ID no um tipo de varivel, e sim apenas uma definio, como
podemos verificar num arquivo .h de exemplo:
// cabealho dos recursos (arquivo .h)
#define IDI_MEUICONE
101
#define IDC_MEUCURSOR
102

Os nmeros referentes ao ID no precisam estar necessariamente na


ordem, mas importante que eles sejam diferentes e que sejam maiores que
100 (nmeros menores que 100 so utilizados pelos IDs dos recursos
definidos pelo sistema).
Sempre usaremos um arquivo de cabealho (como no exemplo)
contendo os IDs dos recursos, quando esses forem utilizados. No arquivo de
recursos .rc, temos que incluir a diretiva:
#include arquivo_de_cabealho.h

Onde arquivo_de_cabealho.h o nome do arquivo de cabealho.

cones personalizados
O primeiro recurso que aprenderemos a incluir no programa o cone.
Com o editor de textos ASCII aberto, digitamos a seguinte linha no arquivo .rc:
IDI_MEUICONE

ICON

meuicone.ico"

Observe a palavra ICON em negrito. Ela a palavra-chave que indica que


um ID para o arquivo de cone de nome meuicone.ico. O ID
IDI_MEUICONE pode ter qualquer outro nome, desde que seja definido no arquivo
de cabealho dos recursos. A string meuicone.ico (incluindo as aspas duplas)
informa o caminho e o nome do arquivo a ser inserido como cone de recurso.

IDI_MEUICONE

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

43

Depois de criado os arquivos .h e .rc, devemos inclu-los no projeto do


nosso programa (geralmente dentro da IDE do compilador) e modificar alguns
trechos da funo WinMain() e incluir um #include no cdigo-fonte.
Nota: sugiro a leitura da documentao do seu compilador, tanto para
aprender como incluir arquivos no projeto quanto para verificar como criar
executveis Win32 utilizando recursos.
Antes de seguir para a modificao do cdigo-fonte do programa,
vamos verificar o contedo dos arquivo .h e .rc, nas Listagens 3.1 e 3.2,
respectivamente:
//-------------------------------------------------------------------------// prog03-1-res.h - Cabealho dos recursos
//-------------------------------------------------------------------------#define IDI_MEUICONE

101
Listagem 3.1: O arquivo de cabealho.

//-------------------------------------------------------------------------// prog03-1-res.rc - Arquivo de recursos


//-------------------------------------------------------------------------#include "prog03-1-res.h"
IDI_MEUICONE

ICON

"meuicone.ico"
Listagem 3.2: O arquivo de recursos.

Para usar o cone do arquivo de recursos, as seguintes modificaes no


arquivo prog03-1.cpp devem ser feitas, em relao ao arquivo prog02.cpp
(Listagem 3.1):
//-------------------------------------------------------------------------// prog03-1.cpp - cones personalizados
//-------------------------------------------------------------------------//-------------------------------------------------------------------------// Bibliotecas
//-------------------------------------------------------------------------#include <windows.h>
// --- linha adicionada --// Cabealho dos recursos
#include "prog03-1-res.h"
// cdigo omitido (veja o cdigo completo no CD-ROM)
int WINAPI WinMain(...)
{
// cdigo omitido (veja o cdigo completo no CD-ROM)

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

44

Programao Windows: C e Win32 API com nfase em Multimdia

// --- linha modificada --// Carrega cone do recurso


wcl.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MEUICONE));
// --- linha modificada --// Carrega cone do recurso
wcl.hIconSm = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MEUICONE));
// cdigo omitido (veja o cdigo completo no CD-ROM)
}
Listagem 3.1: Usando cones personalizados.

No trecho do cdigo da Listagem 3.1, inclumos a diretiva #include


para que o programa possa reconhecer o ID do cone
personalizado. Tambm modificamos duas linhas referentes aos membros de
cone (hIcon e hIconSm) da estrutura WNDCLASSEX, utilizando a funo LoadIcon()
para carregar o cone dos recursos.
prog03-1-res.h,

Conforme explicado no captulo anterior, devemos passar a varivel


no primeiro parmetro de LoadIcon() e o nome do cone no segundo,
quando estamos utilizando cones personalizados. Porm, ao invs de passar
apenas o ID do cone, foi utilizada a macro MAKEINTRESOURCE().
hInstance

A macro MAKEINTRESOURCE() deve ser utilizada quando precisamos


converter um ID (que um nmero) para uma string, somente nos parmetros
de funes que podem receber esse tipo de converso (funes que podem
obter dados dos recursos). Caso passssemos somente o ID do cone, ocorreria
um erro de tipos diferentes (int e string) durante a compilao.
Podemos ver o programa com o cone personalizado (que est em
destaque no canto superior direito) na Figura 3.2.
Dica: podemos mudar o cone de uma janela em tempo de execuo,
bastando enviar a mensagem WM_SETICON para o programa. O parmetro
wParam pode receber ICON_BIG ou ICON_SMALL e lParam recebe o identificador
do cone. Exemplo: SendMessage(hWnd, WM_SETICON, (WPARAM)ICON_BIG,
(LPARAM)LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MEUICONE)));

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

45

Figura 3.2: Programa com cone personalizado.

Novos cursores
O prximo recurso que veremos o cursor. Sua definio no arquivo
de recursos muito semelhante ao cone:
IDC_MEUCURSOR

CURSOR meucursor.cur

A palavra-chave CURSOR indica o ID (IDC_MEUCURSOR, no exemplo) para o


arquivo do cursor (meucursor.cur), semelhante palavra-chave ICON como j
vimos.
Para utilizar o novo cursor no programa, basta modificar a seguinte
linha da funo WinMain():
wcl.hCursor = LoadCursor(NULL, IDC_ARROW);

Para a linha abaixo:


wcl.hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_MEUCURSOR));

Lembrando que sempre devemos adicionar o arquivo de cabealho dos


recursos (.h) e o arquivo de recursos (.rc) no projeto. Veja os arquivos prog03-2-

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

46

Programao Windows: C e Win32 API com nfase em Multimdia

res.h, prog03-2-res.rc e prog03-2.cpp no CD-ROM, com o exemplo do uso de


cursores diferentes.

Bitmaps e sons
Imagens (bitmaps) e sons so dois recursos multimdia que podemos
incluir em nossos programas. A definio de ambos no arquivo de recursos
tambm muito parecida com a de cones e cursores:
IDB_MEUBITMAP
IDW_MEUSOM

BITMAP meubitmap.bmp
WAVE
meusom.wav

As palavras-chaves WAVE e BITMAP indicam os IDs de arquivos de som e


imagem, respectivamente.
No vamos aprender como carregar sons nem bitmaps por enquanto,
pois h captulos especficos para cada um desses assuntos. Apenas citei esses
dois recursos para que voc saiba que eles tambm podem ser inclusos no
programa e como so definidos no arquivo de recursos.
Dica: mesmo que no vamos aprender sobre imagens e sons no momento,
h um programa (prog03-3.cpp) no CD-ROM que carrega bitmaps e sons
dos recursos. Veja os arquivos prog03-3.cpp, prog03-3-res.h e prog03-3-res.rc
caso queira saber como o programa foi feito.

Informaes sobre a verso do programa


Embora nem todas as pessoas tenham conhecimento sobre esse
recurso, possvel adicionar algumas informaes sobre direitos autorais e
verso do programa. No Windows, essas informaes podem ser encontradas
quando visualizamos as propriedades de um arquivo .exe, .dll, .drv, .fon, .fnt, .vxd
ou .lib, como na Figura 3.3.
Esse recurso pode ser til para manter o controle de verses do
programa, para o usurio saber o nome original do arquivo (caso seja
renomeado) ou mesmo para manter informaes sobre os direitos autorais. No
Windows XP, por exemplo, algumas informaes desse recurso so utilizadas
pelo Windows Explorer (Figura 3.4), quando os arquivos so exibidos com a
opo do menu Exibir... Lado a Lado.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

47

Figura 3.3: Propriedades do arquivo prog03-4.exe.

Figura 3.4: Informaes utilizadas pelo Windows Explorer (no Windows XP).

A incluso das informaes sobre a verso do programa (ou biblioteca


DLL, driver de dispositivo, etc) utiliza mais palavras-chaves que os recursos
vistos at agora e no necessita de IDs.
A estrutura para definir o recurso de informao de verso a seguinte
(Listagem 3.2):
1 VERSIONINFO
FILEVERSION n1,n2,n3,n4
PRODUCTVERSION n1,n2,n3,n4
FILEFLAGSMASK fileflagsmask
FILEFLAGS fileflags
FILEOS fileos
FILETYPE filetype
FILESUBTYPE subtype
{
BLOCK "StringFileInfo"
{
BLOCK "lang-charset"
"
{

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

48

Programao Windows: C e Win32 API com nfase em Multimdia


VALUE
VALUE
VALUE
VALUE
VALUE
VALUE
VALUE
VALUE
VALUE
VALUE
VALUE
VALUE

"CompanyName", "texto"
"
"FileDescription", "texto"
"
"FileVersion", "texto"
"
"InternalName",
"
"InternalName", "texto"
"LegalCopyright", "texto"
"
"LegalTrademarks", "texto"
"
"OriginalFilename", "texto"
"
PrivateBuild, "texto"
"
"ProductName", "texto"
"
"ProductVersion", "texto"
"
SpecialBuild,
"
SpecialBuild, "texto"
"Comentrios",
", "texto"
"
"

}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", langID, charsetID
}
}
Listagem 3.2: Estrutura do recurso informao de verso.

A primeira linha deve ser definida como 1 VERSIONINFO. A segunda


linha, FILEVERSION n1,n2,n3,n4, especifica o nmero da verso do arquivo, onde
n1,n2,n3,n4 recebem quatro nmeros inteiros separados por vrgulas. A terceira
linha especifica o nmero da verso do produto o qual o arquivo est sendo
distribudo, onde n1,n2,n3,n4 recebem quatro nmeros inteiros separados por
vrgulas.
Nota: apenas as palavras que no esto em negrito na Listagem 3.2 que
podem ser modificadas. Palavras negritadas so palavras-chave.
A linha FILEFLAGSMASK fileflagsmask especifica quais bits informados
pela linha FILEFLAGS fileflags so vlidos. O parmetro fileflagsmask recebe
como padro 0x17L. Caso fileflags receba VS_FF_PRIVATEBUILD, devemos
somar 0x8L em fileflagsmask (note que a soma em hexadecimal). Quando
fileflags recebe VS_FF_SPECIALBUILD, somamos 0x20L em fileflagsmask. Se
tanto VS_FF_PRIVATEBUILD quanto VS_FF_SPECIALBUILD for especificado em
fileflags, devemos somar 0x28L em fileflagsmask.
O parmetro fileflags pode receber um ou mais valores da Tabela 3.1.
Valor
VS_FF_DEBUG
VS_FF_PATCHED

Descrio
Arquivo tem informaes de depurao ou foi
compilado no modo debug.
Arquivo foi modificado e no igual ao
original de mesmo nmero de verso.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos


VS_FF_PRERELEASE
VS_FF_PRIVATEBUILD

VS_FF_SPECIALBUILD

0x1L

49

Arquivo est em fase de desenvolvimento e


no um produto final.
Arquivo no foi criado utilizando padres do
modo release (final). Se esse valor for utilizado,
o bloco StringFileInfo precisa conter a
string PrivateBuild.
Arquivo foi criado pela empresa original
utilizando padres do modo release, mas
uma variao do arquivo de mesma verso. Se
esse valor for utilizado, o bloco
StringFileInfo
precisa conter a string
SpecialBuild.
Arquivo compilado no modo release.
Tabela 3.1: Valores para fileflags.

A linha FILEOS fileos especifica para qual sistema operacional o


arquivo foi desenvolvido. O parmetro fileos pode receber um dos valores da
Tabela 3.2.
Valor
VOS_UNKNOWN
VOS_DOS
VOS_NT
VOS__WINDOWS16
VOS__WINDOWS32
VOS_DOS_WINDOWS16
VOS_DOS_WINDOWS32
VOS_NT_WNDOWS32

Descrio
Sistema operacional para o qual o arquivo foi
desenvolvido desconhecido.
Arquivo foi desenvolvido para MS-DOS.
Arquivo foi desenvolvido para Windows
NT/2000/XP.
Arquivo foi desenvolvido para Windows
plataforma 16-bit.
Arquivo foi desenvolvido para Windows
plataforma 32-bit.
Arquivo foi desenvolvido para Windows
plataforma 16-bit rodando MS-DOS.
Arquivo foi desenvolvido para Windows
plataforma 32-bit rodando MS-DOS.
Arquivo foi desenvolvido para Windows
NT/2000/XP.
Tabela 3.2: Valores para fileos.

A linha FILETYPE filetype especifica de que tipo o arquivo, com


podendo receber um dos valores da Tabela 3.3.

filetype

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

50

Programao Windows: C e Win32 API com nfase em Multimdia

Valor

Descrio
Arquivo desconhecido.
Arquivo um aplicatico.
Arquivo uma biblioteca DLL.
Arquivo um driver de dispositivo. No caso,
subtype especifica mais detalhes do driver.
Arquivo uma fonte. No caso, subtype
especifica mais detalhes da fonte.
Arquivo um dispositivo virtual.
Arquivo uma biblioteca esttica.

VFT_UNKNOWN
VFT_APP
VFT_DLL
VFT_DRV
VFT_FONT
VFT_VXD
VFT_STATIC_LIB

Tabela 3.3: Valores para filetype.

A linha FILESUBTYPE subtype especifica mais detalhes do tipo de arquivo,


no caso de drivers (filetype recebe VFT_DRV) e fontes (filetype recebe VFT_FONT).
O parmetro subtype pode receber um dos valores da Tabela 3.4 no caso de
drivers, um dos valores da Tabela 3.5 no caso de fontes ou VFT2_UNKOWN em
outros casos.
Valor
VFT2_UNKNOWN
VFT2_DRV_COMM
VFT2_DRV_PRINTER
VFT2_DRV_KEYBOARD
VFT2_DRV_LANGUAGE
VFT2_DRV_DISPLAY
VFT2_DRV_MOUSE
VFT2_DRV_NETWORK
VFT2_DRV_SYSTEM
VFT2_DRV_INSTALLABLE
VFT2_DRV_SOUND
VFT2_DRV_VERSIONED_PRINTER

Descrio
Tipo do driver desconhecido.
Driver de comunicao.
Driver de impressora.
Driver de teclado.
Driver de lngua.
Driver de vdeo.
Driver de mouse.
Driver de rede.
Driver de sistema.
Driver de instalao.
Driver de som.
Driver de impressora (com verso).

Tabela 3.4: Valores de drivers para subtype.

Valor
VFT2_UNKNOWN
VFT2_FONT_RASTER
VFT2_FONT_VECTOR
VFT2_FONT_TRUETYPE

Descrio
Tipo de fonte desconhecida.
Fonte do tipo bitmap.
Fonte do tipo vetorial.
Fonte do tipo True Type.
Tabela 3.5: Valores de fontes para subtype.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

51

Depois de definirmos esses parmetros, devemos informar dois blocos


de tipos de informaes: de string e de varivel. Esses blocos devem estar entre
{ }, como se fossem cdigos de uma funo, conforme a estrutura da Listagem
3.2.
O primeiro bloco que vamos definir de string, BLOCK StringFileInfo.
Dentro desse bloco existe um outro definido como BLOCK lang-charset, onde
lang-charset a combinao da lngua (a Tabela 3.6 lista alguns valores) e o
tipo de caractere do programa em hexadecimal (a Tabela 3.7 lista alguns
valores).
Valor

Lngua
Alemo
Grego
Ingls americano
Ingls britnico
Espanhol
Finlands
Francs
Italiano
Japons
Portugus (Brasil)
Portugus (Portugal)

0407
0408
0409
0909
040A
040B
040C
0410
0411
0416
0816

Tabela 3.6: Alguns valores para lang-charset.

Valor (hexa)

Valor

0000

03A4

932

03B5

949

04B0

1200

04E2

1250

04E4

1252

04E7

1255

Tipo de caractere
ASCII 7-bit
Japo
Coria
Unicode
Europa oriental
Ocidente
Hebreu

Tabela 3.7: Alguns valores para lang-charset.

Poderamos definir a linha BLOCK lang-charset como BLOCK


041604E4, ou seja, o programa est em portugus do Brasil e usa caracteres do
ocidente.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

52

Programao Windows: C e Win32 API com nfase em Multimdia

Dentro do bloco lang-charset precisamos especificar informaes


sobre o arquivo, o produto e direitos autorais. Cada informao tem um nome
e propsito especfico e deve ser indicado no parmetro texto das linhas
VALUE Valor, Descrio. Veja cada um deles e para que servem na Tabela
3.8.
Valor
CompanyName
FileDescription
FileVersion
InternalName
LegalCopyright

LegalTrademarks

OriginalFilename

PrivateBuild

ProductName
ProductVersion
SpecialBuild

Descrio
Nome da empresa que produziu o arquivo.
Descrio do arquivo.
Verso do arquivo.
Nome interno do arquivo. Geralmente o
nome original do arquivo sem extenso.
Informaes de direitos autorais que se
aplicam ao arquivo. Essa informao
opcional.
Informaes de marcas registradas que se
aplicam ao arquivo. Essa informao
opcional.
Nome original do arquivo, sem o caminho.
Essa informao til para o programa
determinar se o arquivo foi renomeado pelo
usurio.
Informaes sobre uma verso particular do
arquivo. Essa informao s deve ser inclusa
se VS_FF_PRIVATEBUILD for especificado na linha
FILEFLAGS fileflags.
Nome do produto o qual o arquivo est sendo
distribudo junto.
Verso do produto o qual o arquivo est
sendo distribudo junto.
Especifica a diferena entre a verso desse
arquivo com sua verso padro. Essa
informao s deve ser inclusa se
VS_FF_SPECIALBUILD for especificado na linha
FILEFLAGS fileflags.
Informao adicional.

Comentrios /
Qualquer outro texto
Tabela 3.8: Informaes do bloco lang-charset.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

53

Definido essas informaes, fechamos os blocos lang-charset e


com duas } }. Precisamos agora definir o segundo bloco,
BLOCK VarFileInfo. Nesse bloco, informamos apenas um valor, atravs da
linha VALUE Translation, langID, charsetID. O parmetro langID recebe 0x
mais um dos valores da Tabela 3.6 e charsetID recebe um dos valores da Tabela
3.7 (valores decimais, segunda coluna). Para informar que o idioma do
programa portugus do Brasil e usa caracteres ocidentais, a linha ficaria com
os seguintes valores: VALUE Translation, 0x0416, 1252.
StringFileInfo

No precisamos modificar nem adicionar nenhuma linha de cdigo no


nosso programa (arquivo .cpp) para que o recurso de informaes de verso
seja incluso. Basta que a estrutura da Listagem 4.2 esteja dentro do arquivo .rc e
automaticamente o compilador incluir as informaes no executvel. Porm,
devemos incluir a diretiva #include <windows.h> no arquivo .rc, pois utilizamos
definies dessa biblioteca (como VOS_UKNOWN).
A Listagem 3.3 mostra o contedo do arquivo prog03-4-res.rc com a
definio do recurso de informaes sobre a verso do programa. Parte das
informaes podem ser vistas na Figura 3.3.
//-------------------------------------------------------------------------// prog03-4-res.rc - Arquivo de recursos
//-------------------------------------------------------------------------#include <windows.h>
#include "prog03-4-res.h"
IDI_MEUICONE
IDC_MEUCURSOR

ICON
CURSOR

"meuicone.ico"
"meucursor.cur"

1 VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x17L
FILEFLAGS 0x0L
FILEOS VOS__WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE VFT2_UNKNOWN
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "041604e4"
BEGIN
VALUE "CompanyName", "Andr Kishimoto"
VALUE "FileDescription", "Uso de recursos - VERSIONINFO"
VALUE "FileVersion", "1.0"
VALUE "InternalName", "prog03-4"
VALUE "LegalCopyright", "Copyright 2004, Andr Kishimoto"
VALUE "OriginalFilename", "prog03-4.exe"

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

54

Programao Windows: C e Win32 API com nfase em Multimdia

VALUE "ProductName", "Uso de recursos - VERSIONINFO"


VALUE "ProductVersion", "1.0"
VALUE "Comentrios", "Pode escrever qualquer coisa"
VALUE "...psiu!", "Programar jogos muito legal!"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x416, 1252
END
END
Listagem 3.3: Definindo informaes sobre o programa.

Dica: no arquivo de recursos, tambm podemos utilizar as palavras-chave


BEGIN...END ao invs de {...}, como na Listagem 3.3, dando um visual de
linguagem Pascal para a definio dos recursos.

Definindo menus e teclas de atalho


Vamos aprender agora a criar um recurso bsico para 99% dos
programas Windows: menus e teclas de atalho. Um menu composto por uma
lista de opes, como na Figura 3.5, que, quando selecionadas, executam certa
ao. Um menu tambm pode conter sub-menus, com mais opes e tambm
mais sub-menus, criando uma hierarquia de opes.

Figura 3.5: Hierarquia de opes de um menu.

Para criarmos um menu, utilizamos o seguinte esqueleto no arquivo de


recursos (Listagem 3.4):

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

55

IDM_MEUMENU
MENU
{
POPUP "menu1"
", tipos (opcional)
"
{
MENUITEM "item1",
", ID_DO_MENU1_ITEM1,
"
ID_DO_MENU1_ITEM1 tipos (opcional)
MENUITEM "item2",
", ID_DO_MENU1_ITEM2,
"
ID_DO_MENU1_ITEM2 tipos (opcional)
MENUITEM "itemX",
", ID_DO_MENU1_ITEMX,
"
ID_DO_MENU1_ITEMX tipos (opcional)
}
POPUP "menu2"
", tipos (opcional)
"
{
MENUITEM "item1",
", ID_DO_MENU2_ITEM1,
"
ID_DO_MENU2_ITEM1 tipos (opcional)
MENUITEM "item2",
", ID_DO_MENU2_ITEM2,
"
ID_DO_MENU2_ITEM2 tipos (opcional)
MENUITEM "itemX",
", ID_DO_MENU2_ITEMX
"
ID_DO_MENU2_ITEMX,
MENU2_ITEMX tipos (opcional)
}
}
Listagem 3.4: Esqueleto de um menu.

A palavra-chave MENU indica o ID do menu, que no esqueleto


IDM_MEUMENU. Aps essa definio do ID, devemos abrir um bloco de cdigo
com { (ou BEGIN).
A palavra-chave POPUP cria um menu-pai, que servir para listar os
itens (opes) do menu. O parmetro tipos opcional e pode receber um dos
valores da Tabela 3.9 para modificar a aparncia do menu. Para definir um
menu com mais de um valor da Tabela 3.9, devemos separar os valores por
vrgulas.
No preciso definir nenhum ID para o menu-pai. Depois de criar um
menu-pai, abrimos um bloco de cdigo para adicionar os itens do menu.
Valor
CHECKED
GRAYED
HELP
INACTIVE

MENUBARBREAK

MENUBREAK

Descrio
Menu marcado/selecionado.
Menu no pode ser clicado (desabilitado). No
pode ser usado junto com INACTIVE.
Identifica um item de ajuda
Menu inativo (no faz nada, mas pode ser
clicado). No pode ser usado junto com
GRAYED.
Idem a MENUBREAK, exceto que adiciona uma
linha separando as colunas (para itens do
menu-pai).
Posiciona o menu-pai numa nova linha. Para
itens do menu-pai, posiciona-os numa nova
coluna, sem linhas separatrias.
Tabela 3.9: Aparncia do item do menu.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

56

Programao Windows: C e Win32 API com nfase em Multimdia

Para adicionarmos um item no menu, colocamos a linha MENUITEM


dentro do bloco de cdigo do POPUP menupai, onde MENUITEM indica que ID_DO_MENU_ITEMX o ID do item itemX do
menu. O parmetro tipos opcional e pode receber um ou mais valores
(separados por vrgulas) da Tabela 3.9 para modificar a aparncia do item do
menu.
itemX, ID_DO_MENU_ITEMX, tipo

Existe um item de menu especial, que o separador de itens (veja a


Figura 3.5 o item separador a linha traada entre os itens Item 3 e Item
X. Ele definido no arquivo de recursos como MENUITEM SEPARATOR.
Nos textos dos menus, so muito utilizadas as teclas hot keys, que so
teclas de atalhos combinadas com o uso do ALT. Para definir uma letra do
texto como hot key, usamos o smbolo & antes da letra. Por exemplo, ao definir
MENUITEM Sai&r, ID_MENU_SAIR, estamos informando que a hot key do item do
menu Sair a combinao ALT+R.
Dica: o texto informado em itemX pode ter o caractere
texto do item.

\t

para tabular o

Alm das hot keys, podemos criar e utilizar teclas de atalho


(aceleradoras), como a famosa tecla F1 para abrir o arquivo de ajuda. Para
utilizar teclas de atalho, devemos defin-las no arquivo de recursos, como na
Listagem 3.5.
IDA_MEUATALHO
ACCELERATORS
{
tecla, ID_DO_ATALHO, tipo (opcional), opes (opcional)
tecla, ID_DO_ATALHO, tipo (opcional), opes (opcional)
}
Listagem 3.5: Definindo teclas de atalho como recursos.

A palavra-chave ACCELERATORS indica que IDA_MEUATALHO o ID das teclas


de atalho. Abrimos um bloco de cdigo em seguida, para acrescentar as teclas
de atalho atravs da linha tecla, ID_DO_ATALHO, tipo, opes.
O parmetro tecla pode receber: um caractere entre aspas duplas
(caractere com prefixo ^ indica que a tecla CONTROL tambm deve ser usada
no atalho), ou um valor inteiro representando o caractere (o parmetro tipo
deve receber o valor ASCII), ou uma tecla virtual (Tabela 4.12; o parmetro tipo
deve receber o valor VIRTKEY).
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

57

O parmetro ID_DO_ATALHO indica o ID da tecla de atalho. Quando


usamos teclas de atalho para executar algum item do menu, podemos enviar o
mesmo ID do item para esse parmetro.
O parmetro tipo s precisa ser definido quando o parmetro tecla
recebe um valor inteiro (tipo recebe ASCII) ou uma tecla virtual (tipo recebe
VIRTKEY).
O parmetro opes pode receber de um a trs valores (separados por
vrgulas), sendo esses: ALT, SHIFT e CONTROL. O envio desses valores para o
parmetro indica que a tecla de atalho ativada apenas se as teclas desses
valores enviados estiverem pressionadas.
Podemos verificar um exemplo de criao de teclas de atalho na
Listagem 3.6.
IDA_MEUATALHO ACCELERATORS
{
"1", ID_DO_MENU1_ITEM1, ALT
; ALT+1
VK_F2, ID_DO_MENU1_ITEM2, VIRTKEY ; F2
"^X", ID_DO_MENU1_ITEMX
; CONTROL+X
VK_ESCAPE, IDA_ATALHO_ESC, VIRTKEY ; ESC
}
Listagem 3.6: Criando teclas de atalho.

Dica: teclas de atalho no precisam necessariamente estar associadas um


item do menu.

Usando menus e teclas de atalho


Temos trs opes para usarmos os menus no programa: enviar o ID
do menu para o membro lpszMenuName da estrutura WNDCLASSEX, passar um
identificador de menu para o parmetro HMENU hMenu da funo
CreateWindowEx() ou utilizar a funo SetMenu().
No primeiro caso, modificamos apenas uma linha dentro da funo
WinMain() no cdigo-fonte do nosso programa, onde especificamos os atributos
da classe da janela (WNDCLASSEX):
wcl.lpszMenuName = MAKEINTRESOURCE(IDM_MEUMENU);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

58

Programao Windows: C e Win32 API com nfase em Multimdia

Com a modificao acima, o menu j ser inserido no programa. A


segunda opo enviar um identificador de menu para o dcimo parmetro da
funo CreateWindowEx():
// Cria identificador do menu do recurso
HMENU hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDM_MEUMENU));
hWnd = CreateWindowEx(..., ..., ..., ..., ..., ..., ..., ..., ...,
hMenu, ..., ...);

Para criar e enviar o identificador de menu para a funo


obtemos o mesmo pelo retorno da funo LoadMenu().

CreateWindowEx(),

HMENU LoadMenu(
HINSTANCE hInstance, // identificador do mdulo
LPCTSTR lpMenuName // ID do recurso do menu
);

A funo recebe o identificador do mdulo que contm o recurso do


menu (no nosso caso, a instncia atual do programa o primeiro parmetro
da funo WinMain() porm, tambm podemos carregar recursos de
bibliotecas DLL). O segundo parmetro recebe o ID do recurso do menu, o
qual devemos passar utilizando a macro MAKEINTRESOURCE(). O retorno de
LoadMenu() o identificador do menu do recurso ou NULL quando ocorre algum
erro.
Quando utilizamos LoadMenu() para carregar um menu do recurso,
devemos destruir o menu e liberar sua memria antes do programa ser
fechado. Para isso, usamos DestroyMenu().
BOOL DestroyMenu(
HMENU hMenu // identificador do menu
);

A funo recebe apenas o identificador de menu que queremos


destruir. Ela tambm destri todos os sub-menus contidos no menu. O
retorno um valor diferente de zero quando no h erros, ou zero, caso
contrrio.
Dica: podemos adicionar a chamanda funo
linha return(msg.wParam) da funo WinMain().

DestroyMenu()

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

antes da

Captulo 3 Arquivos de Recursos

59

O ltimo mtodo para carregar um menu no programa com o uso da


funo SetMenu().
BOOL SetMenu(
HWND hWnd, // identificador da janela
HMENU hMenu // identificador do menu
);

A funo recebe como primeiro parmetro o identificador da janela


(HWND hWnd) a qual o menu ser adicionado. O segundo parmetro o
identificador do menu, que obtemos com a funo LoadMenu(). A funo
retorna um valor diferente de zero quando no h erros, ou zero, caso
contrrio.
Para adicionar um menu janela principal pelo ltimo mtodo,
devemos criar a janela antes de chamar SetMenu(), como no exemplo da
Listagem 3.7.
// hWnd = CreateWindowEx() j foi executada
if(hWnd)
{
// Cria identificador do menu do recurso
HMENU hMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDM_MEUMENU));
// Definimos o menu para a janela
SetMenu(hWnd, hMenu);
// etc
}
Listagem 3.7: Definindo o menu com SetMenu().

Depois de termos adicionado o menu, vamos habilitar o uso das teclas


de atalho no programa, se existirem. Carregamos as teclas de atalho com a
funo LoadAccelerators().
HACCEL LoadAccelerators(
HINSTANCE hInstance,
hInstance, // identificador do mdulo
LPCTSTR lpTableName // recurso com teclas de atalho
);

O primeiro parmetro da funo recebe o identificador do mdulo que


contm o recurso das teclas de atalho (geralmente passamos a varivel
hInstance do parmetro da WinMain()) e o segundo parmetro recebe o ID do
recurso, com o uso da macro MAKEINTRESOURCE(). A funo retorna o
identificador do recurso das teclas de atalho ou NULL em caso de erro.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

60

Programao Windows: C e Win32 API com nfase em Multimdia

Essa funo apenas carrega as teclas de atalho e cria seu identificador.


Para utiliz-las, devemos traduzi-las em comandos para que o programa possa
process-las. Usamos a funo TranslateAccelerator(); porm, necessrio modificar o
loop de mensagens da WinMain().
int TranslateAccelerator(
HWND hWnd, // identificador da janela
HACCEL hAccTable, // identificador das teclas de atalho
LPMSG lpMsg // ponteiro para estrutura de mensagem
);

A funo recebe o identificador da janela (hWnd) no primeiro parmetro;


o segundo parmetro recebe o identificador das teclas de atalho (que acabamos
de obter com a funo LoadAccelerators()) e o terceiro recebe um ponteiro
para a estrutura MSG, que contm informaes das mensagens da fila de
mensagens. A funo retorna um valor diferente de zero quando bem sucedida
ou zero no caso de erro (ou seja, a mensagem no foi traduzida).
Nota: quando a funo retorna um valor diferente de zero (mensagem
processada), nosso programa no deve chamar a funo TranslateMessage()
para processar novamente a mensagem. Por isso devemos fazer uma
modificao no loop de mensagens.
Quando usamos teclas de atalho, o loop de mensagens codificado da
seguinte maneira (Listagem 3.8):
// Armazena dados da mensagem que ser obtida
MSG msg;
// Loop de mensagens, enquanto mensagem no for WM_QUIT,
// obtm mensagem da fila de mensagens
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
// Verifica se tecla de atalho foi ativada, se for, no executa
// TranslateMessage() nem DispatchMessage(), pois j foram processadas
if(!TranslateAccelerator(hWnd, hAccel, &msg))
{
// Traduz teclas virtuais ou aceleradoras (de atalho)
TranslateMessage(&msg);
// Envia mensagem para a funo que processa mensagens (WindowProc)
DispatchMessage(&msg);
}
}
Listagem 3.8: Loop de mensagens com teclas de atalho.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

61

J adicionamos o menu e carregamos as teclas de atalho no nosso


programa, mas como sabemos se o usurio escolheu alguma opo do menu
ou ativou alguma tecla de atalho? Quando ocorrem esses eventos, o Windows
envia uma mensagem, WM_COMMAND, para a fila de mensagens do nosso programa.
No processo da mensagem WM_COMMAND, verificamos o valor do
menos significativo do parmetro wParam para sabermos qual item
menu/tecla de atalho foi selecionado/ativada. O bit mais significativo
wParam 1 se a mensagem foi enviada por uma tecla de atalho ou zero se
enviada por um item do menu.

bit
do
de
foi

Dica: o uso de controles (como botes, por exemplo) tambm gera a


mensagem WM_COMMAND. No caso, podemos verificar qual controle enviou a
mensagem comparando wParam com seu ID ou lParam com o identificador
do controle. Veremos como criar e utilizar controles mais para frente.
A Listagem 3.9 mostra o processamento da mensagem WM_COMMAND,
utilizando algumas IDs de menu e teclas de atalho, definidas como exemplos
no decorrer desse captulo. Para um exemplo integral da definio, criao e
uso de menus e teclas de atalho, veja os arquivos prog03-5.cpp, prog03-5-res.h e
prog03-5-res.rc no CD-ROM.
case WM_COMMAND: // Item do menu, tecla de atalho ou controle ativado
{
// Verifica bit menos significativo de wParam (IDs)
switch(LOWORD(wParam))
{
case ID_DO_MENU1_ITEMX:
{
// Executa alguma ao
} break;
case ID_DO_MENU2_ITEMX:
{
// Executa alguma ao
} break;
case ID_DO_MENU2_ITEM3_X:
{
// Executa alguma ao
} break;
case IDA_ATALHO_ESC:
{
// Destri a janela
DestroyWindow(hWnd);
} break;
}
return(0);
} break;
Listagem 3.9: Processando a mensagem WM_COMMAND.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

62

Programao Windows: C e Win32 API com nfase em Multimdia

Modificando itens do menu


Durante a execuo dos nossos programas, podemos modificar os itens
do
menu,
deixando-os
habilitado/desabilitado/indisponvel
e
marcado/desmarcado. Existem trs funes que podem modificar o estado
dos itens de um menu: EnableMenuItem(), CheckMenuItem() e
CheckMenuRadioItem().
BOOL EnableMenuItem(
HMENU hMenu, // identificador do menu
UINT uIDEnableItem // item de menu a ser modificado
UINT uEnable // opes
);

A funo EnableMenuItem() faz com que um item de menu seja


habilitado, desabilitado ou fique indisponvel. O primeiro parmetro dessa
funo recebe o identificador do menu. O segundo parmetro depende do
valor de UINT uEnable: quando uEnable receber MF_BYCOMMAND, devemos passar o
ID do item que ser modificado no segundo parmetro; quando receber
MF_BYPOSITION, o valor de uIDEnableItem indica a posio do item no menu (o
primeiro item tem posio zero). O ltimo parmetro, alm de controlar o
modo de referncia ao item de menu (do segundo parmetro), indica qual ser
o estado desse item: MF_ENABLED (habilitado), MF_DISABLED (desabilitado) ou
MF_GRAYED (indisponvel). O retorno da funo indica o estado anterior do item
do menu (MF_ENABLED, MF_DISABLED ou MF_GRAYED) ou 1 caso o item no exista.
DWORD CheckMenuItem(
HMENU hmenu, // identificador do menu
UINT uIDCheckItem, // item do menu a ser modificado
UINT uCheck // opes
);

Essa funo faz com que um item do menu fique marcado ou no. Os
parmetros recebem os mesmos valores da funo EnableMenuItem(), com uma
nica diferena no ltimo: ao invs de receber MF_ENABLED, MF_DISABLED ou
MF_GRAYED, a funo deve receber MF_CHECKED (item ser marcado) ou
MF_UNCHECKED (item ser desmarcado). A funo retorna o estado anterior do
item (MF_CHECKED ou MF_UNCHECKED) ou 1 se o item do menu no existir.
BOOL
BOOL CheckMenuRadioItem(
HMENU hmenu, // identificador do menu
UINT idFirst, // ID ou posio do primeiro item do menu
UINT idLast, // ID ou posio do ltimo item do menu
UINT idCheck, // ID ou posio do item do menu a ser modificado
UINT uFlags // opes

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

63

);

A funo CheckMenuRadioItem() checa um item de menu e o transforma


num item de rdio. Um grupo de itens de rdio pode ter apenas um item
selecionado por vez, ao contrrio de itens do tipo checkbox (como na funo
CheckMenuItem()). O item selecionado com essa funo marcado com um
crculo, e no com a figura de um visto (como no checkbox). Todos os outros
itens no intervalo idFirst idLast so desmarcados.
O primeiro parmetro passado para a funo o identificador do
menu. Os parmetros idFirst, idLast e idCheck podem receber tanto o ID do
primeiro item, ltimo item e item a ser modificado (respectivamente) quanto a
posio de cada um deles, dependendo do valor informado em uFlags. Se
uFlags receber MF_BYCOMMAND, os trs parmetros anteriores devem receber o ID
dos itens do menu. Se uFlags receber MF_BYPOSITION, os trs parmetros
anteriores devem receber a posio inicial, final e do item a ser modificado,
respectivamente. A funo retorna um valor diferente de zero quando no h
erros ou zero, caso contrrio.
Dica: no CD-ROM existe um programa com exemplos do uso dessas trs
funes, assim como o cdigo para criar menus pop-up (menus flutuantes
que aparecem quando o usurio clica com o boto direito em algum lugar
do programa). Estude o cdigo-fonte prog03-6.cpp, pois voc aprender
mais funes de manipulao de menu.

Caixas de dilogo
O ltimo recurso que veremos a caixa de dilogo janela muito
parecida com as dos programas que estivemos criando at agora, mas que
definida no arquivo de recursos atravs de palavras-chave, facilitando a criao
e layout da mesma.
Nota: existem diversas opes de recursos e estilos para a caixa de dilogo,
mas veremos apenas os mais utilizados nos programas.
Para criarmos uma caixa de dilogo, utilizamos a estrutura conforme a
Listagem 3.10.
IDD_MEUDIALOGO
DIALOGEX
CAPTION ttulo (opcional)

x, y, largura, altura

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

64

Programao Windows: C e Win32 API com nfase em Multimdia

EXSTYLE estilos_extendidos (opcional)


FONT tamanho, fonte, espessura, itlico, charset (opcional)
MENU id_do_menu (opcional)
STYLE estilos (opcional)
{
controles
}
Listagem 3.10: Estrutura de uma caixa de dilogo.

Na primeira linha dessa estrutura, utilizamos a palavra-chave DIALOGEX


para indicar que IDD_MEUDIALOGO o ID da caixa de dialogo. Na mesma linha,
devemos informar, aps DIALOGEX, a coordenada (x, y) inicial da caixa de dilogo
e seu tamanho, passando os valores para os parmetros largura e altura.
As prximas cinco linhas so opcionais, mas bom utiliz-las para que
nossas caixas de dilogo fiquem mais personalizadas. A palavra-chave CAPTION
define o ttulo (informado no parmetro ttulo) da caixa de dilogo. A
palavra-chave EXSTYLE indica que a caixa de dilogo ter estilos extras, assim
como o primeiro parmetro da funo CreateWindowEx() vista no captulo
anterior. O parmetro estilos_extendidos pode receber os valores da Tabela
2.6, separados por vrgulas.
Na prxima linha, FONT define qual fonte ser utilizado pelos controles
(textos estticos, botes, listas, etc) da caixa de dilogo. O parmetro tamanho
recebe o tamanho da fonte; fonte recebe uma string contendo o nome da fonte
(por exemplo, MS Sans Serif); espessura pode receber um dos valores da
Tabela 4.5 (captulo 4, onde aprenderemos a utilizar fontes no programa); o
parmetro itlico recebe 1 (fonte itlica) ou 0 (fonte no-itlica) e charset
recebe um dos valores da Tabela 4.6.
Se quisermos colocar um menu na caixa de dilogo, usamos a palavrachave MENU e, em seguida, indicamos o ID do menu que vamos utilizar. No
caso de caixas de dilogo, o menu carregado e associado automaticamente,
sem a necessidade de codificao.
A palavra-chave STYLE indica os estilos da caixa de dilogo. Esse
parmetro pode receber uma combinao dos valores da Tabela 2.5 e da
Tabela 3.10 (a qual lista apenas alguns valores de estilos de dilogo).
Valor
DS_ABSALIGN

Descrio
Indica que a coordenada da caixa de dilogo
est em coordenadas da tela. Se no utilizado,
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

DS_CENTER
DS_CENTERMOUSE
DS_MODALFRAME

65

a coordenada da caixa de dilogo em


coordenadas da janela.
Centraliza a caixa de dilogo na rea de
trabalho.
Centraliza a caixa de dilogo no cursor do
mouse.
Cria uma caixa de dilogo modal que pode ser
combinada com uma barra de ttulo e menu de
sistema, especificando os estilos WS_CAPTION e
WS_SYSMENU.
Tabela 3.10: Alguns estilos das caixas de dilogo.

Em seguida, devemos abrir um bloco de cdigo, para que sejam


adicionados controles caixa de dilogo. Podemos utilizar quatro tipos de
controles: textos estticos, caixas de edio, botes e controles genricos.
Para criarmos textos estticos, como os labels dos ambientes de
programao visual, utilizamos a seguinte sintaxe:
alinhamento texto, id_do_texto_esttico, x, y, largura, altura, estilos,
estilos_extendidos

O primeiro parmetro, alinhamento, pode receber LTEXT (alinhamento


esquerda), CTEXT (centralizado) ou RTEXT (alinhamento direita). O segundo
parmetro recebe uma string contendo o texto esttico. O terceiro parmetro,
id_do_texto_esttico, recebe o ID do texto, definido no arquivo .h dos
recursos. Os outros parmetros informam a coordenada (x, y) do texto (dentro
da caixa do dilogo) e o tamanho ocupado por ele (largura e altura).
O parmetro estilos (opcional) indica o estilo do controle, podendo
receber SS_CENTER (mostra texto centralizado num retngulo invisvel, padro),
WS_TABSTOP (move cursor do teclado para outro controle com a tecla TAB,
padro) e WS_GROUP. O parmetro estilos_extendidos pode receber um ou mais
valores da Tabela 2.6 e seu uso opcional.
Nota: o uso do estilo WS_GROUP indica que o controle com esse estilo o
primeiro de um grupo de controles, onde o usurio pode movimentar o
cursor do teclado entre eles atravs das setas direcionais. O prximo
controle com esse estilo comea um outro grupo, finalizando o grupo
anterior.
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

66

Programao Windows: C e Win32 API com nfase em Multimdia

Para criarmos caixas de edio (textbox), onde o usurio pode digitar


qualquer texto, utilizamos a sintaxe:
EDITTEXT id_da_caixa, x, y, largura, altura, estilos, estilos_extendidos

Onde a palavra-chave EDITTEXT indica que id_da_caixa o ID da nova


caixa de edio, posicionada em (x, y) e de tamanho (largura, altura).
O parmetro estilos pode receber um ou mais valores da Tabela 3.11 e
tambm: WS_TABSTOP, WS_GROUP, WS_VSCROLL (janela com barra de rolagem
vertical), WS_HSCROLL (janela com barra de rolagem horizontal) e WS_DISABLED
(janela inativa). O parmetro estilos_extendidos pode receber um ou mais
valores da Tabela 2.6. Ambos os parmetros estilos e estilos_extendidos so
opcionais.
Valor
ES_AUTOHSCROLL
ES_AUTOVSCROLL
ES_CENTER
ES_LEFT
ES_LOWERCASE
ES_MULTILINE

ES_NUMBER
ES_PASSWORD
ES_READONLY
ES_RIGHT
ES_UPPERCASE
ES_WANTRETURN

Descrio
Rolagem automtica do texto na horizontal.
Rolagem automtica do texto na vertical.
Texto centralizado.
Texto alinhado esquerda.
Converte todos os caracteres para minsculo.
A caixa possui mltiplas linhas, no apenas
uma (que o padro). Note que para a tecla
ENTER ser utilizada para pular de linha, o
estilo ES_WANTRETURN deve ser especificado.
A caixa aceita apenas nmeros.
Mostra um asterisco para cada caractere
inserido na caixa.
Impede que o usurio possa editar o contedo
da caixa.
Texto alinhado direita.
Converte todos os caracteres para maisculo.
Indica que uma nova linha ser inserida
quando o usurio apertar a tecla ENTER
numa caixa de mltiplas linhas.
Tabela 3.11: Alguns valores de estilo de caixas de edio.

Para a criao de botes, temos disponveis oito palavras-chave, cada


uma indicando um tipo de boto; porm, a sintaxe, independente da palavrachave utilizada, a seguinte:
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

palavra-chave texto,
estilos_extendidos

id_do_botao,

x,

y,

largura,

altura,

67

estilos,

O parmetro palavra-chave pode receber um dos valores da Tabela


3.12, indicando o tipo de boto que ser criado. O segundo parmetro recebe
uma string contendo o texto que ser mostrado no boto. O terceiro
parmetro, id_do_botao, recebe o ID do boto, definido no arquivo .h dos
recursos. Os outros parmetros informam a coordenada (x, y) do boto (dentro
da caixa do dilogo) e o tamanho ocupado por ele (largura e altura).
Os valores do parmetro estilos mudam confrome o tipo de boto que
criado (veja Tabela 2.6). O parmetro estilos_extendidos pode receber um ou
mais valores da Tabela 2.6 e seu uso opcional.
Valor
AUTO3STATE

AUTOCHECKBOX

AUTORADIOBUTTON

CHECKBOX

PUSHBOX

PUSHBUTTON

Descrio
Cria um checkbox automtico de trs estados
(marcado, desmarcado ou indeterminado). O
parmetro estilos pode receber BS_AUTO3STATE
(padro), WS_TABSTOP (padro), WS_DISABLED e
WS_GROUP.
Cria um checkbox automtico de dois estados
(marcado ou desmarcado). O parmetro
estilos pode receber BS_AUTOCHECKBOX (padro),
WS_TABSTOP (padro) e WS_GROUP.
Cria um boto de rdio automtico. O
parmetro
estilos
pode
receber
BS_AUTORADIOBUTTON
(padro),
WS_TABSTOP
(padro), WS_DISABLED e WS_GROUP.
Cria um checkbox de dois estados (marcado ou
desmarcado). O parmetro estilos pode
receber BS_CHECKBOX (padro), WS_TABSTOP
(padro) e WS_GROUP.
Cria um boto contendo apenas o texto, sem
sua janela em volta. O parmetro estilos pode
receber BS_PUSHBOX (padro), WS_TABSTOP
(padro), WS_DISABLED e WS_GROUP.
Cria um boto comum, com o texto
centralizado. O parmetro estilos pode
receber BS_PUSHBUTTON (padro), WS_TABSTOP

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

68

Programao Windows: C e Win32 API com nfase em Multimdia

RADIOBUTTON

STATE3

(padro), WS_DISABLED e WS_GROUP.


Cria um boto de rdio. O parmetro estilos
pode receber BS_RADIOBUTTON (padro),
WS_TABSTOP (padro), WS_DISABLED e WS_GROUP.
Cria um checkbox de trs estados (marcado,
desmarcado ou indeterminado). O parmetro
estilos pode receber BS_3STATE (padro),
WS_TABSTOP (padro) e WS_GROUP.
Tabela 3.12: Tipos de botes.

Veja que existe um tipo automtico para os checkboxes de dois/trs


estados e para os botes de rdio. A diferena entre um tipo automtico ou
no que, quando automtico, no precisamos escrever nenhuma linha de
cdigo para que o estado do boto seja alterado, em resposta ao clique de
boto do usurio. Caso contrrio, devemos utilizar a funo CheckDlgButton()
para modificar o estado de um checkbox e CheckRadioButton() para
selecionar/modificar o estado de um boto de rdio. Ambas as funes
trabalham semelhantemente s funes CheckMenuItem() e CheckMenuRadioItem(),
respectivamente.
BOOL CheckDlgButton(
HWND hDlg, // identificador da caixa de dilogo
int nIDButton, // ID do checkbox
UINT uCheck // estado do checkbox
);

A funo recebe o identificador da caixa de dilogo que contm o


boto no primeiro parmetro. O segundo parmetro recebe o ID do checkbox
que ter seu estado modificado, e o terceiro parmetro indica o novo estado do
checkbox, podendo receber BST_CHECKED (marcado), BST_INDETERMINATE
(indeterminado; vlido apenas para checkbox de trs estados) ou BST_UNCHECKED
(desmarcado). A funo retorna um valor diferente de zero quando bem
sucedida ou zero, caso contrrio.
BOOL CheckRadioButton(
HWND hDlg,
hDlg, // identificador da caixa de dilogo
int nIDFirstButton, // ID do primeiro boto de rdio do grupo
int nIDLastButton, // ID do ltimo boto de rdio do grupo
int nIDCheckButton // ID do boto do rdio a ser selecionado
);

O primeiro parmetro da funo recebe o identificador da caixa de


dilogo que contm o boto de rdio. Os outros parmetros recebem os IDs

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

69

do primeiro boto de rdio do grupo (nIDFirstButton), do ltimo


(nIDLastButton) e do que ser selecionado (nIDCheckButton). A funo retorna
um valor diferente de zero quando bem sucedida ou zero, caso contrrio.
Nota: um grupo de botes de rdio definido pelo primeiro boto de
rdio com o estilo WS_GROUP at o prximo boto de rdio com esse estilo.
Para finalizar a parte de controles nas caixas de dilogo, vamos ver
como criar controles genricos definidos pela Win32 API, utilizando a seguinte
sintaxe:
CONTROL texto, id_do_controle, classe, estilos, x, y, largura, altura,
estilos_extendidos

Utilizamos a palavra-chave CONTROL para indicar que estamos criando


um controle genrico. Nesse caso, o parmetro estilos tem um significado
diferente, dependendo de qual controle for criado.
Todos os outros parmetros j foram explicados na criao de outros
controles, com exceo do parmetro classe. Esse parmetro indica que tipo
de controle iremos criar, podendo receber: BUTTON (boto), COMBOBOX (caixa de
seleo), EDIT (caixa de texto), LISTBOX (lista de seleo), SCROLLBAR (barra de
rolagem) ou STATIC (esttico).
Quando classe recebe BUTTON, estamos criando um controle do tipo
boto, uma janela retangular onde o usurio pode clicar para executar
determinada ao/seleo. Configuramos o seu estilo fornecendo um dos
valores da Tabela 3.13 para o parmetro estilo.
Valor
BS_3STATE
BS_AUTO3STATE
BS_AUTOCHECKBOX
BS_AUTORADIOBUTTON
BS_CHECKBOX
BS_DEFPUSHBUTTON

Descrio
Cria um checkbox de trs estados.
Cria um checkbox automtico de trs estados.
Cria um checkbox automtico de dois estados.
Cria um boto de rdio automtico.
Cria um checkbox de dois estados.
Cria um boto comum com uma borda preta
em volta, indicando que ele o padro;
quando o usurio pressiona ENTER numa
caixa de dilogo, mesmo que o cursor do
teclado no esteja nele, o boto executado.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

70

Programao Windows: C e Win32 API com nfase em Multimdia

BS_GROUPBOX

BS_LEFTTEXT
BS_PUSHBUTTON
BS_RADIOBUTTON
BS_BITMAP
BS_BOTTOM
BS_CENTER
BS_ICON
BS_FLAT

BS_LEFT
BS_MULTILINE
BS_PUSHLIKE
BS_RIGHT
BS_RIGHTBUTTON

BS_TEXT
BS_TOP
BS_VCENTER

Cria um retngulo onde outros controles


podem ser agrupados. O texto associado ao
controle desse estilo aparecer no canto
superior esquerdo do retngulo.
Alinha o texto do checkbox ou do boto de
rdio no lado esquerdo. Idem a BS_RIGHTBUTTON.
Cria um boto comum.
Cria um boto de rdio.
Indica que o boto mostra um bitmap.
Alinha o texto na parte inferior do boto.
Texto centralizado horizontalmente.
Indica que o boto mostra um cone.
Indica que o boto bidimensional (no utiliza
o sombreamento padro que d o aspecto 3D
nos botes).
Alinha o texto na lateral esquerda do boto.
Boto com mltiplas linhas, quando o texto do
mesmo no cabe em uma nica.
Faz com que checkboxes e botes de rdio
atuem como botes comuns.
Alinha o texto na lateral direita do boto.
Posiciona o crculo do boto de rdio ou o
quadrado de um checkbox do lado direito. Idem
a BS_LEFTTEXT.
Indica que o boto mostra um texto.
Alinha o texto na parte superior do boto.
Texto centralizado verticalmente.
Tabela 3.13: Alguns estilos de boto.

Quando classe recebe COMBOX, estamos criando um controle do tipo


caixa de seleo, que consiste de um campo de seleo, similar combinao
de uma caixa de texto e uma lista de seleo. Configuramos o seu estilo
fornecendo um dos valores da Tabela 3.14 para o parmetro estilo.
Valor
CBS_AUTOHSCROLL

Descrio
Faz a rolagem de texto automtica quando o
usurio digita um caracter no fim da linha. Se
esse estilo no for definido, apenas textos que
se encaixam dentro da caixa de seleo so
permitidos.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos


CBS_DISABLENOSCROLL

CBS_DROPDOWN

CBS_DROPDOWNLIST
CBS_LOWERCASE
CBS_NOINTERNALHEIGHT

CBS_SIMPLE
CBS_SORT
CBS_UPPERCASE

71

Mostra uma barra de rolagem vertical


desativada quando a caixa no contm itens
suficientes para fazer a rolagem. Sem esse
estilo, a barra de rolagem fica escondida
enquanto seu uso no for necessrio.
Idem a CBS_SIMPLE, exceto que a lista de seleo
no visvel, a menos que o usurio clique na
caixa de seleo.
Idem a CBS_DROPDOWNLIST, exceto que a caixa
mostra o texto do item selecionado na lista.
Converte todos os caracteres dos itens da lista
para minsculo.
Indica que o tamanho da caixa de seleo do
tamanho especificado pelo programa quando
o mesmo foi criado. Geralmente, o sistema
modifica o tamanho da caixa de seleo para
que no mostre itens pela metade.
Lista de seleo sempre visvel. A seleo atual
da lista mostrada na caixa.
Ordena automaticamente todos os itens
adicionados na caixa.
Converte todos os caracteres dos itens da lista
para maisculo.
Tabela 3.14: Alguns estilos de caixa de seleo.

Quando classe recebe EDIT, estamos criando um controle do tipo caixa


de texto, uma janela retangular onde o usurio pode entrar dados atravs do
teclado. Configuramos o seu estilo fornecendo um dos valores da Tabela 3.11
para o parmetro estilo.
Quando classe recebe LISTBOX, estamos criando um controle do tipo
lista de seleo, uma janela contendo uma lista de itens (strings) que o usurio
poder selecionar. Configuramos o seu estilo fornecendo um dos valores da
Tabela 3.16 para o parmetro estilo.
Valor
LBS_DISABLENOSCROLL

Descrio
Mostra uma barra de rolagem vertical
desativada quando a lista no contm itens
suficientes para fazer a rolagem. Sem esse
estilo, a barra de rolagem fica escondida

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

72

Programao Windows: C e Win32 API com nfase em Multimdia

LBS_EXTENDEDSEL
LBS_MULTICOLUMN
LBS_MULTIPLESEL
LBS_NOINTEGRALHEIGHT

LBS_NOSEL
LBS_SORT
LBS_STANDARD

enquanto seu uso no for necessrio.


Permite mltipla seleo de itens utilizando a
tecla SHIFT e clique do mouse.
Cria uma lista (com rolagem horizontal) com
uma ou mais colunas.
Seleciona/deseleciona item cada vez que o
usurio clicar num item da lista.
Indica que o tamanho da lista do tamanho
especificado pelo programa quando a mesma
foi criada. Geralmente, o sistema modifica o
tamanho da lista para que no mostre itens
pela metade.
Indica que a lista contm itens que no podem
ser selecionados, apenas visualizados.
Ordena os itens da lista alfabeticamente.
Ordena os itens da lista alfabeticamente. A
lista contm bordas nos quatro lados.
Tabela 3.16: Alguns estilos de lista de seleo.

Quando classe recebe SCROLLBAR, estamos criando um controle do tipo


barra de rolagem, controle que mostra setas em ambos os sentidos
(esquerda/direita
e
cima/baixo)
para
fazer
uma
rolagem
(incremento/decremento) em determinado sentido. Configuramos o seu estilo
fornecendo um dos valores da Tabela 3.17 para o parmetro estilo.
Valor
SBS_BOTTOMALIGN

SBS_HORZ
SBS_LEFTALIGN

SBS_RIGHTALIGN

SBS_TOPALIGN

Descrio
Alinha a parte inferior da barra de rolagem
com a parte inferior do retngulo definido
pelos parmetros x, y, largura e altura. Use
esse estilo com SBS_HORZ.
Cria uma barra de rolagem horizontal.
Alinha o lado esquerdo da barra de rolagem
com o lado esquerdo do retngulo definido
pelos parmetros x, y, largura e altura. Use
esse estilo com SBS_VERT.
Alinha o lado direito da barra de rolagem com
o lado direito do retngulo definido pelos
parmetros x, y, largura e altura. Use esse
estilo com SBS_VERT.
Alinha a parte superior da barra de rolagem

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

73

com a parte superior do retngulo definido


pelos parmetros x, y, largura e altura. Use
esse estilo com SBS_HORZ.
Cria uma barra de rolagem vertical.

SBS_VERT

Tabela 3.17: Alguns estilos de barra de rolagem.

Quando classe recebe STATIC, estamos criando um controle do tipo


esttico, que pode ser um texto, caixa, retngulo ou imagem. Configuramos o
seu estilo fornecendo um dos valores da Tabela 3.18 para o parmetro estilo.
Valor
SS_BITMAP

SS_BLACKFRAME
SS_BLACKRECT
SS_CENTER
SS_CENTERIMAGE
SS_GRAYFRAME
SS_GRAYRECT
SS_ICON

SS_LEFT
SS_RIGHT
SS_SUNKEN

Descrio
Indica que um bitmap ser mostrado no
controle esttico. O texto que o controle
recebe o ID do bitmap, definido no arquivo
de recursos. A largura e altura especificadas
so ignoradas, pois o controle se ajusta ao
tamanho do bitmap.
Indica que o controle ser um retngulo com
borda preta (sem preenchimento).
Indica que o controle ser um retngulo preto
(com preenchimento).
Indica que o controle exibir um texto
centralizado.
Indica que o bitmap ser centralizado no
controle.
Indica que o controle ser um retngulo com
borda cinza (sem preenchimento).
Indica que o controle ser um retngulo cinza
(com preenchimento).
Indica que um cone ser mostrado no
controle esttico. O texto que o controle
recebe o ID do cone, definido no arquivo
de recursos. A largura e altura especificadas
so ignoradas, pois o controle se ajusta ao
tamanho do cone.
Indica que o controle exibir um texto
alinhado esquerda.
Indica que o controle exibir um texto
alinhado direita.
Indica que o controle ter uma borda em

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

74

Programao Windows: C e Win32 API com nfase em Multimdia

SS_WHITEFRAME
SS_WHITERECT

baixo relevo.
Indica que o controle ser um retngulo com
borda branca (sem preenchimento).
Indica que o controle ser um retngulo
branco (com preenchimento).
Tabela 3.18: Alguns estilos de controle esttico.

Criando e destruindo caixas de dilogo


possvel criar dois tipos de caixa de dilogo: modal ou modeless. O
primeiro tipo faz com que a caixa de dilogo fique ativa e, ao mesmo tempo,
desativa a janela-pai (e suas filhas) que a criou. A janela-pai reativada somente
aps a caixa de dilogo modal ser destruda. O segundo tipo cria uma caixa de
dilogo inicialmente invisvel e no desativa sua janela-pai.
Para criarmos uma caixa de dilogo modal, devemos utilizar a funo
DialogBox().
INT_PTR DialogBox(
HINSTANCE hInstance, // identificador do mdulo
LPCTSTR lpTemplate, // recurso da caixa de dilogo
HWND hWndParent, // identificador da janela-pai
DLGPROC lpDialogFunc // funo que processa mensagens da caixa de dilogo
);

Essa funo recebe o identificador do mdulo no primeiro parmetro.


O segundo parmetro recebe o ID da caixa de dilogo (passada com o uso da
macro MAKEINTRESOURCE()). O terceiro parmetro recebe o identificador da
janela-pai, ou seja, a janela que est criando o dilogo. O ltimo parmetro
recebe um ponteiro para a funo que processa mensagens da caixa de dilogo
(semelhante ao membro lpfnWndProc da estrutura WNDCLASSEX, com exceo que
uma funo que processa mensagens da caixa de dilogo).
A funo pode retornar trs valores: se no ocorrer nenhum erro, ela
retorna o valor do parmetro nResult passado na funo EndDialog() (veremos
logo adiante). No caso de erro, ela pode retornar zero, se hWndParent for
invlido, ou 1 para qualquer outro tipo de erro.
Quando no precisarmos mais da caixa de dilogo modal, devemos
destru-la utilizando a funo EndDialog(), chamando-a de dentro da funo de
processamento de mensagens da caixa de dilogo.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

75

BOOL EndDialog(
HWND hDlg, // identificador da caixa de dilogo
INT_PTR nResult // valor de retorno
);

O primeiro parmetro da funo recebe o identificador da caixa de


dilogo que ser destruda, e o segundo recebe o valor que ser retornado para
o programa atravs da funo DialogBox(). A funo retorna um valor diferente
de zero quando no ocorrer erros, ou zero caso contrrio.
No caso da criao de uma caixa de dilogo modeless, devemos utilizar
a funo CreateDialog().
HWND CreateDialog(
HINSTANCE hInstance, // identificador do mdulo
LPCTSTR lpTemplate, // recurso da caixa de dilogo
HWND hWndParent, // identificador da janela-pai
DLGPROC
DLGPROC lpDialogFunc // funo que processa mensagens da caixa de dilogo
);

Veja que a funo CreateDialog() recebe os mesmos parmetros que a


funo DialogBox(). A diferena entre essas funes o tipo de retorno; neste
caso, CreateDialog() retorna um identificador da caixa de dilogo criada ou NULL
se houver erros.
Conforme dito anteriormente, uma caixa de dilogo modeless
inicialmente invisvel. Para mostrar o dilogo na tela, precisamos chamar a
funo ShowWindow(), passando como parmetro o identificador da caixa de
dilogo.
Nota: diferente da funo DialogBox(), devemos utilizar a funo
DestroyWindow() para destruir uma caixa de dilogo modeless.

Processando mensagens das caixas de dilogo


Quando estamos utilizando caixas de dilogo, devemos processar suas
mensagens, alm das da janela principal do programa. Para isso, criamos uma
funo do tipo callback para cada caixa de dilogo. O prottipo dessa funo a
seguinte:
INT_PTR CALLBACK DialogProc(
HWND hwndDlg, // identificador da caixa de dilogo
UINT uMsg, // identificador da mensagem
WPARAM wParam, // primeiro parmetro da mensagem

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

76

Programao Windows: C e Win32 API com nfase em Multimdia

LPARAM lParam // segundo parmetro da mensagem


);

Essa funo, por ser do tipo callback, chamada somente pelo


Windows, quando h alguma mensagem da caixa de dilogo a ser processada.
Ela deve retornar TRUE quando uma mensagem processada ou FALSE caso
contrrio. Quando a funo retorna FALSE, o processamento da mensagem
feita automaticamente pela administrao interna da caixa de dilogo.
Quando uma caixa de dilogo (modal ou modeless) criada, o sistema
envia uma mensagem de inicializao, WM_INITDIALOG, que deve retornar TRUE.
Para fechar a caixa de dilogo, o usurio pode usar a combinao de teclas
ALT+F4, utilizar o menu de sistema, ou ainda, clicar no x que fecha a janela.
O uso de qualquer uma dessas opes gera a mensagem WM_COMMAND, com
LOWORD(wParam) contendo IDCANCEL. Devemos ento processar a mensagem
WM_INITDIALOG e WM_COMMAND. A Listagem 3.11 demonstra a criao de uma caixa
de dilogo modal, a funo DialogProc() e o processamento das mensagens
bsicas de dilogo.
//
//
//
//

Prottipo da funo de processamento de mensagens da caixa de dilogo.


Veja que podemos escolher qualquer nome para a funo, desde que o tipo
de retorno e parmetros sejam iguais ao padro e que o nome da funo
seja passada corretamente na funo DialogBox() ou CreateDialog().

INT_PTR CALLBACK DlgProcExemp(HWND, UINT, WPARAM, LPARAM);


//-------------------------------------------------------------------------// WindowProc() -> Processa as mensagens enviadas para o programa
//-------------------------------------------------------------------------LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
// Processando alguma mensagem da WindowProc()
...
// Armazena retorno da DialogBox()
int teste = 0;
// Obs: IDD_MEUDIALOGO foi declarado e criado num arquivo de recursos.
// Cria caixa de dilogo modal e salva retorno da DialogBox() em teste.
teste
=
DialogBox(hInstance,
(DLGPROC)DlgProcExemp);

MAKEINTRESOURCE(IDD_MEUDIALOGO),

// No foi possvel criar a caixa de dilogo


if(teste <= 0)
MessageBox(hWnd, Erro, Erro, MB_OK);
...
// continuao da WindowProc()
}

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

hWnd,

Captulo 3 Arquivos de Recursos

77

//-------------------------------------------------------------------------// DlgProcExemp() -> Processa as mensagens enviadas para a caixa de dilogo


//-------------------------------------------------------------------------INT_PTR CALLBACK DlgProcExemp(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM
lParam)
{
// Verifica qual foi a mensagem enviada
switch(uMsg)
{
case WM_INITDIALOG: // Caixa de dilogo foi criada
{
// Retorna TRUE, significando que a mensagem
// foi processada corretamente
return(TRUE);
} break;
case WM_COMMAND: // Item do menu, tecla de atalho ou controle ativado
{
switch(LOWORD(wParam))
{
case IDCANCEL: // ALT+F4, menu do sistema, boto x
{
// Destri a caixa de dilogo
EndDialog(hDlg, 0);
return(TRUE);
} break;
}
} break;
default: // Outra mensagem
{
// Retorna FALSE, deixando a caixa de dilogo processar a mensagem
return(FALSE);
} break;
}
}
Listagem 3.11: Criao e processamento de mensagens de uma caixa de dilogo modal.

A criao e uso de uma caixa de dilogo modeless um pouco


diferente da modal: alm de usarmos as funes CreateDialog() /
DestroyWindow(), as mensagens que devem ser processadas pela funo da caixa
de dilogo so passadas pela fila de mensagens do programa. Portanto, o loop
de mensagens da WinMain() deve ser modificado, conforme a Listagem 3.12:
// g_hDlg um identificador global da caixa de dilogo (HWND g_hDlg)
// Loop de mensagens, enquanto mensagem no for WM_QUIT,
// obtm mensagem da fila de mensagens
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
// Verifica se a caixa de dilogo modeless foi criada ou
// se a mensagem uma mensagem para a caixa de dilogo

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

78

Programao Windows: C e Win32 API com nfase em Multimdia

if((!IsWindow(g_hDlg)) || (!IsDialogMessage(g_hDlg, &msg)))


{
// Traduz teclas virtuais ou aceleradoras (de atalho)
TranslateMessage(&msg);
// Envia mensagem para a funo que processa mensagens (WindowProc)
DispatchMessage(&msg);
}
}
Listagem 3.12: Loop de mensagens modificado para caixa de dilogo modeless.

A modificao que fizemos no loop de mensagens verifica duas


condies: se a caixa de dilogo modeless foi criada e se a mensagem que ser
processada uma mensagem da caixa de dilogo. Quando a mensagem
processada uma mensagem de dilogo, no devemos executar as funes
TranslateMessage() e DispatchMessage(), pois a funo IsDialogMessage() faz
toda a traduo e envio de mensagem automaticamente.
Inicialmente, declaramos uma varivel global HWND g_hDlg = NULL, que
armazenar o retorno da funo CreateDialog(), ou seja, ela ser o identificador
da caixa de dilogo modeless.
Para verificarmos se a caixa de dilogo (ou qualquer outro tipo de
janela) foi criada, chamamos a funo IsWindow().
BOOL IsWindow(
IsWindow(
HWND hWnd // identificador da janela
);

Essa funo recebe o identificador da janela que queremos verificar se


foi criada ou no e retorna um valor diferente de zero caso a janela foi criada,
ou zero, quando o identificador passado no parmetro hWnd contm zero ou
NULL (significando que ele no identifica nenhuma janela).
A funo IsDialogMessage() verifica se uma mensagem ou no
destinada a uma caixa de dilogo.
BOOL IsDialogMessage(
HWND hDlg, // identificador da caixa de dilogo
LPMSG lpMsg
lpMsg // ponteiro para estrutura de mensagem
);

A funo recebe o identificador da caixa de dilogo como primeiro


parmetro e um ponteiro para uma varivel do tipo MSG, que contm a

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

79

mensagem que ser processada, no segundo. Se a mensagem for processada


por essa funo, ela retorna um valor diferente de zero; se no, retorna zero.
A Listagem 3.13 contm as partes principais de um cdigo-fonte que
cria, mostra e destri uma caixa de dilogo modeless.
//
//
//
//

Prottipo da funo de processamento de mensagens da caixa de dilogo.


Veja que podemos escolher qualquer nome para a funo, desde que o tipo
de retorno e parmetros sejam iguais ao padro e que o nome da funo
seja passada corretamente na funo DialogBox() ou CreateDialog().

INT_PTR CALLBACK DlgProcModeless(HWND, UINT, WPARAM, LPARAM);


// Varivel global que armazena o identificador da caixa de dilog modeless
HWND g_hDlg = NULL;
//-------------------------------------------------------------------------// WinMain() -> Funo principal
//-------------------------------------------------------------------------int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
...
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
// Verifica se a caixa de dilogo modeless foi criada ou
// se a mensagem uma mensagem para a caixa de dilogo
if((!IsWindow(g_hDlg)) || (!IsDialogMessage(g_hDlg, &msg)))
{
// Traduz teclas virtuais ou aceleradoras (de atalho)
TranslateMessage(&msg);
// Envia mensagem para a funo que processa mensagens (WindowProc)
DispatchMessage(&msg);
}
}
...
}
//-------------------------------------------------------------------------// WindowProc() -> Processa as mensagens enviadas para o programa
//-------------------------------------------------------------------------LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
// Processando alguma mensagem da WindowProc()
...
// Obs: IDD_MEUDIALOGO2 foi declarado e criado num arquivo de recursos.
// Cria caixa de dilogo modeless
// Verifica se a caixa de dilogo j foi criada...
if(!IsWindow(g_hDlg))

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

80

Programao Windows: C e Win32 API com nfase em Multimdia

{
// Se no foi, cria e salva identificador em g_hDlg
g_hDlg = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_MEUDIALOGO2), hWnd,
(DLGPROC)DlgProcModeless);
// Mostra a caixa de dilogo
ShowWindow(g_hDlg, SW_SHOW);
}
else // Caixa de dilogo j foi criada...
// Mostra a caixa de dilogo
SetFocus(g_hDlg);
...
// continuao da WindowProc()
}
//-------------------------------------------------------------------------// DlgProcModeless() -> Processa as mensagens enviadas para a caixa de
// dilogo
//-------------------------------------------------------------------------INT_PTR CALLBACK DlgProcModeless(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM
lParam)
{
// Verifica qual foi a mensagem enviada
switch(uMsg)
{
case WM_INITDIALOG: // Caixa de dilogo foi criada
{
// Retorna TRUE, significando que a mensagem
// foi processada corretamente
return(TRUE);
} break;
case WM_COMMAND: // Item do menu, tecla de atalho ou controle ativado
{
switch(LOWORD(wParam))
{
case IDCANCEL: // ALT+F4, menu do sistema, boto x
{
// Destri a caixa de dilogo
DestroyWindow(hDlg);
// Indica que g_hDlg no identifica mais a caixa de dilogo
g_hDlg = NULL;
return(TRUE);
} break;
}
} break;
default: // Outra mensagem
{
// Retorna FALSE, deixando a caixa de dilogo processar a mensagem
return(FALSE);
} break;

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 3 Arquivos de Recursos

81

}
}
Listagem 3.13: Criao e processamento de mensagens de uma caixa de dilogo modeless.

Observe o trecho de cdigo da linha case IDCANCEL. O identificador da


caixa de dilogo (hDlg) que passamos para a funo DestroyWindow() no o
mesmo que utilizamos na chamada da funo CreateDialog(). Esse
identificador o parmetro passado na funo de processamento de
mensagens da caixa de dilogo (DlgProcModeless()), enquanto g_hDlg uma
global que usamos para saber se a caixa de dilogo foi criada ou no. Depois de
destruir a caixa de dilogo, devemos definir o valor NULL para g_hDlg, indicando
que essa varivel no identifica mais a caixa de dilogo.
Dica: no CD-ROM, voc encontra um programa (prog03-7.cpp) com o
exemplo da criao e uso das caixas de dilogo modal e modeless.
H outros tipos de recursos que no foram discutidos nesse captulo,
mas os que voc aprendeu j so suficientes para a criao da maioria de seus
programas. A seguir, veremos como processar mensagens do teclado e do
mouse, alm de uma introduo GDI (parte grfica do Windows).

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

82

Programao Windows: C e Win32 API com nfase em Multimdia

Captulo 4 GDI, Textos e Eventos de


Entrada
Para melhorar a interao do usurio com os nossos programas,
devemos verificar os controles de entrada (teclado e mouse), e em seguida
processar suas mensagens.
No programa-exemplo prog04-1.cpp, alm da interao do usurio via
teclado, acrescentaremos algo mais: como escrever textos na janela do
programa atravs da GDI do Windows. O programa-exemplo ir detectar a
tecla pressionada pelo usurio e colocar a informao na janela do programa,
conforme a Figura 4.1:

Figura 4.1: Detectando as teclas pressionadas

Antes de verificarmos as mensagens para processar os eventos do


teclado e mouse, vamos ver como funciona a interface grfica do Windows e
tambm a mensagem WM_PAINT, que j foi mencionada no captulo 2.

GDI e Device Context


No Windows, tudo relacionado grficos (janelas, textos, linhas,
desenhos, ...) est relacionado GDI. A GDI uma interface que engloba um
conjunto de funes e estruturas necessrias para facilitar a ligao entre o
programador e os drivers dos dispositivos, como monitores e impressoras.
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

83

Dessa maneira, o programador no precisa se preocupar com os diversos tipos


de dispositivos e fabricantes, pois esse trabalho fica por conta da GDI (a
menos que seja necessrio escrever uma rotina para um dispositivo especfico,
o que no o nosso caso).
Para desenharmos qualquer grfico na rea cliente de um programa (ou
seja, toda a rea do programa, com exceo da barra de ttulo, menus, bordas e
controles), utilizamos um contexto de dispositivo (device context) para
comunicarmos com a GDI. Um contexto de dispositivo uma estrutura que
define um conjunto de objetos grficos e atributos os quais sero utilizados
para a sada grfica do seu programa.
Dica: assim como um pintor utiliza uma tela para fazer seus desenhos,
podemos dizer que o contexto de dispositivo de vdeo a nossa tela. Em
ambientes de programao como o C++ Builder, o termo canvas (tela)
utilizado em referncia rea onde iremos desenhar.
Existem diferentes tipos de contexto de dispositivo, tais como de
impressoras, arquivos metafile, memria e vdeo. Iremos estudar apenas os dois
ltimos tipos, que se referem arquivos bitmap e tela de vdeo,
respectivamente. Vamos estudar primeiro o DC (abreviao de device context ou
contexto de dispositivo) de vdeo, pois j estamos trabalhando com ele.
Em geral, os programas utilizam um DC pblico, que mantido pelo
Windows. Esse DC compartilhado entre todos os programas em execuo e
utilizado para sada de grficos na rea cliente das janelas. Ele tambm o
DC padro de todas as janelas, no necessitando nenhuma especificao no
membro WNDCLASSEX.style da classe da janela.
Nota: o termo grfico utilizado no livro refere-se textos, linhas, elipses,
retngulos, imagens bitmap, enfim, qualquer elemento que seja possvel ser
desenhado na rea cliente da janela.
Para trabalharmos com o DC pblico, criamos um identificador para
ele declarando uma varivel do tipo HDC:
HDC hDC = NULL;

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

84

Programao Windows: C e Win32 API com nfase em Multimdia

A partir da, devemos obter o identificador do DC sempre que


quisermos desenhar algum grfico na rea cliente da janela. Algo importante
que voc deve ter em mente que os programas no sabem o que deve ser
desenhado na rea cliente; por isso, devemos informar a eles o que desenhar
sempre que houver uma atualizao na rea cliente da janela (atravs da
mensagem WM_PAINT).
O que os programas fazem detectar o retngulo da rea cliente que
deve ser redesenhada. Isso ocorre quando a posio/tamanho da janela
modificada ou quando qualquer ao afeta a rea cliente, resultando na
invalidao de parte da rea cliente (ou a rea inteira, dependendo do caso). A
Figura 4.2 demonstra um exemplo de invalidao da rea cliente.

Figura 4.2: Parte da rea cliente invalidada quando outra janela sobreposta.

Quando qualquer parte da rea cliente invlida, o Windows envia ao


programa uma mensagem WM_PAINT. Nessa mensagem, devemos validar a rea
que foi marcada como invlida, ou seja, redesenhamos essa rea para que o seu
contedo no seja perdido e informamos ao Windows que a atualizao j foi
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

85

feita (caso contrrio, o Windows continua enviando mensagens WM_PAINT at ser


informado sobre a atualizao).

Processando a mensagem WM_PAINT


Conforme dito anteriormente, para desenhar qualquer grfico na rea
cliente, utilizamos um DC de vdeo, que no processamento da mensagem
WM_PAINT obtido atravs das funes BeginPaint() e EndPaint(). Esse par de
funes tem a funo de obter o identificador do DC e validar a rea que foi
atualizada.
Nota: BeginPaint() e EndPaint() devem ser usados somente no processo da
mensagem WM_PAINT e, para cada chamada BeginPaint(), deve existir um
EndPaint() correspondente.
HDC BeginPaint(
HWND hWnd, // identificador da janela
LPPAINTSTRUCT lpPaint // ponteiro para estrutura que contm informaes de
desenho
);

A funo BeginPaint() recebe dois parmetros: o primeiro, HWND hWnd,


indica qual janela deve ser preparada para receber as aes de desenho; o
segundo, LPPAINTSTRUCT lpPaint, um ponteiro para uma estrutura contendo
informaes de desenho, que preenchida automaticamente pela funo. A
estrutura a seguinte:
typedef struct tagPAINTSTRUCT {
HDC hdc; // identificador do DC de vdeo usado para desenho
BOOL fErase; // flag indicando se o fundo ser apagado
RECT rcPaint; // retngulo que deve ser redesenhado
BOOL fRestore; // reservado, utilizado internamente pelo sistema
BOOL fIncUpdate; // reservado, utilizado internamente pelo sistema
BYTE rgbReserved[32]; // reservado, utilizado internamente pelo sistema
} PAINTSTRUCT;

O primeiro membro, HDC hDC, recebe o identificador do DC de vdeo


que ser utilizado para desenhar grficos (o mesmo retornado pela funo
BeginPaint()).
um flag que indica se o fundo da janela deve ou no ser
apagado, utilizando a cor declarada no membro WNDCLASSEX.hbrBackground da
classe da janela.
BOOL fErase

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

86

Programao Windows: C e Win32 API com nfase em Multimdia

O membro RECT rcPaint armazena o retngulo da rea que deve ser


redesenhada e tambm indica a rea de corte (clipping region), ou seja, qualquer
rea fora desse retngulo ser descartada para fins de atualizao. A estrutura
RECT tem seus membros auto-explicativos e definida como:
typedef struct _RECT {
LONG left; // coordenada x inicial (ngulo esquerdo superior)
LONG top; // coordenada y inicial (ngulo esquerdo superior)
LONG right; // coordenada x final (ngulo direito inferior)
LONG bottom; // coordenada y final (ngulo direito inferior)
} RECT;

Os outros membros so reservados e so utilizados internamente pelo


Windows. O retorno da funo BeginPaint() o identificador do DC para a
janela especificada, se no houver erros. Se ocorrer algum erro, a funo
retorna NULL, indicando que nenhum DC de vdeo est disponvel.
Aps a chamada da funo BeginPaint(), fazemos toda a codificao
para o desenho dos grficos. Feito isso, devemos indicar o fim do desenho e
tambm a validao da rea, atravs da funo EndPaint().
BOOL EndPaint(
HWND hWnd, // identificador da janela
CONST PAINTSTRUCT *lpPaint // ponteiro
informaes de desenho
);

para

estrutura

que

contm

Os parmetros de EndPaint() so idnticos ao da funo BeginPaint() e


seu retorno sempre diferente de zero.
A codificao da mensagem WM_PAINT tem a seguinte estrutura genrica
(sendo que HDC hDC e PAINTSTRUCT psPaint j foram declaradas anteriormente):
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{
// Obtm identificador do DC e preenche PAINTSTRUCT
hDC = BeginPaint(hWnd, &psPaint);
//
// Cdigo para desenhar grficos
//
// Libera DC e valida rea
EndPaint(hWnd, &psPaint);
return(0);
} break;
Listagem 4.1: mensagem WM_PAINT.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

87

Grficos fora da WM_PAINT


H casos em que queremos desenhar grficos na rea cliente sem ser
durante o processamento da mensagem WM_PAINT; por exemplo, a cada clique
do boto esquerdo do mouse (mensagem WM_LBUTTONDOWN), podemos desenhar
um crculo na tela. Nesse caso, no utilizamos as funes BeginPaint() e
EndPaint() para obtermos o identificador do DC de vdeo (eles so utilizados
somente na mensagem WM_PAINT), mas sim as funes GetDC() e ReleaseDC().
Uma das diferenas entre essas funes que GetDC() e ReleaseDC() no
utilizam apenas a parte invlida da rea cliente, mas sim ela inteira. Assim, no
ficamos limitados a desenhar grficos apenas nas reas que houve invalidao.
Outro detalhe que utilizando essas funes ns no validamos a rea cliente;
a validao feita sempre durante a mensagem WM_PAINT. Vamos verificar como
funcionam as funes GetDC() e ReleaseDC():
HDC GetDC(
HWND hWnd // identificador de uma janela
);

A funo GetDC() recebe como nico parmetro um identificador de


uma janela (geralmente o da janela principal) e retorna o identificador do DC
da rea cliente da janela especificada ou NULL se ocorreu algum erro. O
parmetro HWND hWnd tambm pode receber NULL, indicando que o DC ser da
tela inteira.
Com o retorno da GetDC() sendo diferente de NULL, fazemos todas as
aes necessrias para desenhar nossos grficos. Depois, devemos liberar o DC
para que ele seja utilizado por outros programas, atravs da funo ReleaseDC():
int ReleaseDC(
ReleaseDC(
HWND hWnd, // identificador da janela
HDC hDC // identificador do DC
);

O primeiro parmetro da funo recebe o identificador da janela da


qual o DC ser liberado. O segundo parmetro recebe o identificador do DC a
ser liberado. A funo retorna 1 se o DC liberado ou zero caso contrrio.
Nota: assim como ocorre com BeginPaint() e EndPaint(), para cada GetDC()
chamado, deve existir um ReleaseDC() correspondente.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

88

Programao Windows: C e Win32 API com nfase em Multimdia

Como foi citado o exemplo de desenhar um crculo a cada clique do


boto esquerdo do mouse, vamos ver como podemos utilizar GetDC() e
ReleaseDC(), processando a mensagem WM_LBUTTONDOWN (dentro da funo
WindowProc()), com o seguinte trecho de cdigo (Listagem 4.2):
case WM_LBUTTONDOWN: // Boto esquerdo do mouse pressionado
{
// Obtm posio (x, y) atual do cursor do mouse
int x = LOWORD(lParam);
int y = HIWORD(lParam);
// Obtm identificador do DC
hDC = GetDC(hWnd);
// Desenha crculo
Ellipse(hDC, x - 10, y - 10, x + 10, y + 10);
// Libera DC
ReleaseDC(hWnd, hDC);
return(0);
} break;
Listagem 4.2: Uso das funes GetDC() e ReleaseDC().

Na mensagem WM_LBUTTONDOWN, podemos obter a coordenada (x, y) na


rea cliente onde o cursor do mouse est localizado no momento do clique do
boto. Essa informao obtida atravs do parmetro adicional lParam. A
coordenada x est no bit menos significativo de lParam e a coordenada y est
no bit mais significativo de lParam (obtm-se os valores do bit mais/menos
significativo utilizando as macros HIWORD e LOWORD conforme o exemplo). As
mensagens e seus parmetros adicionais podem ser encontrados na
documentao da Win32 API (h dezenas deles, tornando-se invivel cit-los
no livro).
Para desenhar um crculo na tela, utilizamos a funo da GDI
Ellipse(), que ser explicada no prximo captulo. O exemplo nos serviu
apenas para ilustrar como so utilizadas as funes GetDC() e ReleaseDC().
Nota: um detalhe importante deve ser observado! Como no estamos
processando a mensagem WM_PAINT, quando ocorrer invalidao da rea
onde desenhamos o grfico, seu contedo ser perdido, pois o programa
no sabe que modificamos o contedo da rea cliente e que essa
modificao deve ser permanecida.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

89

Gerando a mensagem WM_PAINT


Quando vimos o processamento da mensagem WM_PAINT, observamos
que o membro rcPaint da estrutura PAINTSTRUCT armazena a rea que est
invlida, atualizando e permitindo o desenho de grficos apenas dentro dessa
rea, cortando fora (clipping) todo o resto que no est no limite dos valores do
retngulo.
Caso haja a necessidade de desenhar grficos fora da rea que est
invlida, devemos informar ao programa que estamos invalidando outra rea,
com a funo InvalidateRect(). O uso dessa funo gera uma mensagem
WM_PAINT, portanto, podemos utilizar essa funo para atualizar a rea cliente
logo aps ocorrer uma ao do teclado, por exemplo. Ambos exemplos citados
aqui so demonstrados aps a explicao do prottipo da InvalidateRect().
BOOL InvalidateRect(
HWND hWnd, // identificador da janela
CONST RECT *lpRect, // ponteiro para coordenadas do retngulo
BOOL bErase // flag para limpar fundo
);

O parmetro HWND hWnd recebe o identificador da janela onde receber a


nova rea invlida. Se receber NULL, o Windows invalida e redesenha todas as
janelas.
O segundo parmetro recebe um ponteiro para uma varivel do tipo
que contm as coordenadas que sero adicionadas rea de
atualizao/invalidao. Esse parmetro tambm pode receber NULL, fazendo
com que toda rea cliente seja invalidada.
RECT,

O ltimo parmetro, BOOL bErase, um flag que determina se o fundo


da rea invlida ser apagado no prximo processo da mensagem WM_PAINT.
Caso seja TRUE, todo o contedo da rea cliente apagado quando a funo
BeginPaint() for chamada, permanecendo apenas o que for informado para ser
desenhado dentro da WM_PAINT. Em caso de FALSE, o fundo no modificado.
Para invalidar toda a rea cliente na mensagem WM_PAINT e ser possvel
desenhar grficos em qualquer regio dela, utilize o seguinte cdigo (Listagem
4.3):
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

90

Programao Windows: C e Win32 API com nfase em Multimdia

// Invalida toda a rea cliente sem modificar o fundo


InvalidateRect(hWnd, NULL, FALSE);
// Obtm identificador do DC e preenche PAINTSTRUCT
hDC = BeginPaint(hWnd, &psPaint);
//
// Cdigo para desenhar grficos
//
// Libera DC e valida rea
EndPaint(hWnd, &psPaint);
return(0);
} break;
Listagem 4.3: Invalidando a rea cliente.

Conforme o segundo exemplo mencionado, vamos enviar uma


mensagem WM_PAINT ao programa logo aps uma ao do teclado, invalidando
uma rea onde escreveremos um texto armazenado numa varivel szMensagem
(Listagem 4.4):
char szMensagem[1]; // Armazena tecla
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{
// Obtm identificador do DC e preenche PAINTSTRUCT
hDC = BeginPaint(hWnd, &psPaint);
// Mostra mensagem na rea cliente
TextOut(hDC, 8, 8, szMensagem, 1);
// Libera DC e valida rea
EndPaint(hWnd, &psPaint);
return(0);
} break;
case WM_CHAR: // Tecla foi pressionada
{
// Coordenadas da rea a ser invalidada
RECT rcArea = { 8, 8, 28, 28 };
// Indica qual tecla foi pressionada
sprintf(szMensagem, %c, (char)wParam);
// Invalida rea e gera mensagem WM_PAINT
InvalidateRect(hWnd, &rcArea, FALSE);
return(0);
} break;
Listagem 4.4: Enviando mensagem WM_PAINT.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

91

Validando reas
Assim como podemos invalidar partes da rea cliente, tambm
podemos valid-las, atravs da funo ValidateRect(), que valida a parte da rea
cliente especificada num retngulo (passada como parmetro para a funo).
BOOL ValidateRect(
HWND hWnd, // identificador da janela
CONST RECT *lpRect // ponteiro para coordenadas do retngulo
);

O parmetro HWND hWnd recebe o identificador da janela onde receber a


rea que ser validada. Se receber NULL, o Windows valida e redesenha todas as
janelas.
O segundo parmetro recebe um ponteiro para uma varivel do tipo
RECT, que contm as coordenadas que sero removidas da rea de
atualizao/invalidao. Esse parmetro tambm pode receber NULL, fazendo
com que toda rea cliente seja validada.
A funo retornar zero caso ocorra erros ou um valor diferente de
erro caso contrrio.
No faz muito sentido validarmos parte ou toda a rea cliente, pois isso
feito ao processarmos a mensagem WM_PAINT com as funes BeginPaint() e
EndPaint(). Ento, quando podemos validar manualmente a rea cliente?
A validao manual da rea cliente pode ser feita quando estamos
utilizando um DC privado (assunto de um captulo posterior), onde no
precisamos obrigatoriamente obter o identificador do DC na mensagem
WM_PAINT ou utilizar as funes BeginPaint() e EndPaint(), porm, ainda
devemos fazer a validao da rea cliente.

Objetos GDI
Alm do DC, precisamos trabalhar com objetos GDI. Os objetos GDI
so tipos de variveis definidas pela Win32 API os quais devem ser criados e
selecionados no DC antes de desenharmos grficos na rea cliente.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

92

Programao Windows: C e Win32 API com nfase em Multimdia

Os principais objetos GDI so: caneta (pen), pincel (brush), bitmap,


fonte (font) e regio (region). Cada um desses objetos tem um propsito, que
sero discutidos futuramente em maiores detalhes. Nesse momento, devemos
saber que para utilizar cada objeto, o mesmo deve estar selecionado no DC, e
isso feito com a funo SelectObject():
HGDIOBJ SelectObject(
HDC hdc, // identificador do DC
HGDIOBJ hgdiobj // identificador do objeto GDI
);

O primeiro parmetro da funo o identificador do DC para o qual


estamos selecionando o objeto. O segundo parmetro recebe o objeto que vai
ser associado ao DC. Note que o segundo parmetro do tipo HGDIOBJ.
Podemos considerar esse tipo de varivel como sendo um objeto genrico para
os outros citados, podendo receber qualquer valor listado na Tabela 4.1.
Caso o objeto selecionado no DC no seja uma regio, o retorno da
funo ser o identificador do objeto que estava selecionado anteriormente no
DC, caso a funo seja bem sucedida; a funo retorna NULL se no foi bem
sucedida.
Se o objeto selecionado for uma regio e no ocorrer erros, o retorno
da funo poder ser SIMPLEREGION (a regio contm apenas um retngulo),
COMPLEXREGION (a regio contm mais de um retngulo) ou NULLREGION (a regio
vazia). Quando ocorrer erro, o retorno ser HGDI_ERROR.
Em todos os casos, o objeto que retornado pela funo do mesmo
tipo do objeto que foi selecionado no DC.
Valor (tipo de varivel)
HPEN
HBRUSH
HBITMAP
HFONT
HRGN
HGDIOBJ

Objeto GDI
Caneta (pen)
Pincel (brush)
Bitmap (bitmap)
Fonte (font)
Regio (region)
Objeto GDI genrico
Tabela 4.1: Objetos GDI.

Sempre que selecionarmos um objeto no DC, logo aps utiliz-lo,


devemos restaurar o objeto que estava previamente selecionado no DC, pois
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

93

isso evita problemas inesperados que possam ocorrer. Veja o trecho de cdigo
a seguir (Listagem 4.5), que seleciona uma caneta no DC e depois restaura a
caneta antiga (no se preocupe em entender como criar uma caneta, mas sim
como funciona a funo SelectObject()):
HPEN hPen; // Nova caneta;
HPEN hPenOld; // Caneta antiga
// Cria nova caneta
hPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
// Seleciona nova caneta no DC e salva antiga
hPenOld = (HPEN)SelectObject(hDC, hPen);
//
// Cdigo para desenhar grficos
//
// Nova caneta no vai ser mais utilizada, restaura antiga
SelectObject(hDC, hPenOld);
// Exclui a nova caneta e libera memria associada ela
DeleteObject(hPen);
Listagem 4.5: Usando a funo SelectObject().

Voc deve ter percebido que a ltima linha desse cdigo contm uma
funo que ainda no foi discutida aqui: DeleteObject() exclui um objeto e
libera a memria associada ao mesmo. Uma vez excludo, o identificador do
objeto no mais vlido.
BOOL DeleteObject(
HGDIOBJ hObject // identificador do objeto grfico
);

O nico parmetro da funo, HGDIOBJ hObject, recebe o objeto que


ser excludo, podendo receber qualquer um dos objetos da Tabela 4.1.
A funo retorna um valor diferente de zero quando a excluso for
bem sucedida. Se o identificador especificado no for vlido ou est
selecionado no DC, a funo retorna zero.
Nota: no devemos deletar objetos que ainda estejam selecionados no DC;
primeiro devemos retir-lo do DC, restaurando o objeto que estava
selecionado no DC anteriormente. Tambm no podemos selecionar mais
de um objeto no DC ao mesmo tempo, pois isso uma limitao da GDI.
Basta ver como o MS-Paint funciona: podemos utilizar apenas um objeto

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

94

Programao Windows: C e Win32 API com nfase em Multimdia

de desenho por vez. Por exemplo, quando escolhemos o lpis, no


podemos trabalhar ao mesmo tempo com o balde de tinta, e vice-versa.

Obtendo informaes de um objeto GDI


Alm de criarmos objetos GDI, podemos obter as informaes dos
mesmos. Isso til, por exemplo, quando queremos modificar as informaes
de um objeto GDI em tempo de execuo, como a cor de um pincel, espessura
da caneta, etc... Para obter as informaes, utilizamos a funo GetObject():
int GetObject(
GetObject(
HGDIOBJ hgdiobj, // identificador do objeto GDI
int cbBuffer, // tamanho do buffer das informaes do objeto
LPVOID lpvObject // buffer para armazenar as informaes do objeto
);

O primeiro parmetro da funo (HGDIOBJ hgdiobj) recebe o


identificador do objeto GDI de onde iremos obter as informaes.
O segundo parmetro, int cbBuffer, indica o tamanho em bytes que
sero gravados no buffer (o terceiro parmetro). O valor desse parmetro deve
indicar o tamanho do objeto que estamos obtendo as informaes, portanto,
basta enviar o comando sizeof(tipo) como parmetro, onde tipo o tipo do
objeto do primeiro parmetro (consulte a Tabela 4.1).
O ltimo parmetro, LPVOID lpvObject, recebe um ponteiro void para o
buffer onde as informaes sero armazenadas. O valor de lpvObject recebe
uma estrutura conforme o objeto GDI que foi enviado no primeiro parmetro.
A Tabela 4.2 lista quais estruturas podem ser enviadas para lpvObject.
Valor
BITMAP

Objeto GDI (primeiro parmetro)


HBITMAP ou HBITMAP retornado da funo
CreateDIBSection()
e
se
cbBuffer

DIBSECTION

HBITMAP

sizeof(BITMAP).

EXTLOGPEN
LOGPEN
LOGBRUSH
LOGFONT

retornado da funo CreateDIBSection()


e se cbBuffer sizeof(DIBSECTION).
HPEN retornado da funo ExtCreatePen().
HPEN.
HBRUSH.
HFONT.
Tabela 4.2: Valores para lpvObject.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

95

Quando a funo executada corretamente, o retorno pode ser: a)


um ponteiro vlido: o retorno o nmero de bytes que foi
armazenado no buffer ou b) lpvbObject NULL: a funo retorna o nmero de
bytes necessrio para armazenar as informaes, que seriam armazenadas no
buffer. Se a funo falhar, o retorno zero.
lpvObject

Nota: veja o ltimo exemplo (Listagem 4.12) do tpico Trabalhando com


fontes desse captulo, que exemplifica a utilizao da funo GetObject().

Escrevendo textos na rea cliente


Existem duas principais funes GDI para escrever textos na rea
cliente: TextOut() e DrawText(). A primeira uma funo mais simplista,
mostrando textos sem formataes, enquanto a segunda suporta formataes
de texto, como quebra de linha e tabulaes. No programa prog04-1.cpp, ambas
as funes so utilizadas; TextOut() para escrever o texto no canto esquerdo
superior e DrawText() para escrever Utilizando GDI centralizado na rea
cliente do programa. Vamos ver cada uma dessas funes:
BOOL TextOut(
HDC hdc, // identificador do DC
int nXStart, // posio x do texto
int nYStart, // posio y do texto
LPCTSTR lpString, // ponteiro para string
int cbString // quantidade de caracteres na string
);

A funo TextOut() recebe o identificador do DC (que obtivemos


anteriormente), a posio (x, y) onde o texto ser mostrado, um ponteiro para a
string contendo o texto, e a quantidade de caracteres da string.
A funo retorna um valor diferente de zero se no houve falhas, caso
contrrio, zero retornado indicando erro.
O quarto parmetro, LPCTSTR lpString, pode ser uma constante e no
precisa ser necessariamente terminado com zero, pois o ltimo parmetro
indica quantos caracteres devem ser impressos, como mostra o exemplo a
seguir:
TextOut(hDC, 0, 0, Mostrar o texto, 15);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

96

Programao Windows: C e Win32 API com nfase em Multimdia

Porm, nem sempre queremos mostrar um texto constante; muitas


vezes preciso mostrar valores e contedos de variveis. TextOut() no aceita
strings formatadas como o printf() da linguagem C. A soluo para isso
utilizar a funo sprintf() para pr-formatar a string antes de pass-la para
TextOut(), conforme mostra a Listagem 4.6:
char texto[255];
char nome[] = Adauto;
int idade = 20;
sprintf(texto, %s tem %d anos., nome, idade);
TextOut(hDC, 0, 0, texto, lstrlen(texto));
Listagem 4.6: texto pr-formatado para TextOut().

Usar uma varivel do tipo char[] (ou LPSTR) tambm facilita quando
precisamos passar o ltimo parmetro da funo, pois podemos usar lstrlen()
para indicarmos a quantidade de caracteres da string automaticamente.
Mesmo utilizando a funo sprintf() para pr-formatar a string,
no aceita certas seqncias de escape como quebra de linha ou
tabulao. Para isso, utilizamos DrawText():

TextOut()

int DrawText(
DrawText(
HDC hDC, // identificador do DC
LPCTSTR lpString, // ponteiro para string
int nCount, // quantidade de caracteres da string
LPRECT lpRect, // ponteiro para retngulo onde o texto ser formatado
UINT uFormat // flags para formatao do texto
);

recebe diferentes parmetros da TextOut(), pois trabalha


baseado em reas retangulares ao invs de coordenadas (x, y). O identificador
do DC passado para o primeiro parmetro da funo, HDC hDC.
DrawText()

O segundo parmetro, LPCTSTR lpString, recebe um ponteiro para a


string que contm o texto, enquanto int nCount recebe a quantidade de
caracteres da string. Nesse terceiro parmetro, podemos passar o valor 1,
assim, a funo ir calcular automaticamente a quantidade de caracteres da
string passada para a funo.
O parmetro LPRECT lpRect recebe um ponteiro de uma varivel do tipo
RECT, que define o retngulo onde ser impresso o texto informado em LPCTSTR
lpString.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

97

O ltimo parmetro, UINT uFormat, pode receber diversos valores


combinados com o operador |, conforme mostra alguns valores da Tabela 4.3,
os quais fazem a formatao do texto.
Quando a funo DrawText() executada sem problemas, ela retorna a
altura do texto ou zero se houve algum problema.
Valor
DT_BOTTOM

DT_CENTER
DT_EXPANDTABS
DT_LEFT
DT_RIGHT
DT_SINGLELINE
DT_TOP

DT_VCENTER
DT_WORDBREAK

Descrio
Alinha o texto para a parte inferior do
retngulo. Esse valor deve ser combinado com
DT_SINGLELINE.
Centraliza o texto horizontalmente no
retngulo.
Aumenta os caracteres de tabulao. O valor
padro de caracteres por tabulao oito.
Alinha o texto esquerda.
Alinha o texto direita.
Mostra o texto em uma nica linha. Quebra de
linhas (\n) no tm efeito nesse caso.
Alinha o texto na parte superior do retngulo.
Esse valor deve ser combinado com
DT_SINGLELINE.
Centraliza o texto verticalmente. Esse valor
deve ser combinado com DT_SINGLELINE.
Quebra de linhas so automaticamente
inseridas caso uma palavra ultrapasse a rea do
retngulo especificado no parmetro lpRect.
Tabela 4.3: Alguns valores de formatao de texto para DrawText().

Podemos utilizar a funo GetClientRect() para obter o retngulo da


rea cliente do programa e imprimir um texto centralizado no meio da rea
cliente (como no programa-exemplo prog04-1.cpp):
BOOL
BOOL GetClientRect(
HWND hWnd, // identificador da janela
LPRECT lpRect // ponteiro para retngulo
coordenadas da rea cliente
);

onde

sero

armazenadas

as

A funo GetClientRect() recebe o identificador da janela de onde ser


obtida a rea cliente e um ponteiro para uma varivel do tipo RECT onde sero
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

98

Programao Windows: C e Win32 API com nfase em Multimdia

armazenadas as coordenadas da rea cliente. Os valores dos membros de RECT


sero: left = 0, top = 0, right = largura da rea cliente e bottom = altura da
rea cliente. A funo retorna zero se houve algum erro ou um valor diferente
de zero se a funo foi executada corretamente.
Para imprimir um texto centralizado no meio da rea cliente, utilizamos
o seguinte trecho de cdigo (Listagem 4.7):
// Obtm rea cliente
RECT rcArea;
GetClientRect(hWnd, &rcArea);
// Imprime texto na rea cliente
DrawText(hDC, Utilizando GDI, -1, &rcArea, DT_SINGLELINE | DT_CENTER |
DT_VCENTER);
Listagem 4.7: Texto centralizado na rea cliente.

Com uma pequena modificao (Listagem 4.8), podemos imprimir o


mesmo texto centralizado horizontalmente e centralizado verticalmente
utilizando apenas metade da altura da rea cliente:
// Obtm rea cliente
RECT rcArea;
GetClientRect(hWnd, &rcArea);
// Utiliza apenas metade da altura da rea cliente
rcArea.bottom = rc.Area.bottom / 2;
// Imprime texto na rea determinada
DrawText(hDC, Utilizando GDI, -1, &rcArea, DT_SINGLELINE | DT_CENTER |
DT_VCENTER);
Listagem 4.8: Texto na metade da altura da rea cliente.

E caso voc queira imprimir um texto de mltiplas linhas, iniciando da


coordenada (8, 20) da rea cliente, utilize o seguinte cdigo (Listagem 4.9):
// Obtm rea cliente
RECT rcArea;
GetClientRect(hWnd, &rcArea);
rcArea.left = 8; // Retngulo inicia em x = 8
rcArea.top = 20; // Retngulo inicia em y = 20
// Imprime texto na rea determinada
DrawText(hDC, Essa a linha 1\nEssa a linha 2\nEssa linha 3., -1,
&rcArea, DT_LEFT);
Listagem 4.9: Texto com mltiplas linhas.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

99

Cores RGB COLORREF


Antes de verificarmos como modificar os atributos de texto, vamos ver
um novo tipo de varivel: COLORREF, varivel de 32-bits utilizada para especificar
uma cor no formato RGB (de Red, Green, Blue, ou seja, Vermelho, Verde, Azul).
Podemos criar cerca de 16,7 milhes de cores atravs da combinao de
diferentes valores para os bits que armazenam informaes sobre as cores, pois
possvel definir 256 intensidades/tons diferentes para cada uma dessas trs
cores. A Figura 4.3 demonstra como so utilizados os bits da COLORREF e sua
estrutura.
Nota: obviamente, a quantidade mxima de cores que ser visualizada
depender do monitor e da placa de vdeo utilizada.

Figura 4.3: A estrutura COLORREF e como seus bits so armazenados.

Na GDI, as funes que recebem parmetros de cor utilizam a varivel


COLORREF. Podemos definir uma cor RGB de duas maneiras: explicitamente,
utilizando valores em hexadecimal, ou atravs da macro RGB().
Quando uma cor RGB definida atravs de valores hexadecimais, o
valor da varivel do tipo COLORREF deve ser informado no formato
0x00BBGGRR, ou seja, o byte menos significativo (RR) armazena a
intensidade da cor vermelha, o segundo byte (GG) armazena a intensidade da
cor verde, o terceiro byte (BB) armazena a intensidade da cor azul e o byte
mais significativo (00) deve ser zero. Os valores de cada byte podem estar entre
os intervalos 00 e FF.
O mais comum e prtico utilizar a macro RGB() para definir uma cor.
A definio da macro RGB a seguinte:
#define RGB(r, g, b)
(BYTE)(b)) << 16)))

((DWORD) (((BYTE)(r) | ((WORD)(g) << 8)) | (((DWORD)

Podemos pensar nessa macro como uma funo com o seguinte


prottipo:
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

100

Programao Windows: C e Win32 API com nfase em Multimdia

COLORREF RGB(
BYTE bRed, // cor vermelha
BYTE bGreen, // cor verde
BYTE bBlue // cor azul
);

Onde a funo recebe trs parmetros que so os valores das


intensidades de cada cor e retorna uma varivel do tipo COLORREF contendo a
cor informada nos parmetros da funo.
A Tabela 4.4 mostra algumas cores criadas com a macro
tambm criadas explicitamente atravs de valores hexadecimais:
RGB()

Valor hexadecimal

RGB(0, 0, 0)

0x00000000

RGB(255, 255, 255)

0x00FFFFFF

RGB(255, 0, 0)

0x000000FF

RGB(128, 0, 0)

0x0000007F

RGB(0, 255, 0)

0x0000FF00

RGB(0, 128, 0)

0x00007F00

RGB(0, 0, 255)

0x00FF0000

RGB(0, 0, 128)

0x007F0000

RGB(255, 255, 0)

0x0000FFFF

RGB(128, 128, 0)

0x00007F7F

RGB(255, 0, 255)

0x00FF00FF

RGB(128, 0, 128)

0x007F007F

RGB(0, 255, 255)

0x00FFFF00

RGB(0, 128, 128)

0x007F7F00

RGB()

Cor
Preto
Branco
Vermelho claro
Vermelho escuro
Verde claro
Verde escuro
Azul claro
Azul claro
Amarelo claro
Amarelo escuro
Magenta claro
Magenta escuro
Ciano claro
Ciano escuro

Tabela 4.4: Algumas cores RGB.

Nota: os programas Windows sempre utilizam o padro de cores 24-bit (8


bits por canal/cor). Caso a placa de vdeo esteja configurada para uma
quantidade diferente de cores, o Windows faz uma aproximao com as
cores disponveis no sistema.

Modificando atributos de texto


Quando TextOut() ou DrawText() so utilizados, o resultado do texto
impresso na rea cliente no muito agradvel, pois vemos o texto com cor
preta e fundo branco, mesmo se o fundo da rea cliente for, por exemplo,
verde.
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

101

Isso ocorre porque no definimos alguns atributos da fonte-padro


utilizada pelos programas a cor do texto, a cor de fundo e o modo como o
fundo misturado com a rea cliente. Para isso, utilizamos as funes
SetTextColor(), SetBkColor() e SetBkMode(), respectivamente.
utilizada para definir a cor do texto impressa com
ou DrawText() em um DC especfico.

SetTextColor()
TextOut()

COLORREF SetTextColor(
HDC hdc, // identificador do DC
COLORREF crColor
crColor // cor do texto
);

A funo recebe o identificador do DC, no primeiro parmetro, onde o


atributo de cor de texto ser modificado com a cor especificada no parmetro
COLORREF crColor. O retorno da funo a cor de texto que estava definida
anteriormente ou CLR_INVALID caso a funo falhe.
O uso da cor de retorno da funo til quando queremos modificar a
cor de um texto e depois voltar para a cor original antes da modificao. O
trecho de cdigo (Listagem 4.10) a seguir exemplifica esse trabalho:
COLORREF crOld;
// Modifica cor e salva cor antiga em crOld
crOld = SetTextColor(hDC, RGB(255, 0, 0));
// Mostra texto vermelho
TextOut(hDC, 0, 0, Texto em Vermelho, lstrlen(Texto em Vermelho));
// Restaura cor antiga
SetTextColor(hDC, crOld);
// Mostra texto na cor original
TextOut(hDC, 50, 50, Cor Original, lstrlen(Cor Original));
Listagem 4.10: Modificando cor do texto.

Para modificar a cor de fundo atual do texto, utilizamos a funo


SetBkColor().
COLORREF SetBkColor(
HDC hdc, // identificador do DC
COLORREF crColor // cor do fundo
);

O primeiro parmetro da funo recebe o identificador do DC e o


segundo recebe a cor que ser atribuda ao fundo do texto. O retorno da
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

102

Programao Windows: C e Win32 API com nfase em Multimdia

funo a cor de fundo que estava definida anteriormente ou CLR_INVALID caso


a funo falhe.
Assim como SetTextColor(), o retorno COLORREF da funo SetBkColor()
pode ser utilizado para armazenar a cor de fundo antiga e restaur-la quando
necessrio.
Nota: SetBkColor() tambm utilizada para preencher os espaos entre
estilos de linhas desenhadas usando uma caneta (pen) criado com a funo
CreatePen(). Estudaremos pens e suas funes no prximo captulo.
Alm de modificar a cor da face do texto e do seu fundo, podemos
definir como a cor de fundo misturada com a rea cliente, atravs da funo
SetBkMode().
int SetBkMode(
HDC hdc, // identificador da janela
int iBkMode // modo de fundo
);

A funo SetBkMode() recebe o identificador do DC como primeiro


parmetro; no segundo, int iBkMode, definimos o modo que a cor de fundo
ser misturada com a rea cliente. iBkMode recebe o valor OPAQUE, caso
desejemos que o fundo do texto seja preenchido com a cor de fundo (definida
em SetBkColor()) ou TRANSPARENT, para que o fundo do texto fique transparente.
O retorno da funo, quando bem sucedida, o valor do modo de
fundo (iBkMode) que estava definido anteriormente. Caso contrrio, o retorno
zero.
Nota: SetBkMode() tambm afeta os estilos de linhas desenhadas pela
funo CreatePen().
Para exemplificar o uso dessas trs funes (Listagem 4.11), vamos
imprimir dois textos na rea cliente, um de fundo amarelo e opaco (o segundo
parmetro de SetBkColor() recebe OPAQUE) com texto azul e outro de fundo
transparente e texto verde escuro:
COLORREF crOldText; // Armazena cor de texto antiga
COLORREF crOldBk; // Armazena cor de fundo antiga
int iOldMode; // Armazena modo de fundo antigo

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

103

// Muda cor de texto para azul e salva antiga


crOldText = SetTextColor(hDC, RGB(0, 0, 255));
// Muda cor de fundo para amarelo e salva antiga
crOldBk = SetBkColor(hDC, RGB(255, 255, 0));
// Muda modo de fundo para opaco e salva antigo
iOldMode = SetBkMode(hDC, OPAQUE);
// Mostra texto em azul e fundo amarelo
TextOut(hDC, 0, 0, Brasil, 6);
// Muda cor de texto para verde escuro
SetTextColor(hDC, RGB(0, 128, 0));
// Muda modo de fundo para transparente
SetBkMode(hDC, TRANSPARENT);
/* Note que no salvamos as cores antigas, pois o que queremos restaurar
depois so as cores que estavam definidas anteriormente (as quais j foram
salvas na primeira chamada das funes SetTextColor() e SetBkMode()). */
// Mostra texto em verde escuro e fundo transparente
TextOut(hDC, 0, 20, Amaznia, 8);
// Restaura configuraes antigas
SetTextColor(hDC, crOldText);
SetBkColor(hDC, crOldBk);
SetBkMode(hDC, iOldMode);
Listagem 4.11: Mudando atributos de cor de texto e fundo.

Trabalhando com fontes


Uma outra opo para melhorar a visualizao dos textos em nossos
programas modificar a fonte utilizada para impresso na rea cliente.
Conforme mencionado em Objetos GDI, fontes so objetos GDI e devem
ser criados e associados ao DC que estamos trabalhando. Podemos criar um
objeto fonte (HFONT) de duas maneiras: atravs da chamada funo
CreateFont() ou funo CreateFontIndirect(). A diferena entre elas que a
primeira recebe 14 parmetros informando o tipo de fonte, enquanto a
segunda recebe uma estrutura LOGFONT que contm esses 14 parmetros. Vamos
ver como utilizar ambas funes:
HFONT CreateFont(
int nHeight, // altura da fonte
int nWidth,
nWidth, // largura da fonte
int nEscapement, // ngulo do texto
int nOrientation, // ngulo do texto
int fnWeight, // espessura da fonte
DWORD fdwItalic, // estilo de fonte itlica
DWORD fdwUnderline, // estilo de fonte sublinhada
DWORD fdwStrikeOut,
fdwStrikeOut, // estilo de fonte tachada
DWORD fdwCharSet, // identificador do estilo dos caracteres

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

104

Programao Windows: C e Win32 API com nfase em Multimdia

DWORD fdwOutputPrecision, // preciso de sada


DWORD fdwClipPrecision, // preciso de corte (clipping)
DWORD fdwQuality, // qualidade de sada
DWORD fdwPitchAndFamily,
fdwPitchAndFamily, // pitch e famlia da fonte
LPCTSTR lpszFace // nome da fonte
);

O primeiro parmetro, int nHeight, especifica a altura da fonte. Esse


parmetro pode receber trs tipos de valores: se nHeight for zero, o programa
utiliza o tamanho padro da fonte; se maior que zero, o programa obtm a
altura da cela dos caracteres da fonte, e se for menor que zero, o programa
obtm o valor absoluto da altura dos caracteres da fonte.
Nota: a cela de caractere um retngulo imaginrio que abrange cada
caractere da fonte. Sua altura calculada obtendo a distncia entre a parte
debaixo da letra g minscula at o topo da letra m maiscula, mais um
valor conhecido por internal leading. A altura do internal leading ocupada por
caracteres que possuem acentos, tais como as letras , , . A altura de um
caractere obtida subtraindo a altura do internal leading pela altura da cela.
Veja esse esquema demonstrado atravs da Figura 4.4.

Figura 4.4: Cela, caractere e internal leading.

O segundo parmetro, int nWidth, especifica a largura dos caracteres da


fonte. Para que o mapeador de fontes calcule automaticamente a largura
padro para ns, enviamos zero para esse parmetro.
O terceiro parmetro, int nEscapement, especifica o ngulo de rotao
da fonte, porm, cada ngulo passado para esse parmetro sendo
multiplicado por 10: o ngulo de 90 graus deve ser passado como 900, o de 30
graus deve ser passado como 300, etc... O parmetro int nOrientation deve
receber o mesmo valor que nEscapement.
O parmetro int fnWeight identifica a espessura da fonte (entre 0 a
1000), indicando se o texto ser escrito com a fonte normal ou em negrito. Os
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

105

valores da Tabela 4.5 podem ser enviados a esse parmetro. O valor zero faz
com que uma espessura padro da fonte seja utilizada.
Valor
FW_DONTCARE
FW_THIN
FW_EXTRALIGHT
FW_ULTRALIGHT
FW_LIGHT
FW_NORMAL
FW_REGULAR
FW_MEDIUM
FW_SEMIBOLD
FW_DEMIBOLD
FW_BOLD
FW_EXTRABOLD
FW_ULTRABOLD
FW_HEAVY
FW_BLACK

Espessura
0
100
200
200
300
400 (normal)
400
500
600
600
700 (negrito)
800
800
900
900
Tabela 4.5: Espessuras da fonte.

Os trs prximos parmetros, DWORD fdwItalic, DWORD fdwUnderline e


indicam se a fonte ser itlica, sublinhada e/ou tachada,
respectivamente. Cada parmetro recebe TRUE (aplica estilo na fonte) ou FALSE
(no aplica estilo).
DWORD fdwStrikeOut

O parmetro DWORD fdwCharSet especifica o estilo dos caracteres da


fonte e pode receber um dos valores da Tabela 465. O valor associado a esse
parmetro deve ser do mesmo estilo de caracteres da fonte informada no
parmetro LPCTSTR lpszFace. Em alguns casos, possvel utilizar o valor
DEFAULT_CHARSET, mas devemos ter certeza que a fonte especificada realmente
existe na mquina onde o programa est sendo executado.
Valor
ANSI_CHARSET
BALTIC_CHARSET
CHINESEBIG5_CHARSET
DEFAULT_CHARSET
EASTEUROPE_CHARSET

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

106

Programao Windows: C e Win32 API com nfase em Multimdia

GB2312_CHARSET
GREEK_CHARSET
HANGUL_CHARSET
MAC_CHARSET
OEM_CHARSET
RUSSIAN_CHARSET
SHIFTJIS_CHARSET
SYMBOL_CHARSET
TURKISH_CHARSET
VIETNAMESE_CHARSET
JOHAB_CHARSET
ARABIC_CHARSET
HEBREW_CHARSET
THAI_CHARSET

(verso Windows na linguagem coreana)


(verso Windows na linguagem do Oriente
Mdio)
(verso Windows na linguagem do Oriente
Mdio)
(verso Windows na linguagem tailandesa)
Tabela 4.6: Valores para fdwCharSet.

O parmetro DWORD fdwOutputPrecision especifica a preciso de sada,


definindo o quo prximo a sada deve ser em relao aos valores fornecidos
para a fonte (altura, largura, ngulo, pitch e tipo de fonte). O parmetro pode
receber um dos valores da Tabela 4.7.
Valor
OUT_CHARACTER_PRECIS
OUT_DEFAULT_PRECIS
OUT_DEVICE_PRECIS

OUT_OUTLINE_PRECIS

OUT_PS_ONLY_PRECIS

Descrio
No utilizado.
Especifica o comportamento padro do
mapeador de fontes.
Instrui o mapeador de fontes a escolher uma
fonte de dispositivo quando o sistema possui
contm diversas fontes com o mesmo nome
(por exemplo, uma fonte fornecida pelo
fabricante de impressora).
Instrui o mapeador de fontes a escolher
fontes True Type ou variaes de fontes outline
quando existe mais de uma fonte com o
mesmo nome.
Instrui o mapeador de fontes a escolher
apenas fontes PostScript. Caso no exista
nenhuma fonte PostScript instalada no sistema,

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

OUT_RASTER_PRECIS

OUT_STRING_PRECIS
OUT_STROKE_PRECIS

OUT_TT_ONLY_PRECIS

OUT_TT_PRECIS

107

o mapeador retorna o comportamento


padro.
Instrui o mapeador de fontes a escolher uma
variao de fontes raster quando existe mais
de uma fonte com o mesmo nome.
Retornado quando fontes raster so
enumeradas.
Retornado quando fontes True Type ou
vetoriais so enumeradas. No Windows
95/98/Me, tambm utilizado para o
mapeador de fontes escolher variaes de
fontes vetoriais ou True Type.
Instrui o mapeador de fontes a escolher
apenas fontes True Type. Caso no exista
nenhuma fonte True Type instalada no sistema,
o mapeador retorna o comportamento
padro.
Instrui o mapeador de fontes a escolher
fontes True Type quando existe mais de uma
fonte com o mesmo nome.
Tabela 4.7: Valores para fdwOutputPrecision.

Podemos utilizar os valores OUT_DEVICE_PRECIS, OUT_RASTER_PRECIS,


ou OUT_PS_ONLY_PRECIS para controlar como o mapeador de
fontes escolhe uma fonte quando o sistema possui diversas com o mesmo
nome. Por exemplo, caso exista uma fonte chamada Symbol tanto como
True Type quanto raster, ao especificarmos o valor OUT_TT_PRECIS, o mapeador de
fonte escolher a verso True Type. Utilizando OUT_TT_ONLY_PRECIS fora o
mapeador de fontes a escolher uma fonte True Type, mesmo que ela seja
substituda por uma fonte de outro nome.

OUT_TT_PRECIS

O parmetro DWORD fdwClipPrecision indica a preciso de corte,


definindo como cortar os caracteres que esto parcialmente do lado de fora
regio de corte, atravs de um dos valores da Tabela 4.8.
Valor
CLIP_DEFAULT_PRECIS
CLIP_EMBEDDED
CLIP_LH_ANGLES

Descrio
Preciso de corte padro.
Este valor deve ser especificado quando
utilizamos uma fonte embedded read-only.
Quando utilizado, a rotao das fontes

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

108

Programao Windows: C e Win32 API com nfase em Multimdia

depende do sistema de coordenadas, caso


contrrio, a rotao sempre ocorre no sentido
anti-horrio.
Valor retornado quando fontes so
enumeradas.

CLIP_STROKE_PRECIS

Tabela 4.8: Valores para fdwClipPrecision.

Definimos a qualidade de sada do texto informando um dos valores da


Tabela 4.9 para o parmetro DWORD fdwQuality. A qualidade de sada define
como a GDI deve igualar os atributos da LOGFONT com a fonte em si.
Valor

Descrio
A impresso da fonte feita suavemente.
Qualidade padro da fonte.
A aparncia da fonte no importante.
A impresso da fonte no feita suavemente.
A qualidade da fonte alta e no ocorrem
distores na aparncia.

ANTIALIASED_QUALITY
DEFAULT_QUALITY
DRAFT_QUALITY
NONANTIALIASED_QUALITY
PROOF_QUALITY

Tabela 4.9: Valores para fdwQuality.

define o pitch e a famlia da fonte. Pitch est


ligado ao espaamento entre os caracteres, podendo ser fixo ou varivel. Um
pitch fixo como a fonte Courier New, onde todas as celas dos caracteres tm
o mesmo espaamento ou seja, mesmo que a letra i tenha uma largura menor
que a letra o, ambas ocupam a mesma largura na impresso. Fontes com pitch
variveis tm celas de larguras diferentes, dependendo do caractere. A Figura
4.5 demonstra exemplos de fontes com pitch fixo e varivel.
DWORD fdwPitchAndFamily

Figura 4.5: Fontes com pitch fixo (esquerda) e varivel (direita).

O parmetro fdwPitchAndFamily pode receber DEFAULT_PITCH (pitch


definido pela fonte), FIXED_PITCH (fora o pitch da fonte a ser fixo
basicamente, o mapeador de fonte escolhe uma outra fonte que tem o pitch
fixo) ou VARIABLE_PITCH (fora o pitch da fonte a ser varivel). Podemos ainda
fazer uma combinao (usando o operador ou bit-a-bit) com os valores da

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

109

Tabela 4.10, que descrevem o estilo da famlia da fonte para o mapeador de


fontes (que usa a informao quando a fonte requisitada no existe).
Valor
FF_DECORATIVE
FF_DONTCARE
FF_MODERN
FF_ROMAN
FF_SCRIPT
FF_SWISS

Descrio
Fontes diferentes, como Old English.
Usar a fonte padro.
Fontes com traado constante, como Courier
New.
Fontes com traado varivel e com serif, como
MS Serif.
Fontes com estilo de escrita mo, como
Script.
Fontes com traado varivel e sem serif, como
MS Sans Serif.
Tabela 4.10: Famlias das fontes.

O ltimo parmetro, LPCTSTR lpszFace, recebe uma string especificando


o nome da fonte que ser utilizada. O tamanho da string no deve ultrapassar
32 caracteres, contando com o ltimo byte \0 (null-string). Se esse parmetro
receber NULL ou uma string vazia, a GDI usa a primeira fonte que coincide com
os atributos informados nos outros parmetros.
Quando no houver problemas, a funo retorna um identificador
HFONT com os atributos passados para os parmetros. Caso contrrio, o retorno
NULL.
Outro mtodo para criarmos uma fonte atravs da funo
CreateFontIndirect():
HFONT CreateFontIndirect(
CONST LOGFONT* lplf // caractersticas da fonte
);

A funo CreateFontIndirect() recebe um ponteiro para uma estrutura


que contm os atributos da fonte que ser criada. O retorno dessa
funo idntica da funo CreateFont().
LOGFONT,

Antes de chamar a funo


membros da estrutura LOGFONT:

CreateFontIndirect(),

devemos inicializar os

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

110

Programao Windows: C e Win32 API com nfase em Multimdia

typedef struct tagLOGFONT {


LONG lfHeight; // altura da fonte
LONG lfWidth; // largura da fonte
LONG lfEscapement;
lfEscapement; // ngulo do texto
LONG lfOrientation;
lfOrientation; // ngulo do texto
LONG lfWeight; // espessura da fonte
BYTE lfItalic; // estilo de fonte itlica
BYTE lfUnderline;
lfUnderline; // estilo de fonte sublinhada
BYTE lfStrikeOut;
lfStrikeOut; // estilo de fonte tachada
BYTE lfCharSet;
lfCharSet; // identificador do estilo dos caracteres
BYTE lfOutPrecision; // preciso de sada
BYTE lfClipPrecision;
lfClipPrecision; // preciso de corte (clipping)
BYTE lfQuality;
lfQuality; // qualidade de sada
BYTE lfPitchAndFamily;
lfPitchAndFamily; // pitch e famlia da fonte
TCHAR lfFaceName[LF_FACESIZE];
lfFaceName[LF_FACESIZE]; // nome da fonte
} LOGFONT, *PLOGFONT;

Note que os membros dessa estrutura so os mesmos dos parmetros


da funo CreateFont(); assim, a explicao dos parmetros de CreateFont() so
aplicados da mesma maneira para a estrutura LOGFONT.
Para exemplificar (Listagem 4.12), vamos criar uma fonte Times New
Roman com tamanho padro (12), itlica e com ngulo de 45 graus, utilizando
ambas funes:
// Cria fonte utilizando funo CreateFont()
HFONT hFonte1 = NULL;
HFonte = CreateFont(0, 0, 450, 450, FW_NORMAL, TRUE, FALSE, FALSE,
ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH, Times New Roman);
// Cria fonte utilizando funo CreateFontIndirect():
// Cria estrutura LOGFONT e inicializa valores
HFONT hFonte2 = NULL;
LOGFONT lf = { 0, 0, 450, 450, FW_NORMAL, TRUE, FALSE, FALSE, ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH,
Times New Roman };
// Cria fonte com as caractersticas informadas em LOGFONT
hFonte2 = CreateFontIndirect(&lf);
Listagem 4.12: Criando fontes.

Quando queremos utilizar todas as caractersticas padres de uma


fonte, basta enviar zero para todos os parmetros, exceto o nome da fonte:
HFONT hFonte3 = CreateFont(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Times New
Roman);

Como as funes CreateFont() e CreateFontIndirect() fazem o mesmo


servio, mudando somente seus parmetros, qual a diferena entre usar uma e
outra? Na realidade, no h nenhuma diferena, porm, a funo
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

111

mais flexvel quando queremos deixar o usurio


modificar os atributos de uma fonte durante a execuo do programa, pois
obtemos os atributos atuais da fonte, armazenamos numa varivel do tipo
LOGFONT e em seguida fazemos as alteraes requisitadas pelo usurio nos
membros da varivel LOGFONT.
CreateFontIndirect()

Se quisermos modificar as caractersticas da fonte HFONT hFonte2 que


criamos nesse tpico, deixando a fonte com ngulo 0, em negrito, retirar o
atributo itlico e mud-la para Arial, podemos usar o seguinte cdigo (Listagem
4.13):
// HFONT hFonte2 e LOGFONT lf j foram criados
// Obtm informaes da fonte e armazena em lf
GetObject(hFonte2, sizeof(LOGFONT), &lf);
// Modifica ngulo para 0, negrita fonte, retira itlico e muda para Arial
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfWeight = FW_BOLD;
lf.lfItalic = FALSE;
lstrcpy(lf.lfFaceName, Arial);
// Define novos atributos para fonte
hFonte2 = CreateFontIndirect(&lf);
Listagem 4.13: Modificando atributos da fonte com GetObject().

Verificando o teclado
Na programao Windows, verificamos o estado do teclado de duas
maneiras: atravs do cdigo de tecla virtual ou atravs do caractere referente
tecla pressionada. Para isso, podemos processar trs mensagens do teclado:
WM_KEYDOWN, WM_KEYUP e WM_CHAR. As duas primeiras esto relacionadas ao cdigo
de tecla virtual, sendo que WM_KEYDOWN enviada ao programa quando o usurio
pressiona alguma tecla e WM_KEYUP enviada quando o usurio solta a tecla.
WM_CHAR enviada quando uma mensagem WM_KEYDOWN traduzida pela funo
TranslateMessage().
Nota: geralmente utilizamos WM_KEYDOWN para verificar se teclas como F1,
ESC, ENTER ou INSERT foram pressionadas e WM_CHAR quando estamos
manipulando strings com o teclado.
Nas trs mensagens, o parmetro lParam armazena os dados da tecla,
indicando a contagem de repetio da tecla, scan code e flags. O lParam dessas
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

112

Programao Windows: C e Win32 API com nfase em Multimdia

mensagens conhecido como Bit Encoded Key-Data e seus bits so compostos


de acordo com a Tabela 4.11.
Bits
0-15
16-23
24

25-28
29
30

31

Descrio
Contagem de repetio da tecla.
Scan code.
Indica se a tecla pressionada de extenso,
como a tecla ALT+CTRL (ALT direito) em
teclados de 101 ou 102 teclas. O valor 1 se a
tecla de extenso ou 0 caso contrrio.
Reservado.
Indica cdigo de contexto. O valor sempre
zero na mensagem WM_KEYDOWN.
Indica o estado anterior da tecla. O valor 1 se
a tecla estava pressionada antes da mensagem
ser enviada ou 0 se tecla no estava pressionada.
Indica o estado de transio. O valor sempre
zero na mensagem WM_KEYDOWN.
Tabela 4.11: lParam das mensagens de teclado.

A Tabela 4.12 lista alguns valores das teclas virtuais, que so verificadas
durante o processo da mensagem WM_KEYDOWN e WM_KEYUP. Note que todos os
cdigos das teclas virtuais comeam com VK_*.
Valor
VK_CANCEL
VK_BACK
VK_TAB
VK_RETURN
VK_ESCAPE
VK_SHIFT
VK_CONTROL
VK_MENU
VK_PAUSE
VK_SPACE
VK_PRIOR
VK_NEXT
VK_END
VK_HOME
VK_INSERT

Tecla correspondente
Control+break
Backspace
Tab
Enter
Esc
Shift
Control
Alt
Pause
Barra de espao
Page Up
Page Down
End
Home
Insert
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada


VK_DELETE
VK_UP
VK_DOWN
VK_LEFT
VK_RIGHT
VK_SNAPSHOT
VK_CAPITAL
VK_SCROLL
VK_NUMLOCK
VK_LWIN
VK_RWIN
VK_APPS
VK_NUMPAD0 ... VK_NUMPAD9
VK_ADD
VK_SUBTRACT
VK_MULTIPLY
VK_DIVIDE
VK_F1 ... VK_F12

113

Delete
Seta acima
Seta abaixo
Seta esquerda
Seta direita
Print Screen
Caps Lock
Scroll Lock
Num Lock
Windows da esquerda
Windows da direita
Tecla de Menu Pop-up
Teclado numrico 0 ... 9
Sinal +
Sinal Sinal *
Sinal /
Teclas F1 F12

Tabela 4.12: Alguns valores das teclas virtuais.

Nota: no h cdigos de teclas virtuais para os nmeros 0 - 9 e letras A Z. Para verific-las nas mensagens WM_KEYDOWN e WM_KEYUP, utilize os valores
hexadecimais 30...39 para os nmeros e 41...5A para as letras, ou A - Z,
0 9 (letras maisculas).
Para exemplificar o processamento de cada uma dessas mensagens
(Listagem 4.14), podemos mostrar na rea cliente quais teclas o usurio
pressionou, no seu formato ASCII (mensagem WM_CHAR) e mostrar uma
mensagem quando o usurio pressionar alguma seta do teclado (mensagem
WM_KEYDOWN):
case WM_CHAR: // Obtm o cdigo ASCII da tecla pressionada
{
char szTecla[1] = { 0 }; // Armazena tecla pressionada
static int itx = 8; // Posio x na rea cliente
// Obtm identificador do DC
hDC = GetDC(hWnd);
// Armazena tecla pressionada em szTecla
sprintf(szTecla, %c, wParam);
// Mostra tecla na rea cliente
TextOut(hDC, itx, 8, szTecla, strlen(szTecla));

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

114

Programao Windows: C e Win32 API com nfase em Multimdia

// Incrementa posio x
itx += 16;
// Libera DC
ReleaseDC(hWnd, hDC);
return(0);
} break;
case WM_KEYDOWN: // Obtm tecla virtual
{
switch(wParam) // Verifica qual tecla virtual foi pressionada
{
case VK_LEFT: // Seta Esquerda
{
MessageBox(hWnd, "SETA PRA ESQUERDA PRESSIONADA!", "TECLADO", MB_OK);
} break;
case VK_RIGHT: // Seta Direita
{
MessageBox(hWnd, "SETA PRA DIREITA PRESSIONADA!", "TECLADO", MB_OK);
} break;
case VK_UP: // Seta Acima
{
MessageBox(hWnd, "SETA PRA CIMA PRESSIONADA!", "TECLADO", MB_OK);
} break;
case VK_DOWN: // Seta Abaixo
{
MessageBox(hWnd, "SETA PRA BAIXO PRESSIONADA!", "TECLADO", MB_OK);
} break;
}
return(0);
} break;
Listagem 4.14: Processando as mensagens WM_CHAR e WM_KEYDOWN.

O cdigo-fonte do programa-exemplo prog04-1.cpp mostrado na


Listagem 4.15:
//-------------------------------------------------------------------------// prog04-1.cpp - Processando mensagens do teclado e GDI
//-------------------------------------------------------------------------//-------------------------------------------------------------------------// Bibliotecas
//-------------------------------------------------------------------------#include <windows.h>
#include <stdio.h>
//-------------------------------------------------------------------------// Definies
//-------------------------------------------------------------------------// Nome da classe da janela
#define WINDOW_CLASS
"prog04-1"
// Ttulo da janela
#define WINDOW_TITLE
"Prog 04-1"
// Largura da janela
#define WINDOW_WIDTH
320

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada


// Altura da janela
#define WINDOW_HEIGHT

115

240

//-------------------------------------------------------------------------// Prottipo das funes


//-------------------------------------------------------------------------LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);
//-------------------------------------------------------------------------// WinMain() -> Idntica ao cdigo do prog02.cpp
//-------------------------------------------------------------------------//-------------------------------------------------------------------------// WindowProc() -> Processa as mensagens enviadas para o programa
//-------------------------------------------------------------------------LRESULT CALLBACK WindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
// Variveis para manipulao da parte grfica do programa
HDC hDC = NULL;
PAINTSTRUCT psPaint;
// Armazena qual tecla foi pressionada
static char szMensagem[10] = { 0 };
// Verifica qual foi a mensagem enviada
switch(uMsg)
{
case WM_CREATE: // Janela foi criada
{
// Retorna 0, significando que a mensagem foi processada corretamente
return(0);
} break;
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{
// Obtm identificador do DC e preenche PAINTSTRUCT
hDC = BeginPaint(hWnd, &psPaint);
// Imprime texto na parte superior da rea cliente
SetTextColor(hDC, RGB(128, 0, 128));
TextOut(hDC, 8, 8, szMensagem, strlen(szMensagem));
// Obtm rea cliente
RECT rcArea;
GetClientRect(hWnd, &rcArea);
// Imprime texto na rea cliente
SetTextColor(hDC, 0x0000FF00);
DrawText(hDC, "Utilizando GDI", -1, &rcArea, DT_SINGLELINE | DT_CENTER
| DT_VCENTER);
// Libera DC e valida rea
EndPaint(hWnd, &psPaint);
return(0);
} break;
case WM_CLOSE: // Janela foi fechada

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

116

Programao Windows: C e Win32 API com nfase em Multimdia


{
// Destri a janela
DestroyWindow(hWnd);
return(0);
} break;
case WM_DESTROY: // Janela foi destruda
{
// Envia mensagem WM_QUIT para o loop de mensagens
PostQuitMessage(0);
return(0);
} break;
case WM_CHAR: // Obtm o cdigo ASCII da tecla pressionada
{
// Obtm identificador do DC
hDC = GetDC(hWnd);
// Verifica a tecla pressionada e mostra no programa
sprintf(szMensagem, "Tecla: %c ", (char)wParam, lParam);
TextOut(hDC, 8, 8, szMensagem, strlen(szMensagem));
// Libera DC
ReleaseDC(hWnd, hDC);
return(0);
} break;

case WM_KEYDOWN: // Obtm tecla virtual


{
switch(wParam) // Verifica qual tecla virtual foi pressionada
{
case VK_LEFT: // Seta Esquerda
{
MessageBox(hWnd, "SETA PRA ESQUERDA PRESSIONADA!", "TECLADO",
MB_OK);
} break;
case VK_RIGHT: // Seta Direita
{
MessageBox(hWnd, "SETA PRA DIREITA PRESSIONADA!", "TECLADO",
MB_OK);
} break;
case VK_UP: // Seta Acima
{
MessageBox(hWnd, "SETA PRA CIMA PRESSIONADA!", "TECLADO", MB_OK);
} break;
case VK_DOWN: // Seta Abaixo
{
MessageBox(hWnd, "SETA PRA BAIXO PRESSIONADA!", "TECLADO", MB_OK);
} break;
}
return(0);
} break;
default: // Outra mensagem
{

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

117

/* Deixa o Windows processar as mensagens que no foram verificadas na


funo */
return(DefWindowProc(hWnd, uMsg, wParam, lParam));
}
}
}
Listagem 4.15: Cdigo-fonte do programa-exemplo prog04-1.cpp.

Outra forma de verificar o teclado


Uma maneira diferente de verificar o estado das teclas atravs da
funo GetAsyncKeyState(). Essa funo pode ser chamada em qualquer parte
do programa, independente de estarmos processando uma mensagem de
teclado ou no (embora no seja recomendado chamar essa funo no
processamento de mensagens de teclado); ela simplesmente retorna o estado de
uma tecla (pressionada/no pressionada) no momento que for chamada.
SHORT GetAsyncKeyState(
int vKey // cdigo de tecla virtual
);

A funo recebe o parmetro int vKey, que o cdigo de tecla virtual,


listados previamente na Tabela 4.12. Ela retorna um tipo SHORT indicando se a
tecla (informada em vKey) est pressionada (bit mais significativo est ativado)
ou no. Para verificarmos se uma tecla est pressionada, fazemos uma
operao AND bit-a-bit do retorno da funo com o valor hexadecimal
0x8000 (que verifica se o bit mais significativo est ativado).
Por exemplo, para verificar se a tecla ENTER foi pressionada,
utilizamos o cdigo da Listagem 4.16:
if(GetAsyncKeyState(VK_RETURN) & 0x8000)
// Tecla pressionada
else
// Tecla no pressionada
Listagem 4.16: Usando GetAsyncKeyState().

Alm dos cdigos da Tabela 4.12, a funo GetAsyncKeyState() aceita os


cdigos da Tabela 4.13, que diferenciam as teclas SHIFT, CONTROL e ALT
da esquerda e direita e os botes do mouse.
Valor
VK_LSHIFT

Tecla correspondente
Shift da esquerda.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

118

Programao Windows: C e Win32 API com nfase em Multimdia

VK_RSHIFT

Shift da direita.
Control da esquerda.
Control da direita.
Alt da esquerda.
Alt da direita.
Boto esquerdo do mouse.
Boto do meio do mouse.
Boto direito do mouse.

VK_LCONTROL
VK_RCONTROL
VK_LMENU
VK_RMENU
VK_LBUTTON
VK_MBUTTON
VK_RBUTTON

Tabela 4.13: Cdigos de teclas-virtuais extras para GetAsyncKeyState().

Verificando o mouse
Alm do teclado, outro dispositivo de entrada/controle o mouse. O
funcionamento de um mouse mais simples que o de um teclado, pois h
apenas a movimentao do mesmo e o uso de dois ou trs botes, em geral. A
Win32 API possui mensagens para processamento de movimentao do
mouse e clique dos botes, conforme a Tabela 4.14:
Mensagem
WM_MOUSEMOVE
WM_LBUTTONDBLCLK

WM_LBUTTONDOWN
WM_LBUTTONUP
WM_MBUTTONDBLCLK

WM_MBUTTONDOWN
WM_MBUTTONUP
WM_RBUTTONDBLCLK

Descrio
Enviada quando o mouse sofre movimentao.
Enviada quando o usurio d um duplo-clique
no boto esquerdo do mouse. necessrio
definir o membro WNDCLASSEX.style com o flag
CS_DBLCLKS.
Enviada quando o usurio clica no boto
esquerdo do mouse.
Enviada quando o usurio solta o boto
esquerdo do mouse.
Enviada quando o usurio d um duplo-clique
no boto do meio do mouse. necessrio
definir o membro WNDCLASSEX.style com o flag
CS_DBLCLKS.
Enviada quando o usurio clica no boto do
meio do mouse.
Enviada quando o usurio solta o boto do
meio do mouse.
Enviada quando o usurio d um duplo-clique
no boto direito do mouse. necessrio
definir o membro WNDCLASSEX.style com o flag

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

119

CS_DBLCLKS.
WM_RBUTTONDOWN
WM_RBUTTONUP

Enviada quando o usurio clica no boto


direito do mouse.
Enviada quando o usurio solta o boto direito
do mouse.
Tabela 4.14: Mensagens do mouse.

Para trabalharmos com o mouse, devemos processar as mensagens


(Tabela 4.14) de acordo com as aes do mouse que o programa responder. J
exemplificamos anteriormente como desenhar um crculo no local onde o
ponteiro do mouse est localizado (dentro da rea cliente), quando o usurio
clica o boto esquerdo do mesmo (veja a Listagem 4.2), mas vamos verificar
outro exemplo.
O cdigo da Listagem 4.17 processa a mensagem e WM_MOUSEMOVE, ou
seja, sempre ser processada quando o mouse mudar de posio. A mensagem
WM_RBUTTONDOWN tambm processada, armazenando o ponto inicial do cursor
durante o traado. Nesse exemplo, verificamos se o boto direito do mouse
est pressionado e, se estiver, traamos uma linha seguindo o ponteiro do
mouse. No se preocupe caso no entenda o uso de certas funes como
MoveToEx() e LineTo(), pois iremos estud-las no prximo captulo.
// Armazena posio (x, y) do cursor do mouse
static int x = 0;
static int y = 0;
case WM_RBUTTONDOWN: // Boto direito do mouse pressionado
{
// Obtm posio (x, y) atual do cursor do mouse
x = LOWORD(lParam);
y = HIWORD(lParam);
return(0);
} break;
case WM_MOUSEMOVE: // Cursor do mouse modificado
{
// Verifica se o boto direito est pressionado
if(wParam == MK_RBUTTON)
{
// Obtm identificador do DC
hDC = GetDC(hWnd);
// Move cursor para posio (x, y) anterior do mouse
MoveToEx(hDC, x, y, NULL);
// Obtm posio (x, y) atual do cursor do mouse
x = LOWORD(lParam);
y = HIWORD(lParam);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

120

Programao Windows: C e Win32 API com nfase em Multimdia

// Traa reta
LineTo(hDC, x, y);
// Libera DC
ReleaseDC(hWnd, hDC);
}
return(0);
} break;
Listagem 4.17: Processando a mensagem WM_MOUSEMOVE.

No processo das mensagens do mouse, existem alguns valores prdefinidos (Tabela 4.15) que indicam o estado de seus botes (pressionado ou
no), fazendo a verificao em wParam. No exemplo da Listagem 4.17,
comparamos wParam com MK_RBUTTON, para verificarmos se o boto direito do
mouse est pressionado.
Valor
MK_LBUTTON
MK_MBUTTON
MK_RBUTTON

Descrio
Boto esquerdo do mouse est pressionado.
Boto do meio do mouse est pressionado.
Boto direito do mouse est pressionado.
Tabela 4.15: Estado dos botes do mouse.

Veja o arquivo prog04-2.cpp no CD-ROM, o qual contm o cdigo-fonte


com o programa-exemplo de processamento de mensagens do mouse,
ilustrado na Figura 4.6.

Figura 4.6: Uso do mouse no programa.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 4 GDI, Textos e Eventos de Entrada

121

Verificando o mouse, II
Tambm podemos utilizar a funo GetAsyncKeyState() para obtermos
o estado dos botes do mouse quando no estamos processando suas
mensagens (veja valores dos botes do mouse na Tabela 4.12).
Para sabermos a posio do cursor do mouse a qualquer momento,
utilizamos a funo GetCursorPos():
BOOL GetCursorPos(
LPPOINT lpPoint // posio do cursor
);

Essa funo recebe um parmetro LPPOINT, que um ponteiro para um


tipo de dado definido pelo Windows, POINT. O retorno da funo zero se
falhar ou diferente de zero caso contrrio.
O tipo de dado POINT tem a seguinte estrutura:
typedef struct tagPOINT {
LONG x; // coordenada x do ponto
LONG y; // coordenada y do ponto
} POINT, *PPOINT;

Podemos, ainda, modificar a posio do cursor do mouse, atravs da


funo SetCursorPos().
BOOL SetCursorPos(
int X, // nova posio x do cursor
int Y // nova posio y do cursor
);

A funo SetCursorPos() recebe como parmetros a nova coordenada


(X, Y) da posio do cursor do mouse. O retorno da funo zero se falhar ou
diferente de zero caso contrrio.
A Listagem 4.18 mostra como obter a posio do cursor do mouse em
qualquer momento, armazenando-a numa varivel do tipo POINT, e em seguida,
modificar a posio atual do cursor.
// Armazena a posio do cursor do mouse
POINT ptMousePos;
// Obtm posio do cursor
GetCursorPos(&ptMousePos);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

122

Programao Windows: C e Win32 API com nfase em Multimdia

// Modifica a posio do cursor do mouse


ptMousePos.x += 10;
ptMousePos.y -= 25;
SetCursorPos(ptMousePos.x, ptMousePos.y);
Listagem 4.18: Utilizando GetCursorPos() e SetCursorPos().

Com o trmino desse captulo, voc j est apto a fazer a interao do


usurio com o seu programa, atravs do teclado e do mouse. Alm disso, voc
aprendeu a mostrar textos na rea cliente do programa. O prximo passo
verificar como desenhar pontos, retas e outros tipos de grficos no seu
programa.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 5 Grficos com GDI

123

Captulo 5 Grficos com GDI


No captulo anterior, fizemos uma introduo Graphics Device Interface
e seus objetos grficos. Agora, vamos aprender como trabalhar com canetas e
pincis e como desenhar grficos vetoriais.
Nota: o Windows trabalha com dois tipos de grficos: vetoriais e mapas de
bits. Grficos vetoriais so formados por retas e curvas (que nada mais so
do que aproximaes de retas) que podem ser facilmente modificadas
atravs de equaes matemticas. Grficos do tipo mapa de bits (ou
bitmap, tambm conhecido por raster bitmap) so representados, como o
nome diz, por um mapa de bits, onde cada bit representa uma cor no
mapa. A manipulao desse tipo de grfico um pouco mais complicada,
pois preciso manipul-lo ponto-a-ponto. Programas que trabalham com
grficos vetoriais tendem a ser mais rpidos na manipulao dos mesmos
do que programas que trabalham com grficos bitmap, porm, bitmaps
possuem mais detalhes e maior nvel de realismo (como fotos, por
exemplo).

Um simples ponto
Em computao grfica, o pixel (ponto) a base da criao de todos os
grficos e o menor grfico que voc pode manipular. Retas e curvas so
formadas por diversos pixels, assim como uma foto no computador
composta por milhares de pixels, cada um com uma certa tonalidade de cor.
Podemos desenhar pontos na rea cliente de um programa com duas
funes: SetPixel() e SetPixelV().
COLORREF SetPixel(
HDC hdc, // identificador do DC
int X, // coordenada x do pixel
int Y, // coordenada y do pixel
COLORREF crColor // cor do pixel
);
BOOL SetPixelV(
HDC hdc, // identificador do DC
int X, // coordenada x do pixel
int Y, // coordenada y do pixel
COLORREF crColor // cor do pixel
);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

124

Programao Windows: C e Win32 API com nfase em Multimdia

Ambas funes desenham um ponto de cor crColor na coordenada (X,


da rea cliente, especificado pelos parmetros. A diferena entre essas
funes o tipo de retorno de cada uma.

Y)

A funo SetPixel() retorna o valor da cor RGB que a funo


desenhou o ponto. O valor retornado pode ser diferente do especificado no
parmetro crColor, pois nem sempre o sistema est configurado para exibir
todas as combinaes de cores (por exemplo, um sistema configurado com
exibio de apenas 256 cores). A funo retorna 1 em caso de falha (ocorre
quando as coordenadas esto fora de alcance da rea cliente).
J a funo SetPixelV() retorna zero se falhar ou um valor diferente de
zero caso contrrio. Assim como SetPixel(), a funo faz uma aproximao da
cor especificada em crColor. Por no retornar o valor da cor RGB que o ponto
foi desenhado, essa funo mais rpida que SetPixel().
A Figura 5.1 demonstra a execuo do programa-exemplo prog05-1.cpp,
que encontra-se no CD-ROM.

Figura 5.1: Desenhando pontos.

Dica: assim como existem funes do tipo SetAlgumaCoisa() (para definir


AlgumaCoisa), podem existir equivalentes GetAlgumaCoisa(), que obtm
informaes de AlgumaCoisa. No caso da funo SetPixel(), h o seu
equivalente GetPixel(), que retorna a cor RGB de determinada coordenada
(x, y) da rea cliente.
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 5 Grficos com GDI

125

Canetas e pincis
Alguns termos utilizados na programao grfica do Windows podem
ser facilmente relacionados com a vida real. Assim, veremos como funciona o
uso de canetas e pincis GDI com exemplos do dia-a-dia.
Um dos principais usos da caneta a caligrafia, mas tambm podemos
usar canetas (e lpis) para desenhar, ou seja, fazer o contorno de uma figura.
Existem diversos tipos e modelos de canetas algumas tm cor da tinta azul,
preta, vermelha, entre outras cores; H canetas com ponta fina e outras com
ponta grossa. Quando desenhamos algo, podemos tracejar linhas contnuas,
espaadas, pontilhadas e de diversas outras maneiras. exatamente para isso
que serve uma caneta na GDI: definir propriedades (cor, espessura, tipo de
linha) para ser aplicado em retas, curvas e contornos de figuras.
Numa pintura leo, depois que o pintor faz o esboo (traado) da sua
obra na tela, ele comea a trabalhar com pincis e tintas (e outras ferramentas
que no vem ao caso) para preencher os espaos vazios entre os traados. No
caso da GDI, os pincis tambm so utilizados para preenchimento (podemos
pensar nos pincis como a ferramenta balde de tinta encontrada em softwares
de edio grfica), podendo ter cores slidas, preenchimento de linhas ou de
texturas.

Criando canetas
Para criarmos uma caneta, usamos a funo CreatePen(), definindo suas
propriedades.
HPEN CreatePen(
int fnPenStyle,
fnPenStyle, // estilo da caneta
int nWidth, // espessura da caneta
COLORREF crColor // cor da caneta
);

A funo recebe como parmetros um estilo de caneta, int fnPenStyle,


que pode ser um dos valores da Tabela 5.1, a espessura (int nWidth) e sua cor
(COLORREF crColor). O retorno da funo o identificador da nova caneta ou
NULL no caso de erro.
Valor
PS_SOLID

Descrio
Caneta slida.
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

126

Programao Windows: C e Win32 API com nfase em Multimdia

PS_DASH

Caneta tracejada.
Caneta pontilhada.
Caneta alternando trao e ponto.
Caneta alternando trao e pontos duplos.
Caneta invisvel.

PS_DOT
PS_DASHDOT
PS_DASHDOTDOT
PS_NULL

Tabela 5.1: Estilos de caneta.

Se nWidth receber zero, a espessura da caneta ser de um pixel. Apenas


canetas com estilo PS_SOLID podem ter a espessura maior que um pixel. Se a
caneta for criada com os estilos PS_DASH, PS_DOT, PS_DASHDOT ou PS_DASHDOTDOT e
nWidth for maior que um, a funo ir criar uma caneta do tipo PS_SOLID com a
espessura indicada.
A Listagem 5.1 exemplifica o procedimento para criar e usar uma
caneta dentro da mensagem WM_PAINT.
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{
// Obtm identificador do DC e preenche PAINTSTRUCT
hDC = BeginPaint(hWnd, &psPaint);
// Cria e seleciona nova caneta no DC e salva caneta antiga
HPEN hPen = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
HPEN hPenOld = (HPEN)SelectObject(hDC, hPen);
//
// Cdigo para desenhar grficos
//
// Restaura caneta antiga e deleta nova caneta
SelectObject(hDC, hPenOld);
DeleteObject(hPen);
// Libera DC e valida rea
EndPaint(hWnd, &psPaint);
return(0);
} break;
Listagem 5.1: Criando e utilizando uma caneta.

Nota: para utilizarmos canetas e qualquer outro objeto GDI, devemos


selecion-los no DC atravs da funo SelectObject(), conforme explicado
no captulo 4.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 5 Grficos com GDI

127

Criando pincis
Podemos criar e utilizar quatro tipos de pincis: preenchimento com
cores slidas, com linhas, com texturas e pincis definidos pelo sistema. Para
cada tipo, existem funes especficas para criar pincis, respectivamente:
CreateSolidBrush(),
CreateHatchBrush(),
CreatePatternBrush()
e
GetStockObject().
HBRUSH CreateSolidBrush(
COLORREF crColor // cor do pincel
);

A funo CreateSolidBrush() recebe o parmetro COLORREF crColor, um


valor enviado com o uso da macro RGB(), determinando a cor do pincel que
ser criado. Retorna o identificador do novo pincel ou NULL no caso de erro.
HBRUSH CreateHatchBrush(
int fnStyle, // estilo de linha
COLORREF clrref // cor de fundo
);

O primeiro parmetro que CreateHatchBrush() recebe indica o estilo de


preenchimento de linhas, conforme a Tabela 5.2. O segundo parmetro indica
a cor das linhas de preenchimento. A funo retorna o identificador do novo
pincel ou NULL no caso de erro.
Valor
HS_BDIAGONAL
HS_CROSS
HS_DIAGCROSS
HS_FDIAGONAL
HS_HORIZONTAL
HS_VERTICAL

Descrio
Linhas diagonais (da esquerda para direita e
para cima).
Linhas horizontais e verticais.
Linhas diagonais cruzadas.
Linhas diagonais (da esquerda para direita e
para baixo).
Linhas horizontais.
Linhas verticais.
Tabela 5.2: Estilos de preenchimento de linhas.

HBRUSH CreatePatternBrush(
HBITMAP hbmp // identificador do bitmap
);

O parmetro hbmp da funo CreatePatternBrush() recebe o


identificador de uma imagem bitmap. Estudaremos o uso de bitmaps no
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

128

Programao Windows: C e Win32 API com nfase em Multimdia

prximo captulo. A funo retorna o identificador do novo pincel ou


caso de erro.

NULL

no

J discutimos o uso de pincis definidos pelo sistema no captulo 2,


durante a definio da classe da janela de um programa. Usamos a funo
GetStockObject(), que recebe valores da Tabela 2.4.
Para criao e uso de pincis, seguimos o mesmo processo das canetas:
criamos um pincel, com sua respectiva funo, salvando-o numa varivel do
tipo HBRUSH. Em seguida, selecionamos o novo pincel no DC e, ao mesmo
tempo, salvamos o pincel antigo que estava selecionado no DC, com a funo
SelectObject(). Depois de utilizado, restauramos o pincel antigo e deletamos o
novo. A Listagem 5.2 exemplifica esse processo, criando um pincel com linhas
horizontais.
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{
// Obtm identificador do DC e preenche PAINTSTRUCT
hDC = BeginPaint(hWnd, &psPaint);
// Cria e seleciona novo pincel no DC e salva pincel antigo
HBRUSH hBrush = CreateHatchBrush(HS_HORIZONTAL, RGB(255, 255, 128));
HBRUSH hBrushOld = (HBRUSH)SelectObject(hDC, hBrush);
//
// Cdigo para desenhar grficos
//
// Restaura pincel antigo e deleta novo pincel
SelectObject(hDC, hBrushOld);
DeleteObject(hBrush);
// Libera DC e valida rea
EndPaint(hWnd, &psPaint);
return(0);
} break;
Listagem 5.2: Criando e utilizando um pincel.

Combinao de cores (mix mode)


A GDI utiliza o mix mode (modo de combinao de cores) para
determinar como a cor de uma caneta ou pincel ser aplicada/misturada em
cima das cores j existentes na rea cliente, conforme a Tabela 5.3.
Valor
R2_BLACK

Descrio
Cor sempre preta.
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 5 Grficos com GDI


R2_COPYPEN
R2_MASKNOTPEN
R2_MASKPEN
R2_MASKPENNOT
R2_MERGENOTPEN
R2_MERGEPEN
R2_MERGEPENNOT
R2_NOP
R2_NOT
R2_NOTCOPYPEN
R2_NOTMASKPEN
R2_NOTMERGEPEN
R2_NOTXORPEN
R2_WHITE
R2_XORPEN

129

Cor da caneta / pincel (padro).


Combinao das cores comuns da rea
cliente e da cor inversa da caneta / pincel.
Combinao das cores comuns da rea
cliente e da caneta / pincel.
Combinao das cores comuns da cor
inversa da rea cliente e da caneta / pincel.
Combinao da cor da rea cliente e da cor
inversa da caneta / pincel.
Combinao da cor da rea cliente e da cor
da caneta / pincel.
Combinao da cor inversa da rea cliente e
da cor da caneta / pincel.
Cor igual da rea cliente (nada desenhado).
Cor inversa da rea cliente.
Cor inversa da caneta / pincel.
Cor inversa de R2_MASKPEN.
Cor inversa de R2_MERGEPEN.
Cor inversa de R2_XORPEN.
Cor sempre branca.
Combinao das cores na rea cliente e na
caneta / pincel, mas no em ambas.
Tabela 5.3: Mix mode.

Para configurar o mix mode, utilizamos a funo SetROP2().


int SetROP2(
HDC hdc, // identificador do DC
int fnDrawMode // mix mode
);

O primeiro parmetro da funo o identificador do DC utilizado. O


segundo parmetro pode receber um dos valores da Tabela 5.3, especificando
o mix mode. A funo retorna o valor do mix mode anterior (Tabela 5.3) ou zero
no caso de erro.
O mix mode padro da GDI R2_COPYPEN, ou seja, no importa a cor da
rea cliente, os pontos das linhas sempre sero desenhadas com as
propriedades da caneta atual e o preenchimento ser feito com as propriedades
do pincel atual. Se definirmos o mix mode como R2_XORPEN, tudo que for
desenhado na rea cliente ter sua cor (da caneta e pincel) invertida, dando
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

130

Programao Windows: C e Win32 API com nfase em Multimdia

aquele efeito de negativo da imagem. Com o mix mode definido como R2_NOT,
uma linha ser desenhada com a cor inversa da rea cliente. Caso a mesma
linha seja desenhada novamente, a mesma ser apagada, pois a cor da rea
cliente voltar ao seu original.
Nota: o valor R2_NOT funciona como o operador
como no exemplo abaixo:

(not) da linguagem C,

bool teste = true; // teste verdadeiro


teste = !teste; // teste fica falso
teste = !teste; // teste volta a ser verdadeiro

Traando linhas retas


Antes de desenharmos uma linha reta, devemos indicar a coordenada
(x, y) inicial da mesma. A GDI armazena um cursor invisvel indicando essa
coordenada. Para modific-la, usamos a funo MoveToEx():
BOOL MoveToEx(
HDC hdc, // identificador do DC
int X, // nova coordenada x
int Y, // nova coordenada y
LPPOINT lpPoint // coordenada anterior
);

Os trs primeiros parmetros so auto-explicativos. O ltimo, LPPOINT


lpPoint, pode receber um ponteiro para uma estrutura POINT, na qual ser
armazenada a coordenada anterior chamada da funo. Se esse parmetro
receber NULL, ento a coordenada anterior no ser armazenada. A funo
retorna um valor diferente de zero quando bem sucedida ou zero se falhar.
Nota: todas as funes de desenho sempre recebem como primeiro
parmetro o identificador do DC (HDC hdc) que estamos utilizando.
Feito isso, o prximo passo indicar a coordenada (x, y) final da reta
que iremos traar, atravs da funo LineTo(). Quanto cor e espessura da reta,
so utilizadas as propriedades da caneta selecionada no DC.
BOOL LineTo(
HDC hdc, // identificador do DC
int nXEnd, // coordenada x do fim da reta
int nYEnd // coordenada y do fim da reta
);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 5 Grficos com GDI

131

Novamente, os parmetros da funo so auto-explicativos. A funo


retorna um valor diferente de zero quando bem sucedida ou zero se falhar.
Nota: LineTo() traa uma reta da posio atual do cursor invisvel at a
coordenada (x, y) informada na funo, porm, esse ponto (x, y) no
incluso no traado da reta.
Depois de executada, a funo LineTo() atualiza a posio do cursor
invisvel para a coordenada (x, y) final da reta. Assim, se quisermos traar uma
reta ligada que acabamos de traar, podemos chamar novamente a funo
LineTo(), sem a necessidade de definir a coordenada inicial com MoveToEx(). A
Listagem 5.3 mostra como traar quatro linhas ligadas entre si, formando um
losango:
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{
// Obtm identificador do DC e preenche PAINTSTRUCT
hDC = BeginPaint(hWnd, &psPaint);
// Caneta j foi criada e selecionada no DC
// Move cursor invisvel para (50, 50)
MoveToEx(hDC, 50, 50, NULL);
// Desenha quatro retas, formando um losango
LineTo(hDC, 20, 70);
LineTo(hDC, 50, 90);
LineTo(hDC, 80, 70);
LineTo(hDC, 50, 50);
// Restaura caneta antiga e deleta nova caneta
// Libera DC e valida rea
EndPaint(hWnd, &psPaint);
return(0);
} break;
Listagem 5.3: Uso de MoveToEx() e LineTo().

Ao invs de fazermos quatro chamadas funo LineTo() para


desenhar o losango, podemos criar um vetor do tipo POINT, onde sero
armazenados os pontos do losango, e traar as retas com o uso da funo
PolylineTo().
BOOL PolylineTo(
HDC hdc, // identificador do DC
CONST POINT *lppt, // vetor de pontos
DWORD cCount // nmero de pontos no vetor
);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

132

Programao Windows: C e Win32 API com nfase em Multimdia

A funo recebe o identificador do DC como primeiro parmetro. Em


passamos o vetor onde esto armazenados os pontos das
retas e informamos a quantidade de pontos no parmetro DWORD cCount. A
funo retorna um valor diferente de zero quando bem sucedida ou zero se
ocorrer algum erro.

CONST POINT *lppt,

PolylineTo(), assim como LineTo(), atualiza a posio do cursor


invisvel para a coordenada (x, y) do ltimo ponto do vetor passado em *lppt.

A Listagem 5.4 uma modificao da Listagem 5.3; dessa vez,


utilizamos PolylineTo() ao invs de LineTo().
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{
// Obtm identificador do DC e preenche PAINTSTRUCT
hDC = BeginPaint(hWnd, &psPaint);
// Caneta j foi criada e selecionada no DC
// Define pontos do losango
POINT ptLosango[4];
ptLosango[0].x = 20;
ptLosango[0].y = 70;
ptLosango[1].x = 50;
ptLosango[1].y = 90;
ptLosango[2].x = 80;
ptLosango[2].y = 70;
ptLosango[3].x = 50;
ptLosango[3].y = 50;
// Move cursor invisvel para (50, 50)
MoveToEx(hDC, 50, 50, NULL);
// Desenha quatro retas formadas pelos pontos do vetor ptLosango[4],
// formando o losango
PolylineTo(hDC, ptLosango, 4);
// Restaura caneta antiga e deleta nova caneta
// Libera DC e valida rea
EndPaint(hWnd, &psPaint);
return(0);
} break;
Listagem 5.4: Uso de PolylineTo().

Nota: h tambm a funo Polyline(), que tm a mesma funo que


PolylineTo(), com a nica diferena que ela no utiliza nem atualiza o
cursor invisvel. Polyline() ignora a coordenada (x, y) informada em
MoveToEx() e usa o primeiro ponto do vetor do tipo POINT como primeira
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 5 Grficos com GDI

133

coordenada. Verifique a diferena entre essas funes, chamando


Polyline() no lugar de PolylineTo() no exemplo da Listagem 5.4.
A Figura 5.2 demonstra a execuo do programa-exemplo prog05-2.cpp,
que encontra-se no CD-ROM.

Figura 5.2: Losangos com linhas retas.

Traando linhas curvas


Alm de linhas retas, podemos traar linhas curvas, que podem ser
curvas parciais de uma elipse ou de forma livre (curvas de Bzier). Vamos
trabalhar inicialmente com arcos.
Quando vamos traar um arco, a GDI, por padro, desenha o arco em
sentido anti-horrio, como no sistema cartesiano. Podemos modificar o
sentido com a funo SetArcDirection():
int SetArcDirection(
HDC hdc, // identificador do DC
int ArcDirection // direo do arco
);

A funo recebe o identificador do DC no primeiro parmetro. O


segundo parmetro define o sentido do arco e pode receber os valores
AD_COUNTERCLOCKWISE (sentido anti-horrio) ou AD_CLOCKWISE (sentido horrio). A

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

134

Programao Windows: C e Win32 API com nfase em Multimdia

funo retorna o sentido que estava definido anteriormente ou zero se ocorrer


erro.
Para traarmos um arco, chamamos a funo Arc():
BOOL Arc(
HDC hdc, // identificador do DC
int nLeftRect, // coordenada x do canto superior esquerdo do retngulo
int nTopRect, // coordenada y do canto superior esquerdo do retngulo
int nRightRect, // coordenada x do canto inferior direito do retngulo
int nBottomRect, // coordenada y do canto inferior direito do retngulo
int nXStartArc, // coordenada x do ponto inicial do arco
int nYStartArc, // coordenada y do ponto inicial do arco
int nXEndArc, // coordenada x do ponto final do arco
int nYEndArc // coordenada y do ponto final do arco
);

O primeiro parmetro da funo recebe o identificador do DC. Os


prximos quatro parmetros indicam o retngulo (invisvel) formado pelas
extremidades da elipse. Os parmetros nXStartArc e nYStartArc indicam a
coordenada do ponto inicial do arco; nXEndArc e nYEndArc indicam a coordenada
do ponto final do arco. Essas duas coordenadas formam retas (tambm
invisveis) com o centro da elipse, determinando o arco que ser traado. A
funo retorna um valor diferente de zero quando o arco desenhado, ou zero
quando o arco no desenhado.
Dica: caso as coordenadas do ponto inicial e final sejam iguais, uma elipse
completa ser desenhada.
A Figura 5.3 mostra como funciona a funo
sentido anti-horrio.

Arc(),

com a direo no

Figura 5.3: Como funciona a funo Arc().

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 5 Grficos com GDI

135

Nota: h tambm a funo ArcTo() para desenhar arcos, porm, ela utiliza
e atualiza o cursor invisvel. Uma linha traada da posio atual do
cursor invisvel at a coordenada do ponto inicial do arco quando
utilizamos ArcTo().
H casos em que no queremos desenhar curvas como arcos, mas sim
curvas com formato livre. Para isso, utilizamos curvas de Bzier, com a funo
PolyBezier(). As curvas de Bzier so criadas com quatro pontos: os pontos das
extremidades da curva e dois pontos de controle, que determinam a forma da
curva. A matemtica por trs do clculo das curvas de Bzier est fora do
alcance desse livro, portanto, veremos apenas como funciona a funo
PolyBezier().
Dica: esse tipo de curva foi criado por um engenheiro francs, Pierre Bzier,
que as utilizou para criar o design de um carro da Renault nos anos 70.
BOOL PolyBezier(
HDC hdc, // identificador do DC
CONST POINT* lppt, // pontos das extremidades e de controle
DWORD cPoints // quantidade de pontos
);

A funo recebe o identificador do DC (HDC hdc), um ponteiro para um


vetor de pontos (CONST POINT* lppt) da curva e a quantidade de pontos do
vetor (DWORD cPoints). A funo retorna um valor diferente de zero quando
bem sucedida ou zero se ocorrer algum erro.
A quantidade de pontos passada no parmetro cPoints deve ser
conforme a equao QP = (3 * QC) + 1, onde QP = quantidade de pontos e QC =
quantidade de curvas. Isso se deve porque, para cada curva, so necessrios
dois pontos de controle e um da extremidade final (a extremidade inicial de
uma curva o mesmo ponto da extremidade final da curva anterior). O + 1
da equao para a extremidade inicial da primeira curva.
Sabendo-se disso, para cada curva extra, precisaremos de trs pontos,
pois a extremidade inicial obtida da curva anterior. Se traarmos apenas uma
curva, sero necessrios quatro pontos.
A Listagem 5.5 exemplifica a criao de uma nica curva de Bzier e de
trs curvas de Bzier consecutivas. As curvas criadas com esse trecho de cdigo

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

136

Programao Windows: C e Win32 API com nfase em Multimdia

so mostradas na Figura 5.4, com seus respectivos pontos de controle e


extremidades, ligados com retas pontilhadas.
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{
// Obtm identificador do DC e preenche PAINTSTRUCT
hDC = BeginPaint(hWnd, &psPaint);
// Caneta j foi criada e selecionada no DC
// Define extremidades
POINT ptUmaCurva[4];
ptUmaCurva[0].x = 290;
ptUmaCurva[1].x = 70 ;
ptUmaCurva[2].x = 190;
ptUmaCurva[3].x = 200;

e pontos de controle da curva


ptUmaCurva[0].y
ptUmaCurva[1].y
ptUmaCurva[2].y
ptUmaCurva[3].y

=
=
=
=

5;
10;
100;
100;

//
//
//
//

extremidade
pt controle
pt controle
extremidade

// Desenha a curva
PolyBezier(hDC, ptUmaCurva, 4);
// Define extremidades e
POINT ptTresCurvas[10];
ptTresCurvas[0].x = 10 ;
ptTresCurvas[1].x = 40 ;
ptTresCurvas[2].x = 50 ;
ptTresCurvas[3].x = 100;
ptTresCurvas[4].x = 140;
ptTresCurvas[5].x = 170;
ptTresCurvas[6].x = 200;
ptTresCurvas[7].x = 220;
ptTresCurvas[8].x = 200;
ptTresCurvas[9].x = 240;

pontos de controle das 3 curvas


ptTresCurvas[0].y
ptTresCurvas[1].y
ptTresCurvas[2].y
ptTresCurvas[3].y
ptTresCurvas[4].y
ptTresCurvas[5].y
ptTresCurvas[6].y
ptTresCurvas[7].y
ptTresCurvas[8].y
ptTresCurvas[9].y

=
=
=
=
=
=
=
=
=
=

100;
30;
130;
100;
75;
90;
200;
180;
140;
100;

//
//
//
//
//
//
//
//
//
//

extremidade
pt controle
pt controle
extremidade
pt controle
pt controle
extremidade
pt controle
pt controle
extremidade

// Desenha as 3 curvas
PolyBezier(hDC, ptTresCurvas, 10);
// Restaura caneta antiga e deleta nova caneta
// Libera DC e valida rea
EndPaint(hWnd, &psPaint);
return(0);
} break;
Listagem 5.5: Criando curvas de Bzier com PolyBezier().

Dica: para que duas curvas de Bzier consecutivas sejam interligadas sem
uma mudana brusca de angulao, certifique-se que o segundo ponto de
controle da curva anterior, sua extremidade final e o primeiro ponto de
controle da curva atual estejam em uma mesma linha (como entre a
primeira e a segunda curva da Figura 4.4).

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 5 Grficos com GDI

137

Figura 5.4: Curvas de Bzier da Listagem 4.4.

Veja o arquivo prog05-3.cpp no CD-ROM, o qual contm o cdigo-fonte


com o programa-exemplo para traar arcos e curvas de Bzier.
Acabamos de aprender como traar linhas retas e curvas, as quais
utilizavam apenas as propriedades da caneta selecionada no DC. A partir de
agora, veremos como desenhar figuras fechadas (retngulos, elipses,
combinao de ambos e polgonos), que utilizam as propriedades do pincel
selecionado no DC para preenchimento e da caneta para contorno da figura.

Desenhando retngulos
O primeiro tipo de figura fechada que veremos o retngulo, que
criado utilizando a funo Rectangle().
BOOL Rectangle(
HDC hdc, // identificador do DC
int nLeftRect, // coordenada x do canto superior esquerdo
int nTopRect, // coordenada y do canto superior esquerdo
int nRightRect, // coordenada x do canto inferior direito
int nBottomRect // coordenada y do canto inferior direito
);

O primeiro parmetro da funo recebe o identificador do DC. Os


parmetros nLeftRect e nTopRect indicam a coordenada (x, y) do canto superior
esquerdo do retngulo. Os parmetros nRightRect e nBottomRect indicam a
coordenada (x, y) do cano inferior direito do retngulo. A funo retorna um
valor diferente de zero quando bem sucedida ou zero se ocorrer algum erro.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

138

Programao Windows: C e Win32 API com nfase em Multimdia

A funo Rectangle() desenha um retngulo com as seguintes


dimenses: altura = (nBottomRect 1) nTopRect e largura = (nRightRect 1)
nLeftRect. Se a caneta utilizada for do tipo PS_NULL, as dimenses do
retngulo diminuiro em 1 pixel na altura e 1 pixel na largura.
Dica: todas as funes que desenham figuras fechadas preenchem o seu
interior com as propriedades do pincel selecionado no DC. Caso queira o
interior das figuras sem preenchimento (transparente), crie um pincel com
(HBRUSH)GetStockObject(NULL_BRUSH). Para descartar o contorno das figuras,
crie uma caneta com o estilo PS_NULL.
Podemos tambm desenhar retngulos com seus cantos arredondados.
A funo RoundRect() realiza esse trabalho.
BOOL RoundRect(
HDC hdc, // identificador do DC
int nLeftRect, // coordenada x do canto superior esquerdo
int nTopRect, // coordenada y do canto superior esquerdo
int nRightRect, // coordenada x do canto inferior direito
int nBottomRect, // coordenada y do canto inferior direito
int nWidth, // largura da elipse
int nHeight // altura da elipse
);

Os cinco primeiros parmetros de RoundRect() so idnticos aos da


funo Rectangle(). Os dois ltimos indicam a largura (int nWidth) e altura (int
nHeight) das elipses que so utilizadas para arredondar os cantos do retngulo.
A funo retorna um valor diferente de zero quando bem sucedida ou zero se
ocorrer algum erro.
Alm dessas duas funes, existe uma terceira, FillRect(), que
utilizada para preencher um retngulo com as propriedades de um pincel (no
necessariamente o que est selecionado no DC). As dimenses do retngulo
preenchido por FillRect() so definidas com as mesmas equaes da funo
Rectangle(); porm, essa funo no desenhar o contorno do retngulo,
dispensando o uso de canetas.
int FillRect(
HDC hDC, // identificador do DC
CONST RECT *lprc // retngulo
HBRUSH hbr // pincel
);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 5 Grficos com GDI

139

A funo recebe o identificador do DC no primeiro parmetro. O


segundo parmetro recebe um ponteiro para uma varivel do tipo RECT, que
contm as coordenadas do retngulo. O terceiro parmetro indica qual pincel
deve ser utilizado para o preenchimento do retngulo. A funo retorna um
valor diferente de zero quando bem sucedida ou zero se ocorrer algum erro.
O uso das trs funes de retngulo demonstrado na Listagem 5.6.
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{
// Obtm identificador do DC e preenche PAINTSTRUCT
hDC = BeginPaint(hWnd, &psPaint);
// Caneta j foi criada e selecionada no DC
// Cria e seleciona novo pincel no DC e salva pincel antigo
HBRUSH hBrush = CreateSolidBrush(RGB(255, 255, 0));
HBRUSH hBrushOld = (HBRUSH)SelectObject(hDC, hBrush);
// Cria pincel hBrush2
HBRUSH hBrush2 = CreateHatchBrush(HS_DIAGCROSS, RGB(0, 0, 255));
// Cria retngulo
RECT rcRect = { WINDOW_WIDTH / 2 - 50 , WINDOW_HEIGHT / 2 - 50,
WINDOW_WIDTH / 2 + 50, WINDOW_HEIGHT / 2 + 50 };
// Preenche retngulo rcRect com pincel hBrush2
FillRect(hDC, &rcRect, hBrush2);
// Desenha retngulo
Rectangle(hDC, 20, 20, 120, 100);
// Desenha retngulo com cantos arredondados
RoundRect(hDC, 200, 150, 250, 200, 20, 20);
// Deleta pincel hBrush2
DeleteObject(hBrush2);
// Restaura pincel antigo e deleta novo pincel
SelectObject(hDC, hBrushOld);
DeleteObject(hBrush);
// Restaura caneta antiga e deleta nova caneta
// Libera DC e valida rea
EndPaint(hWnd, &psPaint);
return(0);
} break;
Listagem 5.6: Desenhando retngulos.

A sada da Listagem 5.6 (que parte do cdigo-fonte do arquivo prog054.cpp) mostrada na Figura 5.5 abaixo.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

140

Programao Windows: C e Win32 API com nfase em Multimdia

Figura 5.5: Desenhando retngulos.

Desenhando elipses
Outro tipo de figura fechada que a GDI pode desenhar so as elipses,
atravs do uso da funo Ellipse(). Quando aprendemos a desenhar arcos,
vimos que para desenh-los era necessrio especificar um retngulo invisvel,
formado pelas extremidades da elipse (Figura 5.3). Essa regra continua valendo
para desenhar elipses, sendo que o centro da elipse o centro do retngulo
especificado na funo.
BOOL Ellipse(
HDC hdc, // identificador do DC
int nLeftRect, // coordenada x do canto superior esquerdo do retngulo
int nTopRect, // coordenada y do canto superior esquerdo do retngulo
int nRightRect, // coordenada x do canto inferior direito do retngulo
int nBottomRect // coordenada y do canto inferior direito do retngulo
);

O primeiro parmetro da funo recebe o identificador do DC. Os


outros quatro parmetros indicam o retngulo (invisvel) formado pelas
extremidades da elipse. A funo retorna um valor diferente de zero quando
bem sucedida ou zero se ocorrer algum erro.
possvel fazer combinaes de arcos e cordas (linhas retas com
extremos pertencentes elipse), criando reas delimitadas pelos mesmos, com
a funo Chord(). Nesse caso, a corda estaria cortando parte da elipse e
descartando-a (veja a Figura 5.6).

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 5 Grficos com GDI

141

Figura 5.6: Combinao de arco e corda (rea cinza).


BOOL Chord(
HDC hdc, // identificador do DC
int nLeftRect, // coordenada x do canto superior esquerdo do retngulo
int nTopRect, // coordenada y do canto superior esquerdo do retngulo
int nRightRect, // coordenada x do canto inferior direito do retngulo
int nBottomRect, // coordenada y do canto inferior direito do retngulo
int nXRadial1, // coordenada x do ponto inicial do arco
int nYRadial1, // coordenada y do ponto inicial do arco
int nXRadial2, // coordenada x do ponto final do arco
int nYRadial2 // coordenada y do ponto final do arco
);

A funo Chord() recebe os mesmo parmetros que a funo Arc() e


possui os mesmos valores de retorno. A diferena entre elas que Chord()
adiciona a corda ao arco e preenche o interior da rea delimitada pelos dois.
Uma variao dessa combinao de arcos e cordas a pizza, muito
utilizada em grficos. Nesse caso, so combinados o arco e duas retas que vo
do centro da elipse at sua borda. A rea delimitada preenchida com o pincel
selecionado no DC. A Figura 5.7 tm as mesmas propriedades da Figura 5.6,
exceto que foi criada utilizando a funo Pie() ao invs de Chord().
BOOL Pie(
HDC hdc, // identificador do DC
int nLeftRect, // coordenada x do canto superior esquerdo do retngulo
int nTopRect, // coordenada y do canto superior esquerdo do retngulo
int nRightRect,
nRightRect, // coordenada x do canto inferior direito do retngulo
int nBottomRect, // coordenada y do canto inferior direito do retngulo
int nXRadial1, // coordenada x do ponto inicial do arco
int nYRadial1, // coordenada y do ponto inicial do arco
int nXRadial2, // coordenada x do ponto final do arco
int nYRadial2 // coordenada y do ponto final do arco
);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

142

Programao Windows: C e Win32 API com nfase em Multimdia

Figura 5.7: Uma pizza.

Note que apenas o nome da funo muda, em relao Chord(). A


diferena do resultado do uso de Pie() e Chord() pode ser comparado entre as
Figuras 5.6 e 5.7.
Veja o arquivo prog05-5.cpp no CD-ROM, o qual contm o cdigo-fonte
com o programa-exemplo para traar figuras discutidas nessa seo, inclusive
uma pizza no formato do Pac-Man :-).

Desenhando polgonos
Para concluir a seo de figuras fechadas, vamos aprender como
desenhar polgonos com o uso da funo Polygon(). Polgonos so figuras
formadas por um conjunto de pontos interligados com retas consecutivas
(vrtices).
BOOL Polygon(
HDC hdc, // identificador do DC
CONST POINT *lpPoints, // vrtices do poligono
int nCount // quantidade de vrtices do polgono
);

A funo recebe o identificador do DC no primeiro parmetro. O


segundo parmetro, CONST POINT *lpPoints, recebe um ponteiro para um vetor
do tipo POINT, que contm os pontos dos vrtices do polgono. O ltimo
parmetro recebe a quantidade de pontos que formam o polgono, que deve
ser no mnimo dois pontos para criar-se um vrtice (porm, para formar uma
figura fechada, deve haver pelo menos trs pontos). A funo retorna um valor
diferente de zero se no ocorrer erros, ou zero, caso contrrio.
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 5 Grficos com GDI

143

Nota: Polygon() traa uma reta do ltimo vrtice at o primeiro, fechando


automaticamente o polgono.
Existem dois modos de preenchimento para os polgonos, quando
esses possuem vrtices que cruzam a rea interna do polgono: modo alternado
e completo. No modo alternado, o polgono comea a ser preenchido da borda
at encontrar um vrtice; desse vrtice at o prximo, o polgono no
preenchido, no prximo vrtice, ele preenchido, e assim por diante. No
modo completo, todas as reas so preenchidas.
Os

modos
SetPolyFillMode():

de

preenchimento

so

definidos

pela

funo

int SetPolyFillMode(
HDC hdc, // identificador do DC
int iPolyFillMode // modo de preenchimento
);

A funo recebe o identificador do DC no primeiro parmetro. O


segundo parmetro pode receber os valores ALTERNATE (modo alternado
padro da GDI) ou WINDING (modo completo). O retorno da funo o valor
do modo de preenchimento anterior ou zero em caso de erro.
A Figura 5.8 mostra a execuo do programa-exemplo prog05-6.cpp que
encontra-se no CD-ROM. O programa cria um vetor POINT com cinco
elementos, que definem os pontos de uma estrela, desenha o polgono com o
preenchimento padro (alternado) e em seguida modifica a posio do
polgono e o modo de preenchimento para modo completo, para desenh-lo
novamente.

Inverso de cores e preenchimento de reas


Existe uma funo da GDI, InvertRect(), que faz a inverso das cores
de determinado retngulo (o efeito negativo de fotos), realizando uma
operao not para cada ponto do retngulo.
BOOL InvertRect(
HDC hDC, // identificador do DC
CONST RECT *lprc // retngulo
);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

144

Programao Windows: C e Win32 API com nfase em Multimdia

Figura 5.8: Polgono no formato de estrela.

O primeiro parmetro da funo o identificador do DC. O segundo


parmetro recebe um ponteiro para uma varivel RECT, que contm as
coordenadas da rea do retngulo que ter as cores invertidas. A funo
retorna um valor diferente de zero se no ocorrer erros, ou zero, caso
contrrio.
No tpico Desenhando retngulos, vimos que a funo FillRect()
utilizada para o preenchimento de reas retangulares. Porm, como podemos
preencher reas no-retangulares, como, por exemplo, reas delimitadas por
linhas retas e curvas de Bzier?
Para tal ao, utilizamos a funo ExtFloodFill(), parecida com o
balde de tinta de diversos softwares grficos. A funo pode fazer o
preenchimento de duas maneiras: preenchendo reas que so definidas por
uma cor-limite (ou seja, a funo continua preenchendo reas at que seja
encontrado um ponto, uma reta ou curva com a cor-limite) ou preenchendo
reas de uma mesma cor (deixando de preencher reas de cores diferentes).
Em ambos os casos, a funo utiliza o pincel selecionado no DC.
BOOL ExtFloodFill(
ExtFloodFill(
HDC hdc, // identificador do DC
int nXStart, // coordenada x onde comea o preenchimento
int nYStart, // coordenada y onde comea o preenchimento
COLORREF crColor, // cor de preenchimento
UINT fuFillType // tipo de preenchimento
);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 5 Grficos com GDI

145

A funo recebe o identificador do DC no primeiro parmetro. Os


segundo e terceiro parmetros (nXStart e nYStart, respectivamente) recebem a
coordenada (x, y) de onde a funo deve comear o preenchimento. O
parmetro COLORREF crColor depende do valor passado em UINT fuFillType:
caso fuFillType receba FLOODFILLBORDER, a rea a ser preenchida ser limitada
pela cor indicada em crColor. fuFillType tambm pode receber o valor
FLOODFILLSURFACE; nesse caso, o preenchimento ser feito apenas nas reas que
estiverem com a cor indica em crColor.
A funo retorna um valor diferente de zero se no ocorrer erros, ou
zero, caso contrrio. A funo tambm retorna zero nos seguintes casos:
- o ponto da coordenada (x, y) especificada da mesma cor que a
indicada em crColor, quando fuFillType recebe FLOODFILLBORDER;
- o ponto da coordenada (x, y) especificada no possui a mesma cor
que a indicada em crColor, quando fuFillType recebe
FLOODFILLSURFACE;
- o ponto da coordenada (x, y) especificada estiver fora da rea
cliente.
Veja o arquivo prog05-7.cpp no CD-ROM, o qual contm o cdigo-fonte
com o programa-exemplo para inverter cores de reas retangulares e o uso da
funo ExtFloodFill() para preenchimento de reas.

Figura 5.9: Invertendo cores e preenchendo reas.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

146

Programao Windows: C e Win32 API com nfase em Multimdia

A Figura 5.9 mostra a execuo do programa. O retngulo do


programa teve sua cor original (roxa) invertida, tornando-se verde. Foi
utilizado a funo ExtFloodFill() para preencher reas de cor branca a partir do
ponto (100, 100). As reas brancas foram preenchidas com um pincel azul e
com linhas diagonais cruzadas.

Um simples programa de desenho


O arquivo prog05-8.cpp incluso no CD-ROM contm o cdigo-fonte de
um pequeno programa de desenho (se que pode ser considerado assim),
demonstrando como desenhar figuras atravs da interao do usurio (Figura
5.10).

Figura 5.10: Um simples programa de desenho.

O programa bem simples e desenha apenas retas, retngulos e elipses.


Para torn-lo um verdadeiro programa de desenho, deveramos dar suporte a
mais figuras, opes para configurar as canetas e pincis, criar uma boa
interface para o usurio (o uso de menus seria uma boa idia), traar a sombra
da figura que est sendo criada (para auxiliar o usurio na criao da mesma),
entre outras implementaes.
O truque do programa processar as mensagens WM_LBUTTONDOWN e
WM_LBUTTONUP. Quando o boto esquerdo do mouse pressionado,
armazenamos a coordenada (x, y) do cursor na varivel POINT ptMouseInicio. O
usurio arrasta o mouse at certo lugar, e para desenhar a figura, solta o boto
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 5 Grficos com GDI

147

esquerdo do mouse. Processamos ento a mensagem WM_LBUTTONUP, onde


obtemos a coordenada (x, y) atual do cursor, sendo esta a coordenada final,
armazenada na varivel POINT ptMouseFim. Ainda na mensagem WM_LBUTTONUP,
verificamos qual figura est selecionada para desenhar e chamamos sua
respectiva funo. Essa a lgica utilizada para a criao de softwares grficos.
Esse programa-exemplo tem um problema grave, pois ele no salva o
contedo da rea cliente, ou seja, se alguma janela sobrepor o programa, a rea
sobreposta ser perdida. Isso acontece porque todos os desenhos so feitos na
mensagem WM_LBUTTONUP, e no na WM_PAINT (que seria a maneira correta). Esse
problema eliminado utilizando um DC de memria, assunto do prximo
captulo, onde estudaremos o uso de bitmaps.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

148

Programao Windows: C e Win32 API com nfase em Multimdia

Captulo 6 Bitmaps
Entre os objetos GDI citados no captulo 4, um deles foi HBITMAP, que
um objeto do tipo bitmap. Nesse captulo, estaremos estudando como utilizar
esse objeto, carregando e mostrando imagens armazenadas em arquivos *.bmp
nos nossos programas.

O que so bitmaps?
Podemos definir bitmaps como um vetor de (largura * altura) bits,
onde uma certa quantidade de bits representa um ponto/cor que compe a
figura. Atualmente, existem dezenas de mtodos para armazenar uma figura no
computador, resultando em diferentes tipos de arquivos, como, por exemplo,
imagens do tipo JPEG ou GIF, famosos pela utilizao em pginas HTML.
Cada tipo de arquivo de imagem possui um cabealho, um mtodo de
armazenamento dos bits e compresso de dados, tornando-se invivel o estudo
de todos os tipos de imagem nesse livro. Veremos como utilizar apenas o tipo
nativo do Windows (bitmap, arquivos com extenso .bmp ou .dib).
Dica: voc pode verificar a estrutura de outros tipos de arquivos de
imagens consultando o livro Encyclopedia of Graphics File Formats (Murray,
James D. e Vanryper, William editora OReilly) ou pela Internet existe
um timo site especificamente sobre estrutura de arquivos em
http://www.myfileformats.com.
Os bitmaps, quanto quantidade de cores, podem ser classificados
conforme a Tabela 6.1
Bitmap de n-bit
1
4
8
16
24
32

Quantidade mxima de cores


2 (21)
16 (24)
256 (28)
65.536 (216)
16.777.216 (224)
4.294.967.296 (232)

Tabela 6.1: Classificao de bitmaps quanto quantidade de cor.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 6 Bitmaps

149

O que significam todos esses nmeros? O lado esquerdo da tabela


indica a quantidade de bits que um bitmap utiliza para representar a cor de
cada pixel, atravs da combinao de valores dos seus bits. O lado direito
informa a quantidade mxima de cores que possvel obter atravs dessa
combinao.
Bitmaps de at 8-bit necessitam de uma tabela de cores, tambm
conhecida por paleta de cores. Para um bitmap de 8-bit, visto que o mesmo
pode ter at 256 cores diferentes, podemos imaginar um vetor do tipo char de
256 posies, onde cada posio no vetor equivale uma cor. O vetor pode ser
do tipo char pois um char ocupa 1 byte de memria (ou 8 bits), ou seja, cada
pixel de um bitmap de 8-bit representado por um byte. A Listagem 6.1
contm um misto de pseudo-cdigo com linguagem C demonstrando como
uma imagem de 8-bit poderia utilizar uma paleta de cores:
/*
Cria Paleta de Cores com as seguintes configuraes / ndices:
- cPaletaDeCores[0] = preto
- cPaletaDeCores[1 84] = tons de vermelho
- cPaletadeCores[85 170] = tons de verde
- cPaletaDeCores[171 254] = tons de azul
- cPaletaDeCores[255] = branco
*/
char cPaletaDeCores[256];
for(int i = 0; i < 256; i++)
cPaletaDeCores[i] = i;
// Cria um emoticon branco com fundo preto
char cRosto[] = {
0, 0 , 255, 255, 255, 0 , 0,
0, 255, 255, 255, 255, 255, 0,
0, 255, 0 , 255, 0 , 255, 0,
0, 255, 255, 255, 255, 255, 0,
0, 255, 255, 0 , 255, 255, 0,
0, 255, 255, 255, 255, 255, 0,
0, 255, 255, 255, 255, 255, 0,
0, 255, 0 , 0 , 0 , 255, 0,
0, 255, 255, 255, 255, 255, 0,
0, 0 , 255, 255, 255, 0, 0
};
// Plota os pixels do emoticon na tela
desenha_na_tela(cRosto);
Listagem 6.1: Pseudocdigo de paleta de cores.

Bitmaps de 16-bit (65 mil cores) ou mais no necessitam de uma paleta


de cores. No caso de bitmaps de 16-bit, existem duas maneiras diferentes que
os bits da imagem podem ser armazenados: 5-5-5 ou 5-6-5. O bitmap 16-bit 5-

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

150

Programao Windows: C e Win32 API com nfase em Multimdia

5-5 um bitmap cujos 5 primeiros bits (0 4) armazenam a intensidade da cor


azul, os bits 5 - 9 armazenam a intensidade da cor verde e os bits 10 14
armazenam a intensidade da cor vermelha, gastando assim um bit que no
utilizado (bit 15). O bitmap 16-bit 5-6-5 um bitmap que utiliza 6 bits para a
cor verde (a escolha de um bit a mais para a cor verde devido aos olhos
humanos serem mais sensveis essa cor) e 5 para as cores azul e vermelha.
Bitmaps de 24-bit utilizam 8 bits para armazenar a intensidade de cada cor
(azul, verde, vermelha), enquanto bitmaps de 32-bit podem utilizar 8 bits para
armazenar a intensidade de cada cor e os ltimos 8 bits para o canal alfa
(transparncia).
Para representar a cor vermelha num bitmap de 16-bit (5-5-5), os 16
bits seriam: 0-11111-00000-00000 (ou 0x7C00 em hexadecimal). Num bitmap
16-bit (5-6-5), a cor vermelha seria representada da seguinte maneira: 11111000000-00000 (ou 0xF800 em hexadecimal). A cor azul num bitmap 24-bit
ficaria: 00000000-00000000-11111111 (ou 0x0000FF em hexadecimal). Veja
que a notao das cores (24-bit) em hexadecimal semelhante utilizada na
codificao de cores em HTML.

Bitmaps no Windows: DDB e DIB


Quando estamos utilizando bitmaps em nossos programas, necessrio
o conhecimento de dois tipos de bitmap definidos pela Microsoft: o devicedependent bitmap (DDB) e o device-independent bitmap (DIB). H certas diferenas
entre essas definies e seus mtodos de trabalho com imagens.
Um DDB um objeto GDI (objeto HBITMAP), sendo possvel selecionar
o mesmo no DC que estamos utilizando. Isso significa que um DDB
compatvel com o DC onde est selecionado, isto , ele fica dependente das
configuraes do DC. Tambm podemos utilizar funes GDI para mostrar os
bitmaps na tela, assim como fazemos com qualquer outro objeto GDI.
Porm, os DDBs tm suas limitaes: no podemos ter acesso direto
aos bits dos bitmaps (til para manipulao e processamento de imagens) e h
um limite de tamanho que um DDB pode suportar (16MB para Windows
95/98 e 48MB para Windows NT/2000). Para isso, a Microsoft criou os
DIBs.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 6 Bitmaps

151

Conforme o nome diz, um DIB um bitmap que independe de um


dispositivo, no havendo restries quanto cores ou tamanho. Com o uso de
um DIB, possvel tambm acessar diretamente os bits da imagem e manipullas, ao contrrio de um DDB.
Diferente dos bitmaps DDB, um DIB no um objeto GDI, mas sim,
uma descrio de um bitmap; assim, no possvel selecionar um DIB no
DC e no h funes que mostrem esse tipo de bitmap na tela. O que deve ser
feito, nesse caso, uma converso DIB para DDB, usando funes GDI
especiais. Devido essa converso, mostrar DIBs na tela um processo mais
lento que utilizar diretamente um bitmap compatvel com o DC.
Nota: estudaremos o uso de bitmaps DDB, enquanto o DIB no ser
discutido. Ao invs, iremos ver um outro tipo de bitmap, DIB Section, um
hbrido do DDB e DIB, o qual une vantagens de ambos (velocidade e
objeto GDI de um DDB com o acesso direto aos bits e a no-restrio
quanto ao tamanho de imagem de um DIB).

Carregando bitmaps
Em nossos programas, possvel utilizar imagens armazenadas em
disco (arquivos *.bmp) ou imagens de recursos (conforme visto no captulo 3),
armazenadas no final do arquivo executvel. Carregamos bitmaps atravs da
funo LoadImage().
HANDLE LoadImage(
HINSTANCE hinst, // identificador da instncia
LPCTSTR lpszName, // imagem a ser carregada
UINT uType, // tipo de imagem
int cxDesired, // largura desejada
int cyDesired, // altura desejada
UINT fuLoad // opes de carregamento
);

Dica: essa funo tambm pode ser utilizada para carregar cones e
cursores, pois ela tem o retorno do tipo HANDLE genrico (sendo necessrio
fazer type-casting para o tipo de imagem que estamos carregando).
O primeiro parmetro da funo LoadImage() recebe o identificador da
instncia do programa, se a imagem for carregada de um recurso, ou NULL
quando for carregada de um arquivo em disco. Quando estamos carregando a

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

152

Programao Windows: C e Win32 API com nfase em Multimdia

imagem de um recurso, o segundo parmetro recebe o ID do mesmo, com o


uso da macro MAKEINTRESOURCE(). No caso de uma imagem em disco, o segundo
parmetro recebe o local e nome de arquivo da imagem. O parmetro UINT
uType indica o tipo de imagem que estamos carregando: IMAGE_BITMAP (bitmap),
IMAGE_CURSOR (cursor) ou IMAGE_ICON (cone).
Os parmetros cxDesired e cyDesired indicam o tamanho (largura e
altura) da imagem que est sendo carregada. No caso de imagem de recurso,
podemos passar zero para ambos os parmetros; assim, a funo
automaticamente obtm a largura e altura da imagem a ser carregada.
O ltimo parmetro recebe opes para carregar a imagem. O valor
padro desse parmetro LR_DEFAULTCOLOR. Quando estamos carregando uma
imagem do disco, passamos o valor LR_LOADFROMFILE para esse parmetro. O
valor LR_CREATEDIBSECTION passado no ltimo parmetro quando queremos
que a funo retorne um DIB Section ao invs de um DDB. A funo retorna
o identificador da nova imagem carregada ou NULL em caso de erro.
Para carregar uma imagem de um recurso, podemos utilizar o seguinte
trecho de cdigo (Listagem 6.2):
// Cria um identificador para o bitmap
HBITMAP hBmp = NULL;
// Carrega o bitmap do recurso, retornando um identificador HBITMAP.
// Note o type-casting feito no retorno da funo LoadImage()
// Os parmetros cxDesired e cyDesired recebem zero, ou seja, a funo
// obtm esses valores automaticamente da imagem no recurso.
hBmp
=
(HBITMAP)
LoadImage(hInstance,
MAKEINTRESOURCE(IDB_MEUBITMAP),
IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
Listagem 6.2: Carregar bitmap de recurso.

Nesse trecho de cdigo, passamos a varivel hInstance para LoadImage(),


a mesma do parmetro da funo WinMain(), e informamos o ID do recurso da
imagem (IDB_MEUBITMAP). Como necessrio informar todos os parmetros,
passamos LR_DEFAULTCOLOR para o ltimo, que o valor padro de UINT fuLoad.
A Listagem 6.3 demonstra como carregar um arquivo de imagem
(imagem.bmp) de tamanho 100x100 pixels armazenada em disco, retornando um
DIB Section ao invs de um DDB (retorno padro).
// Cria um identificador para o bitmap
HBITMAP hBmp = NULL;

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 6 Bitmaps

153

// Carrega o bitmap do disco (LR_LOADFROMFILE),


// retornando um DIB Section (LR_CREATEDIBSECTION).
// Note o type-casting feito no retorno da funo LoadImage()
hBmp = (HBITMAP) LoadImage(NULL, imagem.bmp, IMAGE_BITMAP,
LR_CREATEDIBSECTION | LR_LOADFROMFILE);
Listagem 6.3: Carregar bitmap do disco.

100,

100,

Repare que, no caso de imagem em disco, passamos NULL para o


primeiro parmetro de LoadImage(), informamos o caminho e nome do arquivo
.bmp no segundo parmetro e o valor LR_LOADFROMFILE no parmetro de opes
de carregamento (fuLoad).

Obtendo informaes de um bitmap


Conforme j visto, a funo GetObject() obtm informaes de objetos
GDI (informado no primeiro parmetro da funo) e as salva na varivel
enviada no terceiro parmetro.
No caso de objetos HBITMAP, obtemos suas informaes com o uso da
estrutura BITMAP, chamando GetObject() da seguinte maneira (Listagem 6.4):
HBITMAP hBmp;
BITMAP bmp;
// ...
// Preenche estrutura BITMAP com os dados do objeto GDI HBITMAP
GetObject((HBITMAP)hBmp, sizeof(BITMAP), &bmp);
Listagem 6.4: Obtendo informaes de um bitmap.
typedef struct tagBITMAP {
LONG bmType;
bmType;
LONG bmWidth;
bmWidth;
LONG bmHeight;
bmHeight;
LONG bmWidthBytes;
bmWidthBytes;
WORD bmPlanes
bmPlanes;
anes;
WORD bmBitsPixel;
bmBitsPixel;
LPVOID bmBits;
bmBits;
} BITMAP, *PBITMAP;

O membro bmType indica o tipo do bitmap, e deve ser zero. bmWidth e


armazenam a largura e altura do bitmap, respectivamente.
bmWidthBytes indica a quantidade de bytes em cada linha da imagem. Esse valor
pode ser calculado pela equao bmWidthBytes = (bmBitsPixel / 8) * bmWidth.
bmPlanes indica a quantidade de camadas para as cores do bitmap, e
normalmente recebe valor 1. O membro bmBitsPixel especifica quantos bits
bmHeight

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

154

Programao Windows: C e Win32 API com nfase em Multimdia

devem ser utilizados para representar a cor de um ponto. bmBits um ponteiro


para os bits do bitmap, porm, como no temos acesso direto aos bits de um
bitmap DDB, esse valor zero. No caso de bitmaps DIB Section, usamos esse
ponteiro para acessar e manipular os bits do bitmap.

DC de memria
Antes de aprendermos como mostrar um bitmap na rea cliente de um
programa, devemos saber como criar um DC de memria, que auxilia essa
operao.
Um DC de memria pode ser utilizado em trs ocasies principais:
quando no queremos que as modificaes do DC de vdeo sejam passadas
diretamente para a tela; quando precisamos salvar o contedo do DC de vdeo
(problema que surgiu no programa prog05-8.cpp); ou quando vamos mostrar um
bitmap na tela (o objetivo desse captulo). Nessa ltima ocasio, obrigatrio o
uso de um DC de memria, pois no h funes da Win32 API que mostrem
diretamente um bitmap na tela.
O DC de memria trabalha como o DC de vdeo podemos definir os
objetos GDI que esto selecionados nele, suas propriedades, etc. Mas,
conforme o nome diz, um DC de memria s existe na memria; para que
possamos mostrar o seu contedo, devemos copiar o mesmo para o DC de
vdeo (explicado mais adiante).
Dica: um DC de memria costuma ser chamado tambm como um DC
off-screen, devido ao fato que suas operaes e seu contedo no so
mostrados diretamente no vdeo.
A funo CreateCompatibleDC() utilizada para criar um DC de
memria compatvel com o dispositivo especificado no seu parmetro,
conforme o prottipo abaixo:
HDC CreateCompatibleDC(
HDC hdc // identificador do DC
);

Se o parmetro hdc receber NULL, a funo cria um DC de memria


compatvel com as configuraes atuais de vdeo onde o programa est sendo

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 6 Bitmaps

155

exibido. A funo retorna o identificador do novo DC de memria ou NULL no


caso de erro.
Quando esse DC criado, sua altura e largura, por padro, de um
pixel monocromtico cada. Antes de us-lo para desenhar figuras, nosso
programa deve selecionar nele um bitmap compatvel com o DC de vdeo, que
indica o tamanho correto do DC de memria e tambm sua configurao de
cor.
A criao de um bitmap compatvel com o DC de vdeo feita atravs
da funo CreateCompatibleBitmap().
Nota: um bitmap compatvel criado com CreateCompatibleBitmap()
utilizado quando queremos executar operaes de desenho no modo offscreen ou para salvar o contedo do DC de vdeo. Quando estamos criando
um DC de memria para mostrar um bitmap, podemos selecionar o
identificador do bitmap retornado pela funo LoadImage() no DC de
memria, configurando-o automaticamente.
HBITMAP CreateCompatibleBitmap(
HDC hdc, // identificador do DC
int nWidth, // largura do bitmap, em pixels
int nHeight // altura do bitmap, em pixels
);

A funo recebe em HDC hdc o identificador do DC de vdeo, cujo


bitmap ser compatvel. Os parmetros int nWidth e int nHeight indicam a
largura e a altura do bitmap, respectivamente. Se no houver erros, a funo
retorna o identificador de um bitmap compatvel (DDB); caso contrrio, o
retorno NULL.
Nota: se passarmos o identificador do DC de memria para o primeiro
parmetro de CreateCompatibleBitmap(), o retorno da mesma ser um
bitmap monocromtico, pois o DC de memria monocromtico (ou seja,
o bitmap ser compatvel com o DC de memria).
Quando o bitmap criado por essa funo no mais utilizado, devemos
delet-lo com a funo DeleteObject(). Tambm devemos deletar o DC de
memria quando o mesmo no tiver mais utilidade, usando a funo
DeleteDC().

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

156

Programao Windows: C e Win32 API com nfase em Multimdia

BOOL DeleteDC(
HDC hdc // identificador do DC
);

A funo recebe o identificador do DC que ser deletado e retorna um


valor diferente de zero se a operao ocorreu normalmente ou zero em caso de
erro.
Nota: no devemos deletar um DC criado com a funo GetDC(); ao invs
disso, devemos liberar o mesmo com ReleaseDC().
A Listagem 6.5 mostra os passos para criar e configurar um DC de
memria e um bitmap compatvel.
HDC hDC = NULL; // DC de vdeo
HDC hMemDC = NULL; // DC de memria
HBITMAP hBmp = NULL; // Bitmap compatvel
HBITMAP hBmpOld = NULL; // Salva bitmap anterior
// ...
// Obtm identificador do DC de vdeo
hDC = GetDC(hWnd);
// Cria DC de memria
hMemDC = CreateCompatibleDC(hDC);
// Cria bitmap compatvel com DC de vdeo
hBmp = CreateCompatibleBitmap(hDC, WINDOW_WIDTH, WINDOW_HEIGHT);
// Seleciona bitmap no DC de vdeo e salva bitmap anterior
// Com isso, o DC de memria configurado para ter a largura, a altura e
// a cor do bitmap selecionado nele, pois ele inicialmente criado como
// um DC de tamanho 1x1 monocromtico
hBmpOld = (HBITMAP)SelectObject(hMemDC, hBmp);
//
// Chama funes para desenhar no DC de memria
//
// Restaura bitmap anterior e deleta objeto GDI HBITMAP
SelectObject(hMemDC, hBmpOld);
DeleteObject(hBmp);
// Deleta DC de memria
DeleteDC(hMemDC);
// Libera DC de vdeo
ReleaseDC(hDC);
// ...
Listagem 6.5: Criando um DC de memria.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 6 Bitmaps

157

DC particular de um programa
At agora, estvamos trabalhando com um DC de vdeo que tinha sua
memria compartilhada com o sistema e os programas em execuo. Para
programas que usam operaes de desenho intensivamente (como programas
grficos e jogos), o compartilhamento da memria do DC de vdeo no
vivel, sendo recomendado o uso de um DC com sua memria restrita
unicamente para o programa.
O uso de um DC particular extremamente simples, sendo necessrio
informar apenas o valor CS_OWNDC no membro style da estrutura WNDCLASSEX
(localizado dentro da WinMain()). Com isso, o programa j ter uma memria
reservada para o seu DC. Ainda, no necessrio liberar ou deletar o DC do
programa (como fazemos com um DC compartilhado), pois o mesmo
automaticamente liberado quando o programa finalizado.

Mostrando bitmaps
Agora que j aprendemos que para mostrar um bitmap na tela
necessrio o uso de um DC de memria, vamos ver como podemos visualizar
um bitmap.
Para isso, o que fazemos, na verdade, no mostrar o bitmap, mas sim
copiar o contedo do DC de memria para o DC de vdeo. Dessa maneira, se
um bitmap estiver selecionado no DC de memria, o mesmo ser mostrado na
tela quando houver a cpia de contedo entre os DCs (por isso criamos um
identificador do tipo HBITMAP e o selecionamos no DC de memria).
A cpia do contedo de um DC para outro pode ser feito com duas
funes: BitBlt() e StretchBlt(). O nome da funo BitBlt() (pronunciado bit
blit) vem de BIT BLock Transfer (transferncia de um bloco de bits), que
exatamente o que a funo faz. A funo StretchBlt() faz a transferncia de
um bloco de bits ajustando o tamanho da imagem de acordo com o retngulo
de destino especificado na funo, podendo alargar (se o retngulo de destino
for maior que o de origem) ou comprimir (retngulo de destino menor que de
origem) a imagem. Essa funo ainda pode inverter a visualizao da imagem
(como um espelho) tanto na horizontal quanto na vertical (veja prximo
tpico).

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

158

Programao Windows: C e Win32 API com nfase em Multimdia

Dica: para salvar o contedo do DC de vdeo, copiamos o mesmo para um


DC de memria. Quando a restaurao do DC de vdeo for necessria,
basta copiar o contedo do DC de memria de volta para o de vdeo.
BOOL BitBlt(
HDC hdcDest, // identificador do DC de destino
int nXDest, // x do canto superior esquerdo do retngulo de destino
int nYDest, // y do canto superior esquerdo do retngulo de destino
int nWidth, // largura do retngulo de destino (canto inferior direito)
int nHeight, // altura do retngulo de destino (canto inferior direito)
HDC hdcSrc, // identificador do DC de origem
int nXSrc, // x do canto superior esquerdo do retngulo de origem
int nYSrc, // y do canto superior esquerdo do retngulo de origem
DWORD dwRop // modo de transferncia
);

O primeiro parmetro de BitBlt() indica o DC de destino (em qual DC


o contedo de outro ser copiado). Os quatro prximos parmetros indicam
trs informaes: a posio (nXDest e nYDest) e tamanho (nWidth e nHeight) do
retngulo onde o contedo do DC de origem ser copiado no DC de destino e
tambm o tamanho do retngulo (nWidth e nHeight) que ser transferido do DC
de origem (esse informado no sexto parmetro, hdcSrc). Os parmetros nXSrc
e nYSrc indicam o ponto (x, y) de onde o contedo do DC de origem comear
a ser transferido. O ltimo parmetro deve receber um dos valores da Tabela
6.2, que indicam o modo como as cores do DC de origem sero misturados ao
DC de destino. A funo retorna um valor diferente de zero quando no
ocorrer erros, ou zero, caso contrrio.
Valor
BLACKNESS
MERGECOPY

MERGEPAINT

NOTSRCCOPY
NOTSRCERASE

PATCOPY

Descrio
Preenche o retngulo de destino com a cor
preta.
Combina as cores do retngulo de origem
com o pincl selecionado no DC de destino
usando a operao AND.
Combina as cores inversas do retngulo de
origem com as cores do retngulo de destino
usando a operao OR.
Copia as cores inversas do retngulo de
origem para o destino.
Combina as cores dos retngulos de origem e
destino usando a operao OR e inverte a
cor resultante.
Copia o pincel selecionado no DC de destino
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 6 Bitmaps

PATINVERT

PATPAINT

SRCAND
SRCCOPY
SRCERASE

SRCINVERT
SRCPAINT
WHITENESS

159

no bitmap de destino.
Combina as cores do pincel selecionado no
DC de destino com as cores do retngulo de
destino usando a operao XOR.
Combina as cores do pincel selecionado no
DC de destino com as cores inversas do
retngulo de origem usando a operao OR.
O resultado dessa operao combinada
com as cores do retngulo de destino usando
a operao OR.
Combina as cores dos retngulos de origem e
destino usando a operao AND.
Copia o retngulo de origem diretamente no
retngulo de destino.
Combina as cores inversas do retngulo de
destino com as cores do retngulo de origem
usando a operao AND.
Combina as cores dos retngulos de origem e
destino usando a operao XOR.
Combina as cores dos retngulos de origem e
destino usando a operao OR.
Preenche o retngulo de destino com a cor
branca.
Tabela 6.2: Modos de transferncia (combinao de cores entre os DCs).

BOOL StretchBlt(
HDC hdcDest, // identificador do DC de destino
int nXOriginDest, // x do canto superior esquerdo do retngulo de destino
int nYOriginDest, // y do canto superior esquerdo do retngulo de destino
int nWidthDest, // largura do retngulo de destino (canto inferior
direito)
int nHeightDest, // altura do retngulo de destino (canto inferior
direito)
HDC hdcSrc, // identificador do DC de origem
int nXOriginSrc,
nXOriginSrc, // x do canto superior esquerdo do retngulo de origem
int nYOriginSrc, // y do canto superior esquerdo do retngulo de origem
int nWidthSrc, // largura do retngulo de origem (canto inferior direito)
int nHeightSrc, // altura do retngulo de origem (canto inferior direito)
DWORD dwRop // modo de transferncia
);

Veja que a funo StretchBlt() recebe parmetros parecidos com os da


funo BitBlt() (e tem valores de retorno igual ao dessa funo). A diferena
o acrscimo dos parmetros int nWidthSrc e int nHeightSrc, que indicam,
respectivamente, a largura e a altura do retngulo do DC de origem que ser
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

160

Programao Windows: C e Win32 API com nfase em Multimdia

copiado para o DC de destino. Dessa maneira, os parmetros int nWidthDest e


int nHeightDest passam a indicar apenas o tamanho do retngulo do DC de
destino, diferentemente da funo BitBlt().
A Listagem 6.6 demonstra um exemplo de como utilizar ambas as
funes, mostrando um bitmap normalmente com BitBlt() e StretchBlt() e o
mesmo bitmap redimensionado para o tamanho do retngulo de origem (com
StretchBlt()). A execuo desse trecho de cdigo mostrado na Figura 6.1.
// Verifica qual foi a mensagem enviada
switch(uMsg)
{
case WM_CREATE: // Janela foi criada
{
// Cria DC de memria (hMemDC global)
hDC = GetDC(hWnd);
hMemDC = CreateCompatibleDC(hDC);
// Cria / carrega bitmap do arquivo prog06-1.bmp (hBmp global)
hBmp = (HBITMAP)LoadImage(NULL, " prog06-1.bmp", IMAGE_BITMAP, 160, 120,
LR_LOADFROMFILE);
// Seleciona bitmap no DC de memria (configura DC de memria)
SelectObject(hMemDC, hBmp);
// Retorna 0, significando que a mensagem foi processada corretamente
return(0);
} break;
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{
// Obtm DC de vdeo
hDC = BeginPaint(hWnd, &psPaint);
// Faz transferncia de bits entre os DCs de memria e vdeo
BitBlt(hDC, 0, 0, 160, 120, hMemDC, 0, 0, SRCCOPY);
// Faz transferncia de bits entre os DCs de memria e vdeo
StretchBlt(hDC, 160, 0, 160, 120, hMemDC, 0, 0, 160, 120, SRCCOPY);
// Faz transferncia de bits entre os DCs de memria e vdeo
// (alargando a figura)
StretchBlt(hDC, 0, 120, 240, 90, hMemDC, 0, 0, 160, 120, SRCCOPY);
// Faz transferncia de bits entre os DCs de memria e vdeo
// (comprimindo a figura)
StretchBlt(hDC, 240, 120, 80, 60, hMemDC, 0, 0, 160, 120, SRCCOPY);
// Libera DC de vdeo
EndPaint(hWnd, &psPaint);
return(0);
} break;

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 6 Bitmaps

161

case WM_CLOSE: // Janela foi fechada


{
// Deleta bitmap
DeleteObject(SelectObject(hMemDC, hBmp));
// Deleta DC de memria
DeleteDC(hMemDC);
// Destri a janela
DestroyWindow(hWnd);
return(0);
} break;
// ...
}
Listagem 6.6: Usando BitBlt() e StretchBlt().

Dica: a listagem completa do cdigo-fonte do exemplo de como mostrar


bitmaps na tela encontra-se no arquivo prog06-1.cpp do CD-ROM. Nesse
arquivo tambm foi inserido o cdigo para mostrar bitmaps invertidos (que
ser discutido a seguir). Nesse programa, o clique do boto esquerdo do
mouse modifica um flag que indica se os bitmaps devem ser invertidos ou
no.

Figura 6.1: Mostrando imagens com BitBlt() e StretchBlt().

Mostrando bitmaps invertidos


A funo StretchBlt() tambm pode inverter bitmaps, fazendo um
espelhamento da imagem. Para que a funo inverta uma imagem, devemos

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

162

Programao Windows: C e Win32 API com nfase em Multimdia

informar um valor negativo para o parmetro nWidthDest (espelhamento na


horizontal) e/ou nHeightDest (espelhamento na vertical).
Como j visto, os parmetros nXOriginDest, nYOriginDest, nWidthDest e
da funo StretchBlt() servem para indicar o retngulo de destino
da imagem; porm, quando nWidthDest e/ou nHeightDest recebem valores
negativos, a imagem mostrada invertida (na horizontal, vertical ou ambos os
sentidos, dependendo de quais parmetros receberem valores negativos).
nHeightDest

A Listagem 6.7 contm um pequeno trecho de cdigo que mostra um


bitmap invertido com StretchBlt() o cdigo espelha horizontal e
verticalmente a segunda imagem mostrada com StrecthBlt() da Listagem 6.4.
// Faz transferncia de bits entre os DCs de memria e vdeo
// (alargando a figura, bitmap invertido na horizontal e vertical)
//
//
//
//
//

Parmetros de StretchBlt() para inverter bitmap:


nXOriginDest = Ponto X de destino + largura do bitmap;
nYOriginDest = Ponto Y de destino + altura do bitmap;
nWidthDest = nWidthDest negativo (inverte imagem na horizontal);
nHeightDest = nHeightDest negativo (inverte imagem na vertical);

StretchBlt(hDC, 240, 210, -240, -90, hMemDC, 0, 0, 160, 120, SRCCOPY);


Listagem 6.7: Bitmap invertido com StretchBlt().

Voc deve ter observado que os valores passados para os parmetros


e nYOriginDest esto acrescentados com a largura e altura do
bitmap, respectivamente. Somamos esses valores pois quando um bitmap est
sendo invertido por StretchBlt(), a imagem desenhada na tela da direita para
esquerda (espelhamento horizontal) e de baixo para cima (espelhamento
vertical). Por exemplo, se envissemos o valor zero para nXOriginDest, a
imagem no seria mostrada na tela, pois ela no estaria dentro da rea cliente (a
imagem comearia a ser desenhada a partir do ponto X = 0 at X = -240, o que
estaria incorreto). Caso haja dvidas em relao ao modo que StretchBlt()
desenha os bitmaps (normais e invertidos) na tela, veja o esquema apresentado
na Figura 6.2.
nXOriginDest

A Figura 6.3 demonstra o programa prog06-1.cpp em execuo, com o


flag do programa configurado para mostrar os bitmaps invertidos, atravs do
uso da funo StretchBlt().

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 6 Bitmaps

Figura 6.2: Direo que StretchBlt() mostra bitmaps: (a) normais e (b) invertidos.

Figura 6.3: Bitmaps invertidos com StretchBlt().

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

163

164

Programao Windows: C e Win32 API com nfase em Multimdia

DIB Section
Os bitmaps do tipo DDB possuem a desvantagem de no podermos
acessar e manipular diretamente os seus bits, como j dito anteriormente. Por
exemplo, no podemos carregar uma imagem colorida e mostr-la em tons de
cinza, pois para isso devemos manipular os bits da imagem.
A soluo para esse problema utilizarmos bitmaps do tipo DIB, mas
como necessrio uma converso DIB para DDB para mostrar a imagem na
tela (ocorrendo perda de performance), o melhor caminho criar um objeto
GDI HBITMAP configurado como DIB Section.
Embora exista mais de uma maneira para criar e carregar um bitmap do
tipo DIB Section, apresentarei aqui a soluo mais rpida e fcil, utilizando a
funo LoadImage(), que j estudamos no comeo do captulo.
O ltimo parmetro da funo LoadImage() pode receber o valor
LR_CREATEDIBSECTION, indicando que o retorno da funo ser um objeto HBITMAP
do tipo DIB Section. Simples, no? Inclusive, j vimos um exemplo da criao
de um DIB Section com LoadImage() na Listagem 6.3.
Criar um DIB Section com LoadImage() rpido e fcil. Mas no
queremos somente isso; o nosso objetivo de usar um DIB Section manipular
os bits de uma imagem para podermos criar certos efeitos na mesma. Para
acessarmos os bits de uma imagem, devemos preencher uma estrutura
DIBSECTION:
typedef struct tagDIBSECTION {
BITMAP dsBm;
dsBm;
BITMAPINFOHEADER dsBmih;
dsBmih;
DWORD dsBitfields
dsBitfields[3];
ds[3];
HANDLE dshSection;
dshSection;
DWORD dsOffset;
dsOffset;
} DIBSECTION, *PDIBSECTION;

Os dois primeiros membros (BITMAP e BITMAPINFOHEADER) da estrutura


so duas outras estruturas definidas pela Win32 API, que contm
informaes sobre o bitmap. O membro dsBitfields[3] vlido apenas
quando o membro biBitCount da estrutura BITMAPINFOHEADER 16- ou 32-bit. No
caso afirmativo, cada posio do vetor armazena uma mscara indicando quais
bits de cada pixel correspondem ao canal de cor RGB. Embora no estaremos
utilizando os dois ltimos membros (dshSection e dsOffset), eles so utilizados
DIBSECTION

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 6 Bitmaps

quando um DIB Section criado com a funo


um objeto file mapping.

CreateDIBSection()

165

utilizando

Dica: File mapping utilizado para associar o contedo de um arquivo com


um espao de memria virtual de um processo, assunto que est fora do
contexto desse livro.
Para preenchermos essa estrutura, podemos usar a funo GetObject(),
que obtm informaes do objeto GDI, da seguinte maneira (Listagem 6.8):
// Assumimos que hBmp um HBITMAP DIB Section, no qual carregamos um bitmap
// com a funo LoadImage()
// Cria e preenche uma estrutura DIBSECTION
DIBSECTION dibSect;
GetObject((HBITMAP)hBmp, sizeof(DIBSECTION), (LPVOID)&dibSect);
Listagem 6.8: Preenchendo uma estrutura DIBSECTION.

Uma estrutura que ainda no discutimos a BITMAPINFOHEADER, que faz


parte da DIBSECTION. Essa estrutura contm informaes referentes s
dimenses e cores de um DIB.
typedef struct tagBITMAPINFOHEADER {
DWORD
DWORD biSize;
biSize;
LONG biWidth;
biWidth;
LONG biHeight;
biHeight;
WORD biPlanes;
biPlanes;
WORD biBitCount;
biBitCount;
DWORD biCompression;
biCompression;
DWORD biSizeImage;
biSizeImage;
LONG biXPelsPerMeter;
biXPelsPerMeter;
LONG biYPelsPerMeter;
biYPelsPerMeter;
DWORD biClrUsed;
biClrUsed;
DWORD biClrImportant;
biClrImportant;
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;

O primeiro membro da estrutura (biSize) indica o nmero de bytes


utilizados pela estrutura (sizeof(BITMAPINFOHEADER)). biWidth e biHeight
armazenam a largura e altura do bitmap, respectivamente. biPlanes indica a
quantidade de camadas do dispositivo, e deve ser 1. biBitCount indica a
quantidade de bits que o bitmap usa para representar um pixel. O membro
biCompression informa o tipo de compresso do bitmap. Geralmente, os valores
so BI_RGB ou BI_BITFIELDS. Em biSizeImage armazenado o tamanho da
imagem em bytes, que pode ser calculado pela equao biSizeImage = biWidth *
biHeight * biBitCount / 8. biXPelsPerMeter e biYPelsPerMeter indicam a
resoluo horizontal e vertical (em pixels por metro) do dispositivo de destino
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

166

Programao Windows: C e Win32 API com nfase em Multimdia

do bitmap. O membro biClrUsed especifica a quantidade de cores na paleta de


cores que realmente so utilizados pelo bitmap. Quando recebe zero, significa
que o bitmap usa o nmero mximo de cores indicado por biBitCount. Por fim,
biClrImportant especifica a quantidade de cores necessrias para mostrar o
bitmap. No caso de zero, todas as cores so necessrias. Os quatro ltimos
membros dessa estrutura normalmente recebem o valor zero.
Nota: caso biHeight seja positivo, isso significa que a origem do bitmap o
canto inferior-esquerdo. Caso seja negativo, o bitmap tem sua origem no
canto superior-esquerdo.

Manipulando os bits de um bitmap: tons de cinza e contraste


Os bits que compem uma imagem so armazenados no membro
da estrutura BITMAP dsBm (a qual um membro da estrutura
DIBSECTION). Atravs desse ponteiro, podemos acessar e manipular os bits de
um bitmap, tendo a possibilidade de modificar a imagem original.
LPVOID bmBits

Vamos estudar um caso onde manipulamos os bits de uma imagem


bitmap de 24-bit (um byte para cada cor RGB). O arquivo prog06-2.cpp do CDROM carrega a imagem mostrada na Figura 6.4 (frutas_24bit.bmp, uma imagem
colorida de 24-bit), criando um HBITMAP configurado como DIB Section. No
processo da mensagem WM_PAINT, o programa chama a funo ManipulaPixels()
(Listagem 6.9), onde uma estrutura DIBSECTION criada e preenchida conforme
mencionado anteriormente.

Figura 6.4: Um bitmap 24-bit prestes a ser modificado.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 6 Bitmaps

167

Na funo ManipulaPixels(), declaramos uma varivel (pImgBits) do


tipo unsigned char*, que um ponteiro para os bits da imagem. Em seguida,
preenchemos a estrutura DIBSECTION, com a chamada funo GetObject() e
apontamos pImgBits para DIBSECTION::BITMAP::bmBits. Note que esse membro
do tipo LPVOID, sendo necessrio um type-casting para o tipo unsigned char*.
Em seguida, entramos em um for (que vai de 0 at o tamanho da imagem em
bytes, com passo 3), onde os bits da imagem sero modificados.
void ManipulaPixels(void)
{
DIBSECTION dibSect; // Informaes do bitmap DIB Section
unsigned char *pImgBits; // Ponteiro para bits do bitmap
// Preenche estrutura DIBSECTION com informaes do bitmap
// e faz pImgBits apontar para os bits do bitmap
GetObject((HBITMAP)hBmp, sizeof(DIBSECTION), (LPVOID)&dibSect);
pImgBits = (unsigned char *)dibSect.dsBm.bmBits;
// Converte RGB para tons de cinza
for(int i = 0; i < dibSect.dsBmih.biSizeImage; i += 3)
{
// Obtm os valores RGB dos pontos da imagem
int R = pImgBits[i + 2]; // Red (Vermelho)
int G = pImgBits[i + 1]; // Green (Verde)
int B = pImgBits[i];
// Blue (Azul)
// Calcula luminance / brilho / intensidade de
R = (R << 6) + (R << 3) + (R << 2) + 1;
G = (G << 7) + (G << 4) + (G << 2) + (G << 1);
B = (B << 4) + (B << 3) + (B << 2) + 1;
int L = (R + G + B) >> 8; // L = (R + G + B) /

luz
// R * 77
// G * 150
// B * 29
256

// Converte para tons de cinza


pImgBits[i + 2] = L; // Red (Vermelho)
pImgBits[i + 1] = L; // Green (Verde)
pImgBits[i]
= L; // Blue (Azul)
}
}
Listagem 6.9: Manipulando os bits de uma imagem.

Dentro do loop for da funo, os bits da imagem so modificados,


fazendo uma converso RGB (imagem colorida) para tons de cinza. A
modificao dos bits feita associando o valor de iBrilho para pImgBits[i],
pImgBits[i + 1] e pImgBits[i + 2]. Esses ndices (i, i + 1 e i + 2) so utilizados
pois bitmaps 24-bit utilizam um byte para representar cada componente RGB.
Para converter uma imagem colorida para uma imagem com
tonalidades de cinza, aplicamos o seguinte algoritmo (Listagem 6.10, em
pseudo-cdigo):

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

168

Programao Windows: C e Win32 API com nfase em Multimdia

para cada ponto P na imagem, (P contm Red, Green e Blue)


calcular L = (0.299 * P.Red) + (0.587 * P.Green) + (0.114 * P.Blue)
atribuir P.Red
= L
atribuir P.Green = L
atribuir P.Blue = L
Listagem 6.10: Converso RGB para tons de cinza (pseudo-cdigo).

Nota: L vem do ingls luminance (brilho ou intensidade de luz em uma cor),


que atribuindo seu valor para os componentes RGB, obtm-se a tonalidade
de cinza.
Veja que a equao do pseudo-cdigo diferente do cdigo da
Listagem 6.9, porm o resultado o mesmo, pois a equao L = ((77 * P.Red)
+ (150 * P.Green) + (29 * P.Blue)) / 256 foi utilizada para que no fosse
necessrio o uso de variveis float. Outra otimizao realizada foi o uso dos
operadores binrios shift-left e shift-right, substituindo operaes de multiplicao
e diviso, respectivamente.
Dica: embora nesse caso a otimizao no seja um ponto to crtico,
bom saber que em certas ocasies possvel otimizar clculos e ganhar
performance atravs dos operadores binrios shift-left e shift-right. No
clculo da varivel R da funo ManipulaPixels(), a operao R = (R << 6) +
(R << 3) + (R << 2) + 1 equivalente a R * 26 + R * 23 + R * 22 + 1, que
resulta em R * 77. Shift-left executa a operao num1 << num2 = num1 * 2num2
e shift-right executa a operao num1 >> num2 = num1 / 2num2.
Com

uma pequena modificao no loop for da funo


ManipulaPixels(), podemos criar outra funo, Contraste() (Listagem 6.11,
contendo o pseudo-cdigo da funo), que configura o gamma (contraste) da
imagem, podendo clarear ou escurecer a mesma.
/*
pseudo-cdigo para configurar contraste de uma imagem:
definir o valor de gamma:
valores entre 0.0 e 1.0 clareiam a imagem
valores acima de 1.0 escurecem a imagem
para cada ponto P na
atribuir P.Red
=
atribuir P.Green =
atribuir P.Blue =
*/

imagem, (P contm Red, Green e Blue)


255 * (P.Red / 255.0)gamma
255 * (P.Green / 255.0)gamma
255 * (P.Blue / 255.0)gamma

void Contraste(DIBSECTION dibSect, float fGamma)


{

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 6 Bitmaps

169

// Ponteiro para bits do bitmap


unsigned char *pImgBits = (unsigned char *)dibSect.dsBm.bmBits;
// Configura o contraste da imagem
for(int i = 0; i < dibSect.dsBmih.biSizeImage; i += 3)
{
// Obtm os valores RGB dos pontos da imagem
int R = pImgBits[i + 2]; // Red (Vermelho)
int G = pImgBits[i + 1]; // Green (Verde)
int B = pImgBits[i];
// Blue (Azul)
// Aplica
R = 255 *
G = 255 *
B = 255 *

novo contraste
pow(R / 255.0, fGamma);
pow(G / 255.0, fGamma);
pow(B / 255.0, fGamma);

// Atualiza os pontos da imagem


pImgBits[i + 2] = R; // Red (Vermelho)
pImgBits[i + 1] = G; // Green (Verde)
pImgBits[i]
= B; // Blue (Azul)
}
}
Listagem 6.11: Configurar contraste de uma imagem (pseudo-cdigo e cdigo).

A funo Contraste() recebe dois parmetros: um DIBSECTION, que


contm as informaes de um bitmap DIB Section, e um float, que configura
o contraste da imagem. Supomos que uma DIBSECTION j esteja preenchida e
seja passada para a funo Contraste(), mas poderamos obter as informaes
de um DIB Section dentro dessa funo, assim como foi feito em
ManipulaPixels().
Assim, chegamos ao final de mais um captulo. Voc aprendeu como
utilizar imagens bitmap nos programas, a diferena entre DDBs e DIBs e
como modificar os bits de uma imagem, podendo aplicar diversos efeitos nas
imagens, como transformar uma imagem colorida em tons de cinza e modificar
seu contraste. No prximo captulo, estudaremos regies e algumas de suas
aplicaes.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

170

Programao Windows: C e Win32 API com nfase em Multimdia

Captulo 7 Regies
H alguns anos, os programas para Windows eram montomos;
todos eles tinham o mesmo visual-padro retangular que j estamos
acostumados a trabalhar. Com o lanamento e o grande uso do tocador de
msicas digitais Winamp, essa padronizao de programas com janelas
retangulares perdeu um pouco seu territrio, pois o Winamp deu ao usurio a
possibilidade de modificar totalmente o visual do programa, atravs de imagens
conhecidas por skins. Seguindo o conceito de utilizao de skins, diversos
programas foram surgindo, onde acabaram acrescentando algo mais: a
personalizao no somente do visual, como tambm do formato da janela do
programa.
Hoje, os programas no precisam mais serem retangulares; podemos
criar programas com janelas redondas, em forma de estrela, com os cantos de
um retngulo arredondados e at mesmo com o formato de uma foto. A
criao desses tipos de janelas possvel atravs do uso de regies.

O que so regies?
Regies so objetos GDI (HRGN) que armazenam retngulos, polgonos,
elipses ou combinaes desses trs tipos de geometria, sendo possvel
preencher, executar testes da posio de cursor e modificar o formato da janela
(rea cliente) de um programa.
Dica: uma regio pode ser classificada de acordo com sua complexidade,
ou seja, de que forma ela formada. Uma regio do tipo SIMPLEREGION
quando composta por um nico retngulo e do tipo COMPLEXREGION
quando composta por mais de um retngulo. NULLREGION significa que uma
regio vazia.

Criando regies
Podemos criar quatro tipos de regies: no formato de uma elipse
(funo CreateEllipticRgn()), retangulares (funo CreateRectRgn()),
retangulares com cantos arredondados (funo CreateRoundRectRgn()) e
poligonais (funo CreatePolygonRgn()). Cada um desses formatos possuem
suas prprias funes para criao de regies, conforme mencionados entre
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 7 Regies

171

parnteses, sendo que elas trabalham de forma muito semelhantes s funes


Ellipse(), Rectangle() e RoundRect() e Polygon(), respectivamente, vistas no
captulo 5. As diferenas entre as funes de figuras e de regies so que as
ltimas no recebem um identificador de DC como parmetro e retornam uma
regio (varivel do tipo HRGN) quando criada ou NULL caso contrrio. Os
prottipos de cada uma das funes so listados a seguir.
HRGN CreateEllipticRgn(
int nLeftRect, // coordenada x do canto superior esquerdo do retngulo
int nTopRect, // coordenada y do canto superior esquerdo do retngulo
int nRightRect, // coordenada x do canto inferior direito do retngulo
int nBottomRect // coordenada y do canto inferior direito do retngulo
);
HRGN CreateRectRgn(
CreateRectRgn(
int nLeftRect, // coordenada x do canto superior esquerdo
int nTopRect, // coordenada y do canto superior esquerdo
int nRightRect, // coordenada x do canto inferior direito
int nBottomRect // coordenada y do canto inferior direito
);
HRGN
HRGN CreateRoundRectRgn(
int nLeftRect, // coordenada x do canto superior esquerdo
int nTopRect, // coordenada y do canto superior esquerdo
int nRightRect, // coordenada x do canto inferior direito
int nBottomRect, // coordenada y do canto inferior direito
int nWidthEllipse, // largura da elipse
int nHeightEllipse // altura da elipse
);
HRGN CreatePolygonRgn(
CONST POINT *lppt, // vrtices do poligono
int cPoints, // quantidade de vrtices do polgono
int fnPolyFillMode // modo de preenchimento
);

Veja que a funo CreatePolygonRgn() possui um parmetro int


fnPolyFillMode, que recebe o mesmo valor (ALTERNATE ou WINDING) que a funo
SetPolyFillMode() (vista no captulo 5) e possui o mesmo significado.

Desenhando regies
Uma regio fica invisvel at que o programa seja instrudo para
preencher seu interior por determinado pincel, inverter as cores do seu interior
ou traar uma borda em volta da regio.
Para preencher o interior de uma regio, podemos utilizar duas
funes: FillRgn() e PaintRgn(). A primeira funo preenche a regio com as
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

172

Programao Windows: C e Win32 API com nfase em Multimdia

configuraes de um pincel enviado como parmetro, enquanto a segunda


preenche a regio usando o pincel que est selecionado no DC.
BOOL FillRgn(
HDC hdc,
hdc, // identificador do DC
HRGN
HRGN hrgn,
hrgn, // identificador da regio a ser preenchida
HBRUSH hbr // identificador do pincel a ser utilizado
);

A funo FillRgn() recebe o identificador do DC no primeiro


parmetro (HDC hdc), o identificador da regio que ser preenchida no segundo
(HRGN hrgn) e o pincel que ser utilizado para o preenchimento, no terceiro
parmetro (HBRUSH hbr). O retorno da funo ser diferente de zero quando no
houver erros ou zero caso contrrio.
BOOL PaintRgn(
HDC hdc,
hdc, // identificador do DC
HRGN hrgn // identificador da regio a ser preenchida
);

A funo PaintRgn() recebe apenas o identificador do DC (HDC hdc) e o


identificador da regio (HRGN hrgn) que ser preenchida, visto que a mesma
utiliza o pincel selecionado no DC para preenchimento. O retorno da funo
ser diferente de zero quando no houver erros ou zero caso contrrio.
Para inverter as cores de uma regio, basta utilizar a funo InvertRgn().
BOOL InvertRgn(
HDC hdc,
hdc, // identificador do DC
HRGN hrgn // identificador da regio a ser invertida
);

A funo recebe o identificador do DC no primeiro parmetro (HDC


hdc) e o identificador da regio que ter sua cor invertida (HRGN hrgn). O
retorno da funo ser diferente de zero quando no houver erros ou zero caso
contrrio.
Para traar uma borda em volta da regio, utilizamos a funo
FrameRgn().
BOOL FrameRgn(
HDC hdc,
hdc, // identificador do DC
HRGN hrgn,
hrgn, // identificador da regio onde ser traada a borda
HBRUSH hbr,
hbr, // identificador do pincel para traar a borda
int nWidth,
nWidth, // largura da borda
int nHeight // altura da borda

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 7 Regies

173

);

A funo recebe o identificador do DC no primeiro parmetro (HDC


hdc), o identificador da regio em HRGN hrgn, o identificador do pincel que ser
utilizado para traar a borda em HBRUSH hbr e a largura e altura da borda (int
nWidth e int nHeight, respectivamente). Ela retorna zero em caso de erros ou
um valor diferente de zero caso contrrio.

Operaes com regies


Alm de criar e desenhar regies, podemos realizar algumas operaes,
tais como verificar se duas regies so iguais, verificar se um ponto ou um
retngulo est dentro de uma regio, mover uma regio ou fazer uma
combinao de duas regies.
Para verificarmos se duas regies so idnticas, usamos a funo
Duas regies so consideradas idnticas se so iguais em tamanho e
formato.
EqualRgn().

BOOL EqualRgn(
HRGN
HRGN hSrcRgn1, // identificador da primeira regio
HRGN hSrcRgn2 // identificador da segunda regio
);

A funo recebe como parmetros (hSrcRgn1 e hSrcRgn2) os dois


identificadores das regies que sero comparadas. O retorno pode ser um valor
diferente de zero se ambas regies so idnticas, zero quando so diferentes ou
ERROR, indicando que pelo menos um dos identificadores invlido.
A funo PtInRegion() verifica se um determinado ponto encontra-se
ou no dentro de uma regio especificada.
BOOL PtInRegion(
PtInRegion(
HRGN hrgn, // identificador da regio
int X, // coordenada x do ponto
int Y // coordenada y do ponto
);

Essa funo recebe o identificador da regio no primeiro parmetro e a


coordenada do ponto (x, y) no segundo e terceiro parmetro. Ela ento verifica
se o ponto est dentro da regio e retorna um valor diferente de zero em caso
afirmativo ou zero caso o ponto esteja fora da regio.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

174

Programao Windows: C e Win32 API com nfase em Multimdia

Podemos verificar tambm se um retngulo ou parte dele est dentro


de uma regio, atravs da funo RectInRegion().
BOOL RectInRegion(
HRGN hrgn, // identificador da regio
CONST RECT *lprc // ponteiro para o retngulo
);

A funo recebe o identificador da regio e um ponteiro para uma


estrutura RECT, que contm as coordenadas do retngulo. Caso o retngulo,
integral ou parcialmente, esteja dentro da regio, a funo retorna um valor
diferente de zero. Quando nenhuma parte do retngulo est dentro da regio, a
funo retorna o valor zero.
Quando quisermos mover uma regio, chamamos a funo OffsetRgn().
int OffsetRgn(
HRGN hrgn, // identificador da regio
int nXOffset, // desvio no eixo x
int nYOffset // desvio no eixo y
);
OffsetRgn() recebe em HRGN hrgn o identificador da regio que ser
movida para esquerda/direita (int nXOffset) e/ou para cima/baixo (int
nYOffset). O retorno pode ser NULLREGION (regio vazia), SIMPLEREGION (regio
de um nico retngulo), COMPLEXREGION (regio de mais de um retngulo) ou
ERROR (ocorreu erro e regio no foi modificada).

Uma outra operao que podemos fazer com regies a combinao


delas, resultando em uma nova regio. Para isso, utilizamos a funo
CombineRgn().
int CombineRgn(
HRGN hrgnDest, //
HRGN hrgnSrc1, //
HRGN hrgnSrc2, //
int fnCombineMode
);

identificador da regio de destino


identificador da regio de origem 1
identificador da regio de origem 2
// modo de combinao das regies

Para realizar a combinao de regies, a funo CombineRgn() recebe


duas regies de origem (as regies que sero combinadas), nos parmetros HRGN
hrgnSrc1 e HRGN hrgnSrc2. O resultado da combinao armazenada numa outra
regio, indicada no parmetro HRGN hrgnDest. O ltimo parmetro, int
fnCombineMode indica como as duas regies sero combinadas, podendo receber

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 7 Regies

175

(interseco das duas regies), RGN_COPY (copia apenas a regio


identificada em hsrcSrc1), RGN_DIFF (combina a parte de hrgnSrc1 que no faz
parte de hrgnSrc2), RGN_OR (unio das duas regies) ou RGN_XOR (unio das duas
regies exceto reas que fazem parte de ambas). A funo pode retornar
NULLREGION (regio vazia), SIMPLEREGION (regio de um nico retngulo),
COMPLEXREGION (regio de mais de um retngulo) ou ERROR (regio no foi criada).
RGN_AND

Dica: a regio de destino no precisa ser necessariamente uma outra


regio, pode ser uma das regies de origem; por exemplo, a regio hrgnSrc1
pode ser a mesma que hrgnDest. Dessa maneira, a funo ir combinar as
regies hrgnSrc1 e hrgnSrc2 e armazenar a combinao em hrgnSrc1.

Regies de corte
As regies tambm atuam como regies de corte (clipping region),
especificando um espao onde qualquer operao grfica fora desse limite no
ser afetada. Isso pode ser til quando precisamos modificar apenas um
determinado pedao da rea cliente ou quando queremos que todas as
operaes sejam feitas em apenas uma regio da rea cliente, no limitando-se
regies retangulares.
Para determinar uma regio de corte, basta que criemos uma regio (e,
se necessrio, realizar operaes com regies, conforme mencionado nesse
captulo) e em seguida selecionarmos a regio no DC atual. Por exemplo,
podemos criar uma regio de corte circular em um programa que mostre um
bitmap (retangular), conforme a Listagem 7.1. Como definimos uma regio de
corte, toda a rea ocupada pela imagem que no esteja dentro da regio
delimitada no ser mostrada na tela (Figura 7.1).
//-------------------------------------------------------------------------// WindowProc() -> Processa as mensagens enviadas para o programa
//-------------------------------------------------------------------------LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
lParam)
{
// ...
case WM_CREATE: // Janela foi criada
{
// Cria uma regio elptica
hRgn = CreateEllipticRgn(80, 50, 230, 200);
// Cria DC de memria (hMemDC global)
hDC = GetDC(hWnd);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

176

Programao Windows: C e Win32 API com nfase em Multimdia


hMemDC = CreateCompatibleDC(hDC);

// Cria DIB Section, carregando bitmap do arquivo "frutas_24bit.bmp"


hBmp = (HBITMAP)LoadImage(NULL, "frutas_24bit.bmp", IMAGE_BITMAP, 320,
240, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
// Seleciona bitmap no DC de memria (configura DC de memria)
SelectObject(hMemDC, hBmp);
// Libera DC de vdeo
ReleaseDC(hWnd, hDC);
// Retorna 0, significando que a mensagem foi processada corretamente
return(0);
} break;
case WM_PAINT: // Janela (ou parte dela) precisa ser atualizada
{
// Obtm DC de vdeo
hDC = BeginPaint(hWnd, &psPaint);
// Seleciona regio no DC, definindo regio de corte
SelectObject(hDC, hRgn);
// Faz transferncia de bits entre os DC's de memria e vdeo
BitBlt(hDC, 0, 0, 320, 240, hMemDC, 0, 0, SRCCOPY);
// Libera DC de vdeo
EndPaint(hWnd, &psPaint);
return(0);
} break;
// ...
}
Listagem 7.1: Definindo uma regio de corte.

Figura 7.1: Regio de corte circular.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 7 Regies

177

Nota: o arquivo prog07-1.cpp do CD-ROM contm o cdigo-fonte da


Listagem 7.1 na ntegra, demonstrando a criao e uso de regies.

Criando janelas no-retangulares


A ltima operao com regies que veremos a criao de janelas noretangulares, mencionadas no incio desse captulo. Programas com janelas
no-retangulares contm algumas diferenas, comparadas aos com janelas
retangulares. Uma das primeiras diferenas a barra de ttulo do programa:
geralmente ela no utilizada, por questes de esttica. Logo, a janela deve ser
criada com a propriedade WS_POPUP | WS_VISIBLE (parmetro dwStyle da funo
CreateWindowEx()).
A segunda diferena que, ao desabilitarmos a barra de ttulo, o
usurio no pode arrastar o programa para onde ele quiser. Para contornar esse
problema, enviamos a mensagem WM_NCLBUTTONDOWN para o loop de mensagens
com o valor HTCAPTION quando o usurio clicar com o boto esquerdo do
mouse em determinada rea do programa, simulando um clique na barra de
ttulo. Dessa maneira, o programa automaticamente ir considerar tal clique
como um clique na barra de ttulo, permitindo ao usurio arrastar o programa
pela tela. O trecho de cdigo da Listagem 7.2 simula um clique na barra de
ttulo quando o cursor do mouse estiver no topo da janela.
case WM_LBUTTONDOWN:
{
// Se a posio y do cursor do mouse for menor que 100
if(HIWORD(lParam) < 100)
// Envia mensagem WM_NCLBUTTONDOWN, indicando que foi um
// clique na barra de ttulo
SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, lParam);
return(0);
} break;
Listagem 7.2: Simulando clique na barra de ttulo.

Para criarmos uma janela no-retangular (definir o formato de uma


regio para a janela do programa) usamos a funo SetWindowRgn().
int SetWindowRgn(
HWND hWnd, // identificador da janela
HRGN hRgn, // identificador da regio
BOOL bRedraw // redesenha janela?
);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

178

Programao Windows: C e Win32 API com nfase em Multimdia

A funo SetWindowRgn() recebe o identificador da janela que ser


modificada, o identificador da regio que determinar o formato da janela e um
flag que especifica se a janela ser redesenhada aps ter seu formato
modificado. Geralmente, bRedraw recebe TRUE quando a janela est visvel. A
funo retorna um valor diferente de zero quando nenhum problema ocorrer
ou zero caso contrrio.
Nota: quando SetWindowRgn() executada sem erros, o sistema obtm
controle da regio indicada em hRgn; portanto, no devemos executar
nenhuma operao nesse identificador nem deletar o objeto HRGN, pois o
prprio sistema o far quando o identificador da regio no for mais
utilizado.
Para exemplificar a criao de janelas no-retangulares, o cdigo da
funo WindowSkin() (Listagem 7.3) executa um simples algoritmo que pode ser
utilizado para o uso de skins de um programa (uma skin deve ser uma imagem
carregada em um objeto HBITMAP e suas partes transparentes devem ter a cor
RGB(255, 0, 255)).
A funo primeiro seleciona o bitmap no DC (ambos enviados como
parmetros da funo). Em seguida, executa dois loops onde varre os pontos
do bitmap, obtendo o formato da figura. Dentro dos loops, a funo verifica se
a cor do ponto (x, y) atual da imagem igual a cor de transparncia (definida
na varivel COLORREF rgbTransparente). Se for, a funo simplesmente ignora tal
ponto e verifica o prximo. Quando o ponto no for transparente, a funo
ento salva o primeiro ponto no-transparente e varre a imagem na horizontal
at que encontre o ltimo ponto no-transparente (ou seja, at chegar ao fim
da linha atual (y) ou at encontrar um ponto transparente). Depois disso, a
funo cria uma regio temporria, contendo os pontos no-transparentes da
linha atual, e a combina com a regio atual, que ao final dos loops conter o
formato da figura. Por fim, a funo define o formato da janela de acordo com
a regio atual.
//-------------------------------------------------------------------------// WindowSkin() -> Cria janela no formato de uma figura
//-------------------------------------------------------------------------void WindowSkin(HWND hWnd, HDC hMemDC, HBITMAP hBmp)
{
// Cria regio no formato da figura
HRGN hRgn = CreateRectRgn(0, 0, 0, 0);
HRGN hRgnTemp = hRgn;
// Cor transparente

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 7 Regies

179

COLORREF rgbTransparente = RGB(255, 0, 255);


// Salva o primeiro ponto no-transparente da posio x da imagem
int ix = 0;
// Seleciona bitmap no DC de memria (configura DC de memria)
SelectObject(hMemDC, hBmp);
// Varre o bitmap para obter cores e o formato da figura
for(int y = 0; y <= WINDOW_HEIGHT; y++)
{
for(int x = 0; x <= WINDOW_WIDTH; x++)
{
// Verifica se a cor do ponto atual transparente
if(GetPixel(hMemDC, x, y) != rgbTransparente)
{
// Se no for, salva o primeiro ponto no-transparente da
// posio x da imagem
ix = x;
// E incrementa a posio x at achar um ponto que transparente
// ou at chegar ao final da imagem (na horizontal)
while((x <= WINDOW_WIDTH) &&
(GetPixel(hMemDC, x, y) != rgbTransparente))
x++;
// Depois cria uma regio temporria onde:
// x = primeiro ponto no-transparente at ltimo ponto
// no-transparente
// y = posio y atual at prximo y
hRgnTemp = CreateRectRgn(ix, y, x, y + 1);
// Combina a regio atual (hRgn) com a regio temporria (hRgnTemp)
CombineRgn(hRgn, hRgn, hRgnTemp, RGN_OR);
}
}
}
// Depois que varreu todo o bitmap, verificando seu formato (de acordo com
// as partes transparentes e no-transparentes da imagem), define o
// formato da janela conforme a regio atual (hRgn).
SetWindowRgn(hWnd, hRgn, TRUE);
}
Listagem 7.3: Criao de skin para uma janela.

O arquivo prog07-2.cpp do CD-ROM contm a implementao


completa de um programa que utiliza a funo WindowSkin() e que aplica as
duas modificaes (para programas com janelas no-retangulares) discutidas
nessa seo. A sada desse programa pode ser vista na Figura 7.2: o programa
tem o formato de um boneco de massinha, que na figura est sobrepondo o
Microsoft Visual C++ .Net (que no momento estava com o cdigo do
programa aberto).

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

180

Programao Windows: C e Win32 API com nfase em Multimdia

Figura 7.2: Programa com janela no-retangular.

Nesse captulo, vimos como criar e utilizar regies, incluindo a


combinao de duas ou mais regies e a criao de janelas no-retangulares
muito utilizadas em programas onde o usurio pode definir o formato da janela
atravs de bitmaps. Veremos a seguir como utilizar sons e timers em nossos
programas.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 8 Sons e Timers

181

Captulo 8 Sons e Timers


Para a criao de programas multimdia, msicas e efeitos sonoros so
essenciais. Atravs da Win32 API, usamos funes para reproduzir sons do
tipo wave (arquivos com extenso .wav) e msicas do tipo MIDI (arquivos com
extenso .mid). Podemos utilizar outros recursos multimdia tambm, tais como
reproduzir um vdeo, tocar as faixas de um CD de udio ou mesmo gravar
sons, porm esses assuntos no sero vistos nesse livro.

Reproduzindo sons
A maneira mais rpida e simples de reproduzir um som wave
utilizando a funo PlaySound(). Essa funo pode reproduzir arquivos wave
do disco ou um som wave que est em um arquivo de recursos (que
geralmente anexado ao programa executvel em tempo de compilao),
porm, no suporta a reproduo de mltiplos sons ao mesmo tempo.
BOOL PlaySound(
LPCSTR pszSound, // arquivo ou recurso wave
HMODULE hmod, // instncia do executvel que contm o recurso (som)
DWORD fdwSound // flags
);

Para reproduzir um arquivo wave, devemos enviar o valor SND_FILENAME


para o ltimo parmetro (DWORD fdwSound) e informar o nome do arquivo no
primeiro parmetro (LPCSTR pszSound). Nesse caso, o parmetro HMODULE hmod
deve receber NULL, visto que o som ser carregado de um arquivo.
Para reproduzir um recurso wave, enviamos o valor SND_RESOURCE para o
ltimo parmetro e informamos o identificador do recurso no primeiro
(utilizando o a macro MAKEINTRESOURCE()). O segundo parmetro deve receber a
instncia do programa que contm o recurso (uma varivel do tipo HINSTANCE).
Para parar a reproduo de um som, chamamos a funo com o valor
NULL no parmetro pszSound.
A funo retorna TRUE quando a mesma for executada corretamente ou
FALSE caso contrrio (o arquivo ou recurso wave enviado para a funo no foi
encontrado, por exemplo).

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

182

Programao Windows: C e Win32 API com nfase em Multimdia

O parmetro fdwSound da funo ainda recebe informaes (atravs de


uma combinao OR) de como o som deve ser reproduzido. Consulte a Tabela
8.1 para a descrio dos principais valores desse parmetro.
Valor
SND_ASYNC

SND_FILENAME
SND_LOOP

SND_NOWAIT
SND_RESOURCE

SND_SYNC

Descrio
A funo retorna o controle para o programa
imediatamente aps o som comear a ser
reproduzido.
O parmetro pszSound recebe o nome de um
arquivo.
A funo reproduz o som repetidamente, at
que a funo seja chamada novamente com o
valor NULL no parmetro pszSound. O valor
SND_ASYNC tambm deve ser informado nesse
caso.
Se o driver de som estiver ocupado, retorna
imediatamente sem reproduzir o som.
O parmetro pszSound recebe um
identificador de recurso e o parmetro hmod
indica a instncia que contm o recurso.
O controle para o programa retornado
somente aps o som ter sido reproduzido
por completo.
Tabela 8.1: Como PlaySound() deve reproduzir um som.

A biblioteca Windows Multimedia


Para que a funo PlaySound() (e qualquer outra funo multimdia)
possa ser utilizada, necessrio incluir o arquivo de cabealho mmsystem.h no
cdigo-fonte do programa e tambm a biblioteca winmm.lib.
Para incluir o arquivo de cabealho, basta inserir a diretiva #include
<mmsystem.h> no comeo do cdigo-fonte do seu programa. Para incluir a
biblioteca winmm.lib, necessrio modificar as configuraes do projeto, dentro
do seu compilador. Ou ento, podemos adicionar a biblioteca no prprio
cdigo-fonte, atravs da diretiva #pragma comment(lib, winmmb.lib). O uso
dessa diretiva faz com que o compilador procure a biblioteca winmm.lib para ser
linkada ao arquivo executvel final.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 8 Sons e Timers

183

MCI
Para trabalharmos com multimdia atravs da Win32 API, podemos
utilizar a Interface de Controle de Mdia (Media Control Interface, ou
simplesmente MCI). Essa interface nos fornece comandos padres para o
acesso e uso de diversos dispositivos multimdia, tais como som, msica e
vdeo.
O uso da MCI pode ser feito atravs de strings de comando ou por
mensagens de comando. Quando usamos strings de comando, enviamos uma
string de determinada ao para a funo mciSendString(). No caso de
mensagens de comando, usamos constantes e estruturas para manipulao da
MCI atravs da funo mciSendCommand().
Nota: o sistema operacional converte as strings de comando para
mensagens de comando antes de envi-las para o processamento do driver
MCI. Estudaremos como trabalhar com a MCI atravs de mensagens de
comando.
Vamos supor que precisamos reproduzir um arquivo wave em disco,
chamado teste.wav, e que queremos usar strings de comando. O cdigo para
essa ao ficaria como na Listagem 8.1.
// Reproduz o arquivo wave teste.wav em disco
mciSendString("play teste.wav", NULL, 0, NULL);
Listagem 8.1: Uso de strings de comando MCI.

Para reproduzir o mesmo arquivo wave, mas agora utilizando


mensagens de comando, usaramos o cdigo da Listagem 8.2.
// Abre arquivo wave teste.wav do disco
MCI_OPEN_PARMS mciOpenParms;
mciOpenParms.lpstrDeviceType = "waveaudio";
mciOpenParms.lpstrElementName = "teste.wav";
mciOpenParms.dwCallback = (DWORD)hWnd;
mciSendCommand(0,
MCI_OPEN,
MCI_OPEN_TYPE
(DWORD)&mciOpenParms);
MCIDEVICEID mciDeviceID = mciOpenParms.wDeviceID;

MCI_OPEN_ELEMENT,

// Reproduz o arquivo wave teste.wav em disco


MCI_PLAY_PARMS mciPlayParms;
mciPlayParms.dwCallback = (DWORD)hWnd;
mciSendCommand(mciDeviceID, MCI_PLAY, NULL, (DWORD)&mciPlayParms);
Listagem 8.2: Uso de mensagens de comando MCI.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

184

Programao Windows: C e Win32 API com nfase em Multimdia

Como possvel notar, h uma grande diferena entre o uso de strings


e mensagens de comando, pelo fato que as mensagens de comando utilizam
estruturas que devem ser preenchidas antes de chamarmos a funo
mciSendCommand(). Embora parea complicado, o uso das mensagens de
comando simples e comum na programao Windows, alm de no haver a
converso como no caso do uso de strings.
O prottipo das funes de strings e mensagens de comando so
listadas e explicadas a seguir.
MCIERROR mciSendString(
LPCTSTR lpszCommand,
lpszCommand, // string de comando
LPTSTR lpszReturnString,
lpszReturnString, // buffer com informao de retorno
UINT cchReturn,
cchReturn, // tamanho do buffer, em caracteres
HANDLE hwndCallback // identificador de um callback
);

A funo mciSendString() recebe no primeiro parmetro uma string


contendo o comando MCI que ser executado. Caso seja necessrio uma
informao de retorno da funo, enviamos um ponteiro para o segundo
parmetro (lpszReturnString) e indicamos o tamanho do buffer desse ponteiro
no terceiro parmetro (cchReturn). Quando no h a necessidade de informao
de retorno, basta enviar NULL para lpszReturnString e zero para cchReturn. O
ltimo parmetro deve receber um identificador de uma funo callback se a
flag notify for especificado na string de comando, caso contrrio, passamos
NULL. A funo retorna zero quando executada corretamente ou um erro caso
contrrio.
Nota: sugiro uma consulta ao MSDN para obter as strings de comando e
cdigos de erros.
MCIERROR mciSendCommand(
MCIDEVICEID IDDevice,
IDDevice, // identificador do dispositivo
UINT uMsg,
uMsg, // mensagem de comando
DWORD fdwCommand,
fdwCommand, // flags da mensagem
DWORD_PTR dwParam // estrutura que contm parmetros da mensagem
);

A funo mciSendCommand() recebe no primeiro parmetro o


identificador do dispositivo que receber a mensagem. O segundo parmetro
recebe a mensagem que ser executada (veja Tabela 8.2 para as principais
mensagens). O terceiro parmetro, DWORD fdwCommand, recebe flags das
mensagens. Note que para cada mensagem/comando especfico, existem
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 8 Sons e Timers

185

diferentes tipos de flags. O ltimo parmetro recebe um ponteiro para a


estrutura que contm os parmetros de configurao da mensagem de
comando. A funo retorna zero quando executada corretamente ou um erro
caso contrrio.
Nota: quando a mensagem MCI_OPEN enviada para a funo
mciSendCommand(), o primeiro parmetro dessa funo deve receber NULL.
Ainda, essa mensagem obtm o identificador do dispositivo que deve ser
enviado para o primeiro parmetro quando queremos executar outros
comandos MCI.
Valor
MCI_CLOSE
MCI_OPEN
MCI_PAUSE
MCI_PLAY
MCI_RESUME
MCI_SEEK
MCI_STOP

Descrio
Libera acesso ao dispositivo ou arquivo.
Inicia um dispositivo ou abre um arquivo.
Pausa o dispositivo.
Comea reproduo dos dados do
dispositivo.
Despausa o dispositivo.
Muda a posio atual dos dados do
dispositivo.
Pra a reproduo dos dados do dispositivo.
Tabela 8.2: Principais mensagens de comando.

Reproduo de mltiplos sons


Conforme visto no comeo desse captulo, a funo PlaySound() no
permite a reproduo de dois ou mais sons simultaneamente. Temos que
esperar o primeiro som terminar para ento reproduzirmos o segundo ou
paramos a reproduo do primeiro para iniciar o segundo. Com o uso da MCI,
essa restrio eliminada, pois criamos um identificador para cada dispositivo
(som) que utilizamos no programa.
Para reproduzir um som, devemos proceder com as seguintes etapas:
1) Definir o tipo de dispositivo e arquivo a ser aberto, configurando a
estrutura MCI_OPEN_PARMS;
2) Iniciar o dispositivo, obtendo seu identificador;
3) Reproduzir os dados do dispositivo.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

186

Programao Windows: C e Win32 API com nfase em Multimdia

A estrutura MCI_OPEN_PARMS define as configuraes do dispositivo, tais


como o tipo do dispositivo, o nome do arquivo que ser aberto para
reproduo e o identificador do dispositivo.
typedef struct {
DWORD_PTR dwCallback;
dwCallback;
MCIDEVICEID wDeviceID;
wDeviceID;
LPCSTR lpstrDeviceType;
lpstrDeviceType;
LPCSTR lpstrElementName;
lpstrElementName;
LPCSTR lpstrAlias;
lpstrAlias;
} MCI_OPEN_PARMS;

O membro lpstrDeviceType define o tipo de dispositivo. No caso de


arquivos wave, atribumos o valor waveaudio para ele. Enviamos o nome do
arquivo que ser reproduzido para o membro lpstrElementName. O membro
dwCallback s utilizado quando queremos que a mensagem MCI_NOTIFY seja
processada por algum identificador de janela (que atribudo a esse membro).
lpstrAlias define um pseudnimo para o dispositivo e opcional. O
identificador do dispositivo fica armazenado em wDeviceID, somente aps a
mensagem MCI_OPEN for enviada para mciSendCommand().
Aps ter configurado a estrutura MCI_OPEN_PARMS, iniciamos o
dispositivo enviando a mensagem MCI_OPEN para mciSendCommand(). Essas etapas
podem ser realizadas da seguinte forma (Listagem 8.3):
// Armazena identificador do dispositivo
MCIDEVICEID mciDeviceID = NULL;
// ...
// Verifica se o dispositivo j foi inicializado
if(mciDeviceID == NULL)
{
// Configura o dispositivo
MCI_OPEN_PARMS mciOpenParms;
mciOpenParms.lpstrDeviceType = "waveaudio";
mciOpenParms.lpstrElementName = "teste.wav";
// Abre o dispositivo
mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
(DWORD)&mciOpenParms);
// Obtm identificador do dispositivo
mciDeviceID = mciOpenParms.wDeviceID;
}
// ...
Listagem 8.3: Configurando MCI_OPEN_PARMS e inicializando um dispositivo.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 8 Sons e Timers

187

Note que ao chamar a funo mciSendCommand(), seu primeiro parmetro


recebe NULL, pois ainda no possumos o identificador do dispositivo. A funo
ainda recebe dois flags, MCI_OPEN_TYPE e MCI_OPEN_ELEMENT, indicando,
respectivamente, que o dispositivo a ser aberto do tipo definido em
lpstrDeviceType e que um arquivo foi especificado em lpstrElementName, ambos
definidos na estrutura enviada para o ltimo parmetro da funo
((DWORD)&mciOpenParms).
A etapa seguinte reproduzir o som que foi carregado. Podemos fazer
isso de duas maneiras: com ou sem o envio da mensagem MM_MCINOTIFY para a
funo callback de um identificador de janela. Quando queremos que o
dispositivo envie a mensagem MM_MCINOTIFY aps completar uma determinada
ao (no caso, quando terminar de reproduzir o som), devemos configurar a
estrutura MCI_PLAY_PARMS. Para a reproduo de um som, sem necessidade de
enviar tal mensagem, basta enviar MCI_PLAY para a funo mciSendCommand().
typedef struct {
DWORD_PTR dwCallback;
dwCallback; // funo callback de um identificador de janela que
ir processar a mensagem MM_MCINOTIFY
DWORD dwFrom;
dwFrom; // posio inicial do som
DWORD dwTo;
dwTo; // posio final do som
} MCI_PLAY_PARMS;

Na Listagem 8.4, temos o cdigo para reproduzir um som das duas


maneiras citadas acima.
// Dispositivo j inicializado com um som wave
// Seu identificador foi obtido e armazenado em mciDeviceID
// ...
// Reproduz som com envio da mensagem MM_MCINOTIFY para a funo callback
// hWnd, que ir processar a mensagem
MCI_PLAY_PARMS mciPlayParms;
mciPlayParms.dwCallback = (DWORD)hWnd;
mciSendCommand(mciDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)&mciPlayParms);
// Reproduz som sem envio da mensagem MM_MCINOTIFY
mciSendCommand(mciDeviceID, MCI_PLAY, NULL, NULL);
Listagem 8.4: Reproduzindo um som wave.

Quando no precisamos mais de algum dispositivo MCI, devemos


liberar o seu acesso. Para isso, usamos a mensagem de comando MCI_CLOSE. A
Listagem 8.5 demonstra como fechar um dispositivo MCI.
// Pra a reproduo do dispositivo e libera o mesmo
mciSendCommand(mciDeviceID, MCI_STOP, NULL, NULL);
mciSendCommand(mciDeviceID, MCI_CLOSE, NULL, NULL);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

188

Programao Windows: C e Win32 API com nfase em Multimdia

mciDeviceID = NULL;
Listagem 8.5: Fechando um dispositivo MCI.

Nota: quando o programa fechado, o sistema no libera


automaticamente os dispositivos MCI que estiverem abertos. Devemos,
portanto, incluir o cdigo da Listagem 8.5 no processamento da mensagem
WM_CLOSE, para evitarmos problemas de memria.

Reproduzindo msicas MIDI


Para a reproduo de msicas no formato MIDI, procedemos com as
mesmas etapas necessrias para reproduzir um som wave. A nica diferena
na configurao do dispositivo; ao invs de declararmos um dispositivo do tipo
waveaudio, declaramos o dispositivo como sequencer. A Listagem 8.6
configura um dispositivo MIDI (carregando o arquivo teste.mid) e logo em
seguida reproduz a msica.
// Armazena identificador do dispositivo
MCIDEVICEID mciDeviceIDmidi = NULL;
// ...
// Verifica se o dispositivo j foi inicializado
if(mciDeviceIDmidi == NULL)
{
// Configura o dispositivo
MCI_OPEN_PARMS mciOpenParms;
mciOpenParms.lpstrDeviceType = "sequencer"; // MIDI
mciOpenParms.lpstrElementName = "teste.mid";
// Abre o dispositivo
mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_ELEMENT,
(DWORD)&mciOpenParms);
// Obtm identificador do dispositivo
mciDeviceIDmidi = mciOpenParms.wDeviceID;
}
// Reproduz o dispositivo
mciSendCommand(mciDeviceIDmidi, MCI_PLAY, NULL, NULL);
Listagem 8.6: Configurando e reproduzindo dispositivo MIDI.

Nota: no possvel reproduzir duas ou mais msicas MIDI ao mesmo


tempo. Lembre-se de liberar o acesso ao dispositivo quando o mesmo no
for mais utilizado ou quando o programa for finalizado.
O arquivo prog08-1.cpp no CD-ROM contm o cdigo-fonte de um
programa que demonstra a reproduo de sons wave e msicas MIDI
conforme estudado nesse captulo.
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

Captulo 8 Sons e Timers

189

Timers
H momentos em que precisamos utilizar timers (temporizadores) em
nossos programas recursos que enviam mensagens WM_TIMER em um
determinado intervalo de tempo para serem processadas pela funo
WindowProc() (ou uma funo callback especfica para timers TimerProc(),
como veremos mais a frente). Um exemplo do uso de timers quando
queremos mostrar a hora atual no programa, sendo atualizada a cada segundo.
Seguiremos com esse exemplo para o estudo de timers.
Basicamente, o uso de timers feito da seguinte forma: cria-se um
timer com intervalo de n-milisegundos, executa-se um algoritmo a cada
intervalo do timer (ou seja, quando o timer envia a mensagem WM_TIMER ou
chama a funo TimerProc()) e o destri quando no for mais til.
Para criar um timer, usamos a funo SetTimer().
UINT_PTR SetTimer(
HWND hWnd,
hWnd, // identificador da janela associada ao timer
UINT_PTR nIDEvent,
nIDEvent, // identificador do timer
UINT uElapse,
uElapse, // intervalo do timer em milisegundos
TIMERPROC lpTimerFunc // funo callback de timers
);

O primeiro parmetro da funo recebe o identificador da janela que


ser associada ao timer, ou seja, a janela que receber a mensagem WM_TIMER
quando a contagem do timer se esgotar. O segundo parmetro recebe um
identificador do timer, que deve ser nico para cada timer diferente. O valor
desse parmetro um nmero inteiro; geralmente usamos um #define para
utilizar uma constante ao invs de enviar nmeros ao parmetro. No terceiro
parmetro fornecemos o intervalo (em milisegundos) que o timer envia a
mensagem WM_TIMER (ou que processado pela funo TimerProc()). O ltimo
parmetro da funo recebe um ponteiro para a funo callback que processa
os timers ou NULL para que o timer envie a mensagem WM_TIMER janela
associada. A funo retorna um valor diferente de zero quando sua execuo
bem-sucedida ou zero em caso negativo.
Para o exemplo do programa que mostra a hora na tela, criamos o
timer da seguinte maneira (Listagem 8.7):
#define IDT_TIMER1
#define IDT_TIMER2

1000 // Identificador do timer para WM_TIMER


1001 // Identificador do timer para a hora

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

190

Programao Windows: C e Win32 API com nfase em Multimdia

// Cria um timer que envia a mensagem WM_TIMER WindowProc() em um


// intervalo de 300 milisegundos ltimo parmetro recebeu NULL
SetTimer(hWnd, IDT_TIMER1, 300, NULL);
// O timer de hora ser processado em uma funo callback de timers,
// TimerProc(), a cada 1000 milisegundos, ou seja, a cada 1 segundo
SetTimer(hWnd, IDT_TIMER, 1000, (TIMERPROC)TimerProc);
Listagem 8.7: Criando um timer.

Assim que SetTimer() executada, um timer criado e ativado. No


exemplo acima, criamos dois timers: um que envia a mensagem WM_TIMER
WindowProc() em um intervalo de 300 milisegundos e outro que processado
pela funo TimerProc() a cada 1 segundo. Para o intervalo do timer IDT_TIMER1,
processamos a mensagem WM_TIMER; para o intervalo do timer IDT_TIMER2,
codificamos a funo callback TimerProc(). Veja a Listagem 8.8:
//-------------------------------------------------------------------------// WindowProc() -> Processa as mensagens enviadas para o programa
//-------------------------------------------------------------------------LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
lParam)
{
switch(uMsg)
{
// ...
case WM_TIMER: // Algum timer foi ativado
{
// Identificador do timer ativado IDT_TIMER1
if(wParam == IDT_TIMER1)
{
// Executa cdigo a cada intervalo do IDT_TIMER1 (300 milisegundos)
}
return(0);
} break;
// ...
}
// ...
}
//-------------------------------------------------------------------------// TimerProc() -> Processa os eventos de timer
//-------------------------------------------------------------------------VOID CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD
dwTime)
{
// Armazena hora atual
char cHora[9] = { 0 };
// Identificador do timer ativado IDT_TIMER2
if(idEvent == IDT_TIMER2)
{

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 8 Sons e Timers

191

// Obtm hora atual (a cada segundo) e mostra na rea cliente


_strtime(cHora);
HDC hDC = GetDC(hWnd);
TextOut(hDC, 8, 28, cHora, strlen(cHora));
ReleaseDC(hWnd, hDC);
}
}
Listagem 8.8: Intervalo dos timers.

Na funo WindowProc(), o parmetro WPARAM wParam informa o


identificador do timer que enviou a mensagem WM_TIMER. Verificamos se o
identificador IDT_TIMER1 em caso positivo, executamos um bloco de cdigo.
Repare que a funo callback TimerProc() muito semelhante
O parmetro HWND hWnd contm o identifcador da janela associada
ao timer. No parmetro UINT uMsg, a funo recebe a mensagem WM_TIMER. O
parmetro UINT_PTR idEvent contm o identificador do timer que foi ativado e
DWORD dwTime indica os milisegundos que se passaram desde que o sistema foi
iniciado. Note ainda que a funo no retorna valor.
WindowProc().

Dentro da funo TimerProc(), verificamos se o timer ativado


IDT_TIMER2 (timer para atualizar a hora) em caso positivo, chamamos a funo
_strtime() para que ela converta a hora atual para uma string, que
armazenada em cHora. Em seguida, mostramos o contedo dessa string na rea
cliente atravs da TextOut().
Nota: o intervalo dos timers nem sempre regular ( uma aproximao do
que foi especificado em UINT uElapse), pois a mensagem WM_TIMER (de
prioridade baixa) enviada para a fila de mensagens do programa somente
quando no houver mensagens de prioridade alta na fila.
Depois que os timers so utilizados e no so mais necessrios (ou
quando o programa fechado), devemos destru-los, usando a funo
KillTimer().
BOOL KillTimer(
HWND hWnd,
hWnd, // identificador da janela
UINT_PTR uIDEvent // identificador do timer
);

A funo recebe o identificador da janela (hWnd) a qual o timer est


associado e o identificador do timer que ser destrudo (uIDEvent). A funo

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

192

Programao Windows: C e Win32 API com nfase em Multimdia

retorna um valor diferente de zero quando bem sucedida ou zero caso


contrrio.
No exemplo do horrio, podemos destruir os dois timers (IDT_TIMER1 e
atravs do cdigo da Listagem 8.9.

IDT_TIMER2)

//-------------------------------------------------------------------------// WindowProc() -> Processa as mensagens enviadas para o programa


//-------------------------------------------------------------------------LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
lParam)
{
switch(uMsg)
{
// ...
case WM_CLOSE: // Janela foi fechada
{
// Desativa/destri os timers (para que no haja falta de recursos)
KillTimer(hWnd, IDT_TIMER1);
KillTimer(hWnd, IDT_TIMER2);
// Destri a janela
DestroyWindow(hWnd);
return(0);
} break;
// ...
}
// ...
}
Listagem 8.9: Destruindo timers.

Nota: poderamos ter chamado a funo KillTimer() em outro lugar do


programa (por exemplo, na mensagem WM_COMMAND, quando um boto
pressionado), mas lembre-se que sempre devemos destruir os timers
quando o programa fechado; caso contrrio, os recursos de timers
continuaro na memria, mesmo aps finalizado o programa.
Nesse captulo, vimos como trabalhar com sons wave e msicas MIDI.
Vimos tambm como utilizar timers, atravs da criao de um programa
(arquivo prog08-2.cpp no CD-ROM) que mostra a hora atual na tela, atualizando
a informao a cada segundo. No captulo a seguir, estudaremos a manipulao
de arquivos atravs da Win32 API e como trabalhar com o registro do
Windows.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 9 Arquivos e Registro

193

Captulo 9 Arquivos e Registro


A grande maioria dos programas Windows utilizam algum meio para
armazenar e recuperar informaes; esse meio, em geral, so arquivos gravados
em disco (j trabalhamos com arquivos de imagem no formato .bmp em um
captulo anterior e nesse veremos como trabalhar com arquivos de texto). O
modo bsico de como a Win32 API trabalha com arquivos bem semelhante
com o ANSI-C, embora possua muito mais opes (tornando-se um sistema
mais complexo).
Para armazenar configuraes de um programa (como verso do
programa instalado, nome do usurio que registrou o programa, entre outras
informaes), at o lanamento do Windows 95, o normal era utilizar arquivos
com extenso .ini (de initialization, ou inicializao). Hoje em dia, esse tipo de
arquivo praticamente foi extinto, e agora o comum utilizar o Registro do
Windows, que ser o segundo assunto desse captulo.
Nota: nesse captulo, ser adotada uma abordagem diferente em relao
aos outros. As explicaes sero mais resumidas, dando nfase ao cdigo
utiizado para as aes bsicas de arquivos, tais como abrir, fechar e excluir
arquivos e escrita/leitura. Ainda, parte do cdigo contm algumas funes
que no foram vistas no decorrer da leitura por exemplo, a criao de
botes na rea cliente. Adotei esse mtodo nesse captulo pois acredito que
voc, leitor, j esteja com um bom conhecimento sobre programao
Win32 API e que esteja apto a estudar certas funes mais a fundo atravs
de outras fontes de referncia.

Criando e abrindo arquivos


Os arquivos podem ser criados e abertos utilizando uma funo da
Win32 API, chamada CreateFile().
HANDLE CreateFile(
LPCTSTR lpFileName,
lpFileName, // nome do arquivo
DWORD dwDesiredAccess,
dwDesiredAccess, // modo de acesso
DWORD dwShareMode,
dwShareMode, // modo de compartilhamento
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
lpSecurityAttributes, // atributos de segurana
DWORD dwCreationDisposition,
dwCreationDisposition, // como criar/sobrepor o arquivo
DWORD dwFlagsAndAttributes,
dwFlagsAndAttributes, // atributos do arquivo
HANDLE hTemplateFile // identificador de arquivo temporrio
);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

194

Programao Windows: C e Win32 API com nfase em Multimdia

A Listagem 9.1 contm um exemplo de como abrir o arquivo dados.txt


para escrita/leitura, que encontra-se no mesmo diretrio que o programa, no
compartilhando seu acesso (ou seja, enquanto o identificador do arquivo
retornado pela funo estiver sendo usado, nenhum outro programa ter
acesso ao arquivo). Se o arquivo no existir, a funo criar o arquivo
(OPEN_ALWAYS) especificado em lpFileName. O identificador para trabalhar com o
arquivo retornado pela funo (no exemplo, salvo em HANDLE hFile).
HANDLE hFile = NULL;
// Se arquivo ainda no foi aberto
if(hFile == NULL)
{
// Abre/cria arquivo
hFile = CreateFile("dados.txt", GENERIC_READ |
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

GENERIC_WRITE, 0, NULL,

// Verifica se identificador do arquivo invlido


if(hFile == INVALID_HANDLE_VALUE)
MessageBox(hWnd, "Erro ao abrir/criar arquivo.", "Erro!", MB_ICONERROR |
MB_OK);
else // Identificador vlido, arquivo aberto
{
MessageBox(hWnd, "Arquivo aberto/criado.", "Aviso!", MB_ICONINFORMATION
| MB_OK);
SendMessage(hWnd,
WM_SETTEXT,
(WPARAM)0,
(LPARAM)"Arquivo
aberto/criado.");
// Cria boto na rea cliente
HWND hWndBotao = CreateWindowEx(WS_EX_CLIENTEDGE, "BUTTON", "Clique
aqui!", WS_CHILD | WS_VISIBLE, 10, 10, 100, 30, hWnd, (HMENU)IDC_BOTAO,
NULL, NULL);
}
}
Listagem 9.1: Criando e abrindo arquivos, criao de boto na rea cliente.

Note que, se o arquivo vlido, o trecho acima cria um boto (HWND


na rea cliente do programa com a ID IDC_BOTAO. Clicando nesse
boto (Figura 9.1), o programa enviar uma mensagem WM_COMMAND para a fila de
mensagens com a ID do boto no parmetro LOWORD(wParam) e com o
identificador do boto no parmetro lParam.

hWndBotao)

Dica: a definio de objetos como botes e caixa de texto parecida com


as macros utilizadas em arquivos de recursos (Captulo 3), porm
utilizamos a funo CreateWindowEx(), que retorna um identificador de
janela (visto que tais objetos so considerados janelas pelo Windows).

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 9 Arquivos e Registro

195

Figura 9.1: Boto criado na rea cliente aps arquivo ser aberto/criado.

Fechando arquivos
Para fechar um arquivo, liberando a memria do seu identificador (e o
acesso ao arquivo para outros programas, dependendo do modo de
compartilhamento em que o mesmo foi aberto), chamamos a funo
CloseHandle(), que recebe o identificador do arquivo como parmetro.
BOOL CloseHandle(
HANDLE hObject // identificador do arquivo
);

A Listagem 9.2 mostra o uso da funo para fechar o arquivo aberto


anteriormente.
// Se o arquivo est aberto, fecha
if(hFile)
{
CloseHandle(hFile);
hFile = NULL;
MessageBox(hWnd, "Arquivo fechado.", "Aviso", MB_ICONINFORMATION | MB_OK);
}
Listagem 9.2: Fechando arquivos.

Escrita em arquivos
Para escrever alguma informao no arquivo aberto, utilizamos a
funo WriteFile().

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

196

Programao Windows: C e Win32 API com nfase em Multimdia

BOOL WriteFile(
HANDLE hFile,
hFile, // identificador do arquivo
LPCVOID lpBuffer,
lpBuffer, // buffer de dados
DWORD nNumberOfBytesToWrite,
nNumberOfBytesToWrite, // nmero de bytes a serem escritos
LPDWORD lpNumberOfBytesWritten,
lpNumberOfBytesWritten, // nmero de bytes escritos
LPOVERLAPPED lpOverlapped // buffer de sobreescrita
);

O trecho de cdigo da Listagem 9.3 escreve o contedo contido na


caixa de texto do programa no arquivo dados.txt, que foi aberto na Listagem
9.1.
if(hFile != INVALID_HANDLE_VALUE) // Arquivo est aberto
{
// Obtm quantidade de caracteres da caixa de texto
int tam = GetWindowTextLength(hWndTexto);
// Obtm contedo da caixa de texto, alocando memria para os dados
// (alocao no modo Windows)
LPSTR lpstrBuffer = (LPSTR)GlobalAlloc(GPTR, tam + 1);
GetWindowText(hWndTexto, lpstrBuffer, tam + 1);
// Armazena quantos bytes foram escritos no arquivo
DWORD dwBytesEscritos;
// Modifica posio do arquivo para o incio
SetFilePointer(hFile, NULL, NULL, FILE_BEGIN);
// Grava contedo da caixa de texto no arquivo
WriteFile(hFile, lpstrBuffer, tam, &dwBytesEscritos, NULL);
// Define fim do arquivo
SetEndOfFile(hFile);
// Libera memria dos dados
GlobalFree(lpstrBuffer);
MessageBox(hWnd,
"Contedo
escrito
no
arquivo.",
"Erro!",
MB_ICONINFORMATION | MB_OK);
}
else // Arquivo no foi aberto
MessageBox(hWnd, "Erro ao escrever no arquivo.", "Erro!", MB_ICONERROR |
MB_OK);
Listagem 9.3: Escrita em arquivos.

Nesse trecho de cdigo, modificamos a posio do arquivo para o


incio (SetFilePointer()), indicando que os dados sero gravados a partir do
incio do arquivo. Depois de gravarmos o contedo da caixa de texto no
arquivo (WriteFile()), definimos o fim do arquivo (SetEndOfFile()), para que
qualquer outro dado que estava no arquivo, antes da sua modificao, seja
descartado, no havendo assim duplicao de dados.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 9 Arquivos e Registro

197

Leitura em arquivos
Depois de aberto o arquivo, podemos acessar seu contedo atravs da
funo ReadFile().
BOOL ReadFile(
HANDLE hFile,
hFile, // identificador do arquivo
LPVOID lpBuffer,
lpBuffer, // buffer de dados
DWORD nNumberOfBytesToRead,
nNumberOfBytesToRead, // nmero de bytes a serem lidos
LPDWORD lpNumberOfBytesRead,
lpNumberOfBytesRead, // nmero de bytes lidos
LPOVERLAPPED lpOverlapped // buffer de sobreescrita
);

O trecho de cdigo da Listagem 9.4 processa a mensagem WM_COMMAND,


que enviada quando o boto criado na Listagem 9.1 pressionado pelo
usurio. O cdigo destri o boto da rea cliente e em seguida cria uma caixa
de texto, onde o contedo do arquivo lido copiado.
// ...
case WM_COMMAND: // Item do menu, tecla de atalho ou controle ativado
{
// Verifica bit menos significativo de wParam (IDs)
switch(LOWORD(wParam))
{
// ...
case IDC_BOTAO:
{
// Destri boto
if(hWndBotao)
{
DestroyWindow(hWndBotao);
hWndBotao = NULL;
}
// Cria caixa de texto para o usurio entrar com os dados
hWndTexto = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_CHILD |
WS_VISIBLE | ES_MULTILINE | WS_HSCROLL | WS_VSCROLL, 0, 0, 312, 194, hWnd,
NULL, NULL, NULL);
if(hFile != INVALID_HANDLE_VALUE) // Arquivo est aberto
{
// Obtm tamanho do arquivo
int tam = GetFileSize(hFile, NULL);
// Obtm contedo do arquivo, alocando memria para os dados
// (alocao no modo Windows)
LPSTR lpstrBuffer = (LPSTR)GlobalAlloc(GPTR, tam + 1);
// Armazena quantos bytes foram escritos no arquivo
DWORD dwBytesEscritos;
// L contedo do arquivo
ReadFile(hFile, lpstrBuffer, tam, &dwBytesEscritos, NULL);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

198

Programao Windows: C e Win32 API com nfase em Multimdia


// Coloca contedo do arquivo na caixa de texto
SetWindowText(hWndTexto, lpstrBuffer);
// Libera memria dos dados
GlobalFree(lpstrBuffer);

MessageBox(hWnd,
"Contedo
MB_ICONINFORMATION | MB_OK);

lido

do

arquivo.",

"Aviso!",

// Define cursor na caixa de texto


SetFocus(hWndTexto);
}
else // Arquivo no foi aberto
MessageBox(hWnd, "Erro ao ler o arquivo.", "Erro!", MB_ICONERROR |
MB_OK);
} break;
}
// ...
return(0);
} break;
// ...
Listagem 9.4: Leitura em arquivos, processamento de boto e criao de caixa de texto.

Excluindo arquivos
Para apagar um arquivo em disco, usamos a funo DeleteFile(). Essa
funo recebe o nome do arquivo que ser excludo, retornando um valor
diferente de zero caso o arquivo seja apagado ou zero caso contrrio.
BOOL DeleteFile(
LPCTSTR lpFileName // nome do arquivo a ser excludo
);

A funo pode falhar quando o arquivo a ser excludo no existe ou


quando o mesmo est sendo utilizado pelo sistema, inclusive quando abrimos
o arquivo pelo programa no o fechamos atravs da funo CloseHandle().
Na Listagem 9.5, vemos um exemplo de como deletar o arquivo
dados.txt o qual espera-se estar localizado no mesmo diretrio do programa
executvel.
// Tenta excluir arquivo e mostra resultado para usurio
if(DeleteFile("dados.txt"))
MessageBox(hWnd, "Arquivo excludo.", "Aviso!", MB_ICONINFORMATION |
MB_OK);
else
MessageBox(hWnd, "Arquivo no pode ser excludo.", "Erro!", MB_ICONERROR |
MB_OK);
Listagem 9.5: Excluindo arquivos.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 9 Arquivos e Registro

199

No CD-ROM, voc encontra o arquivo prog09-1.cpp, que contm o


cdigo-fonte completo dos trechos listados nesse captulo. O programa possui
um menu para abrir/criar um arquivo chamado dados.txt, salvar alteraes,
fechar o arquivo, excluir o arquivo e sair do programa. A Figura 9.2 mostra o
programa em execuo, com o arquivo j aberto (repare na caixa de texto, que
foi criada em tempo real no processo do clique do boto IDC_BOTAO).

Figura 9.2: Programa-exemplo em execuo com caixa de texto.

Registro do Windows
O registro do Windows um banco de dados onde so armazenadas
informaes de configurao sobre o ambiente do sistema, dispensando o uso
de arquivos de inicializao (.ini) que eram comuns em sistemas Windows 16bit (at a verso 3.11). No registro, por exemplo, possvel armazenar as
preferncias de diferentes usurios, fazendo com que cada usurio trabalhe em
um ambiente personalizado (escolha de temas, configurao de teclado, entre
outros). Ainda, podemos associar determinado tipo de arquivo a ser aberto
com um determinado programa, como tambm podemos incluir um programa
para ser executado assim que o Windows inicializado (ou seja, assim que um
usurio faa login no sistema).
Podemos verificar o contedo e a estrutura do registro do Windows
atravs do programa regedit.exe, localizado no diretrio onde o Windows foi
instalado. O registro trabalha com uma hierarquia de chaves (keys), subchaves
(subkeys) e valores (values), conforme exemplo na Figura 9.3.
E-Book gratuito disponvel em http://www.tupinihon.com
2006-2012, Andr Kishimoto

200

Programao Windows: C e Win32 API com nfase em Multimdia

Figura 9.3: Hierarquia-exemplo do registro do Windows.

Dica: podemos fazer uma analogia com o Windows Explorer: as chaves


so os diretrios/pastas, as subchaves so os subdiretrios/subpastas e os
valores so os arquivos, inclusive pelo modo como o registro apresentado
ao usurio atravs do programa regedit.exe.
A estrutura do registro possui 5 chaves-razes comuns nos sistemas
Windows 32-bit (Figura 9.4), que so utilizadas conforme a Tabela 9.1.
Chave
HKEY_CLASSES_ROOT

HKEY_CURRENT_USER

HKEY_LOCAL_MACHINE
HKEY_USERS
HKEY_CURRENT_CONFIG

Descrio
Parte da chave HKEY_LOCAL_MACHINE, contm
definies de tipos de documentos,
associao de arquivos e interface de
comando (shell).
Ligao com HKEY_USERS, corresponde s
configuraes do usurio atual. Usurios
padres que no possuem configuraes
especficas utilizam as informaes de
.DEFAULT (da chave HKEY_USERS)
Armazena configuraes de hardware,
protocolos de rede e classes de software.
Utilizado para armazenar as preferncias de
cada usurio.
Configurao selecionada na subchave de
configurao de HKEY_LOCAL_MACHINE.
Tabela 9.1: Descrio das 5 principais chaves-razes.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 9 Arquivos e Registro

201

Figura 9.4: Chaves-razes do registro.

Abrindo e fechando chaves do registro


Em primeiro lugar, para trabalharmos com o registro do Windows,
devemos definir uma varivel/identificador do tipo HKEY. atravs desse
identificador que iremos fazer a manipulao do registro.
Definido o identificador (por exemplo, HKEY hKey = NULL;), podemos
comear a trabalhar com o registro. Vamos estudar primeiro como abrir o
registro, ou melhor, como obter acesso ao registro utilizando a funo
RegOpenKeyEx().
LONG RegOpenKeyEx(
HKEY hKey,
hKey, // chave-raz ou identificador da chave de registro
LPCTSTR lpSubKey,
lpSubKey, // subchave
DWORD ulOptions,
ulOptions, // reservado (deve receber zero)
REGSAM samDesired,
samDesired, // modo de acesso
PHKEY phkResult // ponteiro para identificador da chave de registro
);

Essa funo abre uma chave e uma subchave do registro, identificada


em HKEY hKey (que pode receber uma das chaves-raz da Tabela 9.1 ou um
identificador de chave) e LPCTSTR lpSubKey, respectivamente. O modo de acesso
geralmente recebe KEY_ALL_ACCESS (permisso para ler e escrever), KEY_READ
(permisso para ler) ou KEY_WRITE (permisso para escrever). No ltimo
parmetro (PHKEY phkResult) enviamos um ponteiro para o identificador que
criamos anteriormente o qual ser utilizado para manipular o registro.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

202

Programao Windows: C e Win32 API com nfase em Multimdia

Dica: todas as funes de registro retornam um valor LONG. Quando as


funes forem executadas corretamente, o retorno ERROR_SUCCESS.
Para fecharmos o acesso ao registro, usamos a funo
que recebe apenas o identificador da chave que foi aberta.

RegCloseKey(),

LONG RegCloseKey(
HKEY hKey // identificador da chave de registro
);

Nota: lembre-se que, dependendo das modificaes no registro do


Windows, o sistema pode no funcionar corretamente. A modificao das
informaes contidas no registro do Windows no aconselhada; o risco e
responsabilidade de modific-lo fica totalmente ao leitor.
O arquivo prog09-2.cpp do CD-ROM contm o cdigo-fonte de um
programa que cria e edita chaves/valores no registro, alm de fazer a leitura de
valores e excluso tanto das chaves quanto de valores. O cdigo da Listagem
9.6 contm parte do cdigo-fonte; no caso, utilizado para obter acesso ao
registro, ler um valor de uma subchave e fechar o registro.
HKEY hKey = NULL; // Identificador do registro aberto (incluindo subchaves)
LONG lResultado = 0; // Verifica se ao com o registro foi bem sucedida
// Abre o registro para leitura, a partir da chave-raz HKEY_LOCAL_MACHINE
// e na subchave SOFTWARE\___prog09-2
// Salvando o identificador desse local em hKey
lResultado = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\___prog09-2", 0,
KEY_READ, &hKey);
// Registro aberto com sucesso
if(lResultado == ERROR_SUCCESS)
{
// Obtm o valor "(Padro)" da subchave
// (PS: Padro no caso uma string NULL, ou seja, "")
// Salva o valor em byteValor e
// a quantidade de caracteres lidos em dwTamanho
BYTE byteValor[255];
DWORD dwTamanho;
RegQueryValueEx(hKey, "", NULL, NULL, byteValor, &dwTamanho);
// Mostra valor obtido na tela
MessageBox(hWnd,
(LPCSTR)byteValor,
MB_ICONINFORMATION | MB_OK);

"Valor

obtido

no

// Fecha o registro, usando o identificador hKey


RegCloseKey(hKey);
}
else // Registro no pde ser aberto

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

registro:",

Captulo 9 Arquivos e Registro


MessageBox(hWnd, "Erro ao tentar abrir chave do registro.",
MB_ICONERROR | MB_OK);
Listagem 9.6: Acessando o registro, lendo valores e finalizando o acesso.

Note

que,

no trecho de

HKEY_LOCAL_MACHINE\SOFTWARE\___prog09-2
MessageBox()

203

"Erro!",

cdigo acima, caso a subchave


no exista, o programa mostrar o

do else.

Criando e excluindo chaves do registro


Para criarmos uma chave (subchave) no registro, utilizamos a funo
Quando a chave indicada nessa funo j existe, a mesma
aberta, como em RegOpenKeyEx().
RegCreateKeyEx().

LONG RegCreateKeyEx(
HKEY hKey
hKey, // chave-raz ou identificador da chave de registro
LPCTSTR lpSubKey,
lpSubKey, // subchave
DWORD Reserved,
Reserved, // reservado (deve receber zero)
LPTSTR lpClass,
lpClass, // classe da chave (recebe string null)
DWORD dwOptions,
dwOptions, // opes especiais
REGSAM samDesired,
samDesired, // modo de acesso
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
lpSecurityAttributes, // herana de processos (null)
PHKEY phkResult,
phkResult, // identificador da chave de registro
LPDWORD lpdwDisposition // ao (cria nova chave ou abre chave existente)
);

Os parmetros dessa funo so parecidos com os da funo


RegOpenKeyEx().
Em
DWORD
dwOptions,
especificamos
o
valor
REG_OPTION_NON_VOLATILE para que as informaes gravadas no registro sejam
armazenadas mesmo que o computador seja desligado. A funo modifica o
valor da varivel enviada no parmetro LPDWORD lpdwDisposition, que indica se a
chave indicada j existe (REG_OPENED_EXISTING_KEY) ou no (REG_CREATED_NEW_KEY).
A Listagem 9.7 cria uma nova subchave no registro e tambm modifica
o valor padro (Padro)da subchave e adiciona um novo valor valor1
subchave.
HKEY hKey = NULL; // Identificador do registro aberto (incluindo subchaves)
LONG lResultado = 0; // Verifica se ao com o registro foi bem sucedida
// Cria uma subchave no registro para escrita, a partir da chave-raz
// HKEY_LOCAL_MACHINE, na subchave SOFTWARE
// Salvando o identificador do novo local,
// (HKEY_LOCAL_MACHINE\SOFTWARE\___prog09-2) em hKey
// Em dwAcao, armazenado se a subchave indicada j existia ou no
DWORD dwAcao;
lResultado = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\___prog09-2", 0,
NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwAcao);

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

204

Programao Windows: C e Win32 API com nfase em Multimdia

// Ao no registro realizada com sucesso


if(lResultado == ERROR_SUCCESS)
{
// Subchave no existia, criou uma nova
if(dwAcao == REG_CREATED_NEW_KEY)
MessageBox(...); // chave nova
// Subchave j existia, apenas abriu a mesma
if(dwAcao == REG_OPENED_EXISTING_KEY)
MessageBox(...); // chave existente
// Muda o valor "(Padro)" da subchave, sendo do tipo REG_SZ
// (string terminada com \0)
lResultado = RegSetValueEx(hKey, "", 0, REG_SZ, (BYTE *)"{Adicionado por
prog09-2}\0", 26);
if(lResultado == ERROR_SUCCESS)
MessageBox(...); // modificado
else
MessageBox(...); // erro
// Cria um novo valor, "valor1" dentro da subchave
// HKEY_LOCAL_MACHINE\SOFTWARE\___prog09-2
// O novo valor do tipo nmero de 32-bit (REG_DWORD)
// Note que se o valor "valor1" j existisse, o comando abaixo iria apenas
// modificar seu valor, como feito na chamada funo acima
// (que modificou o valor "(Padro)")
DWORD dwValor = 2005;
lResultado = RegSetValueEx(hKey, "valor1", 0, REG_DWORD, (BYTE *)&dwValor,
sizeof(DWORD));
if(lResultado == ERROR_SUCCESS)
MessageBox(...); // modificado
else
MessageBox(...); // erro
// Fecha o registro, usando o identificador hKey
RegCloseKey(hKey);
}
else // Chave no registro no pde ser criado
MessageBox(hWnd, "Erro ao tentar criar chave no registro.",
MB_ICONERROR | MB_OK);
Listagem 9.7: Criando uma chave no registro e modificando valores.

"Erro!",

Para excluirmos uma chave do registro, utilizamos RegDeleteKey().


LONG RegDeleteKey(
HKEY hKey,
hKey, // chave-raz ou identificador da chave de registro
LPCTSTR lpSubKey // subchave que ser excluda
);

O primeiro parmetro da funo recebe uma das chaves-raz da Tabela


9.1 ou o identificador da chave de registro; o segundo parmetro recebe o
nome da subchave (que ser excluda).

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 9 Arquivos e Registro

205

O trecho de cdigo da Listagem 9.8 exclui a subchave criada pela


Listagem 9.7.
HKEY hKey = NULL; // Identificador do registro aberto (incluindo subchaves)
LONG lResultado = 0; // Verifica se ao com o registro foi bem sucedida
// Abre o registro para escrita, a partir da chave-raiz HKEY_LOCAL_MACHINE
// e na subchave SOFTWARE\___prog09-2
// Salvando o identificador desse local em hKey
lResultado = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\___prog09-2", 0,
KEY_WRITE, &hKey);
// Registro aberto com sucesso
if(lResultado == ERROR_SUCCESS)
{
// Exclui a subchave HKEY_LOCAL_MACHINE\SOFTWARE\___prog09-2
// e verifica se foi excluda ou no
lResultado = RegDeleteKey(HKEY_LOCAL_MACHINE, "SOFTWARE\\___prog09-2");
if(lResultado == ERROR_SUCCESS)
MessageBox(...); // excluda
else
MessageBox(...); // erro
// Fecha o registro, usando o identificador hKey
RegCloseKey(hKey);
}
else // Registro no pde ser aberto
MessageBox(hWnd, "Erro ao tentar abrir chave do registro.", "Erro!",
MB_ICONERROR | MB_OK);
Listagem 9.8: Excluindo uma subchave do registro.

Gravando, obtendo e excluindo valores do registro


Para gravar informaes nos valores do registro, podemos utilizar a
funo RegSetValueEx(); seu uso j foi visto na Listagem 9.7.
LONG RegSetValueEx(
HKEY hKey,
hKey, // identificador da chave de registro
LPCTSTR lpValueName,
lpValueName, // nome do valor ( para valor padro de uma chave)
DWORD Reserved,
Reserved, // reservado (deve receber zero)
DWORD dwType,
dwType, // tipo do valor (REG_SZ, REG_DWORD, REG_BINARY, ...)
CONST BYTE *lpData,
lpData, // dados do valor
DWORD cbData // tamanho dos dados do valor
);

Lembre-se que antes de gravar um valor, necessrio que o acesso ao


registro tenha sido efetuado, inclusive onde o valor ser gravado (chave ou
subchave). Caso o nome do valor j exista, a funo modifica o valor; caso
ainda no exista, um novo valor criado no registro.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

206

Programao Windows: C e Win32 API com nfase em Multimdia

Para obter informaes dos valores do registro, utilizamos a funo


tambm j vista, na Listagem 9.6.

RegQueryValueEx(),

LONG RegQueryValueEx(
HKEY hKey,
hKey, // chave-raz ou identificador da chave de registro
LPCTSTR lpValueName,
lpValueName, // nome do valor ( para valor padro de uma chave)
LPDWORD lpReserved,
lpReserved, // reservado (deve receber zero)
LPDWORD lpType,
lpType, // tipo do valor (REG_SZ, REG_DWORD, REG_BINARY, ...)
LPBYTE lpData,
lpData, // ponteiro para os dados do valor
LPDWORD lpcbData // ponteiro para o tamanho dos dados do valor
);

O contedo obtido do valor do registro armazenado na varivel que


enviada para o parmetro LPBYTE lpData da funo. O tamanho do contedo do
valor armazenado na varivel enviada para o parmetro LPDWORD lpcbData. Na
Listagem 9.6, o contedo foi armazenado na varivel byteValor e o tamanho,
em dwTamanho.
A excluso de valores do registro feita atravs da funo
que simplesmente recebe o identificador da chave de registro
que contm o local onde se encontra o valor a ser excludo e o nome do valor.

RegDeleteValue(),

LONG RegDeleteValue(
HKEY hKey,
hKey, // identificador da chave de registro
LPCTSTR lpValueName // nome do valor que ser excludo
);

Um exemplo de como excluir um valor do registro pode ser visto na


Listagem 9.9.
// ... Abre registro para escrita
// Registro aberto com sucesso
if(lResultado == ERROR_SUCCESS)
{
// Exclui o valor "valor1" e verifica se foi excludo ou no
lResultado = RegDeleteValue(hKey, "valor1");
if(lResultado == ERROR_SUCCESS)
MessageBox(...); // excludo
else
MessageBox(...); // erro
// Fecha o registro, usando o identificador hKey
RegCloseKey(hKey);
}
else // Registro no pde ser aberto
MessageBox(hWnd, "Erro ao tentar abrir chave do registro.", "Erro!",
MB_ICONERROR | MB_OK);
Listagem 9.9: Excluindo um valor do registro.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Captulo 9 Arquivos e Registro

207

Conforme j mencionado, voc pode encontar o arquivo prog09-2.cpp


no CD-ROM que acompanha o livro, contendo a implementao de um
programa que cria uma subchave no registro, modifica seu valor padro,
adiciona um novo valor, l o valor, exclui o valor adicionado e a subchave
criada. A Figura 9.5 mostra o registro do Windows aps o programa criar a
subchave e modificar os valores.

Figura 9.5: Registro do Windows aps execuo do programa-exemplo.

Nesse captulo, aprendemos como utilizar arquivos e como manipular


informaes no registro do Windows, para que configuraes e preferncias do
usurio sejam salvas e recuperadas futuramente. Com o trmino desse captulo,
chegamos ao final do livro, restando agora algumas palavras e consideraes
finais que me direciono a voc, caro leitor.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

208

Programao Windows: C e Win32 API com nfase em Multimdia

Captulo 10 Consideraes Finais


Espero que, aps a leitura desse livro, voc tenha obtido um timo
conhecimento sobre como funciona a programao Windows, e que a
experincia do aprendizado tenha sido agradvel (embora muitas vezes acredito
ter sido cansativa).
Meu objetivo nesse livro foi de introduzir a programao Windows
com uma nfase em multimdia, e, portanto, diversos assuntos no foram
abordados pelo livro (mesmo os livros de mais de 1000 pginas no
conseguem abordar a vasta quantidade de tpicos da programao Windows).
Caso tenha interesse em outros assuntos (tais como DLLs, controles e caixas
de dilogos comuns, threads e atoms), sugiro pesquisar as fontes informadas na
Bibliografia. Aps a leitura desse livro, acredito que voc j esteja apto em
pesquisar outras fontes de referncia sem que as informaes paream
obscuras.
Conforme j mencionado na Introduo, a idia de escrever esse livro
surgiu em 2002, mas somente em 2003 que comecei a trabalhar nele. Foram
necessrios cerca de 15 meses para que o objetivo inicial do meu trabalho fosse
concludo; nesse perodo, fiquei sem escrever durante alguns meses, pois tive
outros compromissos, como faculdade, famlia e projetos que acabaram
atrasando a finalizao do livro. Foi um trabalho duro, mas que valeu a pena,
um desafio pessoal que consegui atingir. Mas... esse desafio no pra por aqui!
Nesse tempo entre o incio e o trmino do livro, tive a idia de estender o livro
para o desenvolvimento de jogos, que ser uma continuao desse trabalho.
Agradeo a todos os leitores pelo interesse no meu trabalho e dou-lhes
meus parabns em ter aprendido a programao Windows e pelo autodidatismo de cada um. Continuem assim!
Caso queira entrar em contato comigo, envie um e-mail para:
kishimoto@tupinihon.com

Ou visite o site:
http://www.tupinihon.com

- Andr Kishimoto

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Bibliografia

209

Bibliografia
CALVERT, Charles. Teach Yourself Windows Programming in 21 Days.
Indianopolis: Sams. 1993.
CHANDLER, Damon; FTSCH, Michael. Windows 2000 Graphics API Black
Book. Scottsdale: The Coriolis Group. 2001.
LAMOTHE, Andr. Tricks Of The Windows Game Programming Gurus
Fundamentals Of 2D And 3D Game Programming. Indianopolis: Sams. 1999.
LAMOTHE, Andr. Windows Game Programming for Dummies. New York:
Hungry Minds. 1998.
MORRISON, Michael; WEEMS, Randy. Windows 95 Game Developers Guide
Using the Game SDK. Indianopolis: Sams, 1996.
MSDN. Microsoft Developers Network. Disponvel em: http://www.msdn.com.
PAMBOUKIAN, Srgio Vicente D. Desenvolvendo Interfaces Grficas Utilizando
Win32 API e Motif 2a Edio. So Paulo: Scortecci. 2003.
PETZOLD, Charles. Programming Windows, Fifth Edition. Redmond: Microsoft
Press. 1998.
SIMON, Richard J. Windows NT Win32 API SuperBible. Corte Madera: The
Waite Group. 1997.
STEVENS, Roger T. Computer Graphics Dictionary. Hingham: Charles River
Media. 2002.
YOUNG, Michael J. Introduction To Graphics Programming For Windows 95
Vector Graphics Using C++. Chestnut Hill: Academic Press. 1996.
YUAN, Feng. Windows Graphics Programming Win32 GDI and DirectDraw.
Upper Saddle River: Prentice Hall. 2001.

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

210

Programao Windows: C e Win32 API com nfase em Multimdia

ndice Remissivo
reas
De corte
Validando
Arquivos
.INI
Abrindo
Criando
Escrita em
Excluindo
Fechando
Leitura em
Atoms

86
91
193
193
193
195
198
195
197
208

Bitmaps
Carregando
151
Classificao
148
Compatvel
155
DDB
150
De recursos
152
Definio
148
Device-dependent bitmap
(ver DDB)
Device-independent bitmap
(ver DIB)
DIB
150
DIB Section
164
Invertidos
161
Luminance
168
Manipulando bits
166
Mostrando
157
Obtendo informaes de 153
C++
Caixas de dilogo
Comuns
Criar
Destruindo
Estilos
Mensagens
Canvas
Charles Simonyi
Classe
Da Janela
Registrando

7
208
63, 74
74
64
75
83
6
15
20

Classes
Clipping region
(ver rea de corte)
Comentrios
Controles
Barra de rolagem
Botes
Caixas de edio
Genricos
Labels
(ver Textos estticos)
Lista de seleo
Textbox
(ver Caixas de edio)
Textos estticos
Cores
Combinao
Inverso de
Paleta de
Preenchimento
RGB
Cursores
Carregar
De Recursos
Curvas de Bzier

6
8
72
66
66
69
71
65, 73
128
143
149
144
99
18
45
133

Delphi
Device context
De memria
De vdeo
Obter identificador
Off-screen
(ver DC de memria)
Particular
Pblico

Fontes
Form

103
24

154
85
85, 87
157
83

GDI
82
Graphics Device Interface
(ver GDI)

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

ndice
Handle
(ver Identificador)
Hello World

MS-DOS
MSDN

5
13

Nomenclatura
Notao hngara

6
6

Objetos GDI
Bitmaps
Canetas
Elipses
Excluindo
Linhas curvas
Obtendo informaes de
Pincis Padres
Pincis
Polgonos
Ponto
Retngulos
Retas
Selecionando
Textos

148
125
140
93
133
94
19
127
142
123
137
130
91
95

Platform SDK
Portabilidade

5
9

Identificador
cones
Carregar
De Recursos

10
17
42

Janelas
Criando
Destruir
Estilos de
Janela-pai
Mostrar
No-retangulares
Java

21
32
24
74
24
177
7

Macros
9
Main()
9
MCI
(ver Sons)
Mensagens
Caixa de
12
Caixas de dilogo
75
Enviando
38
Envio de
5, 27
Gerando WM_PAINT 89
Loop de
25
Processamento de
5
Processando
28
Traduzir
27
WM_PAINT
85
Menus
Definindo
54
Destruindo
58
Hot keys
56
Menu-pai
55
Modificando itens do
62
Teclas de atalho
54
Usando
57
MFC
5
Microsoft Foundation Class
(ver MFC)
MIDI
(ver Sons)
Mouse
118, 121

Recursos
Arquivos de
Bitmaps
Caixas de dilogo
Cursores
IDs
cones
Menus
Sons
Teclas de atalho
Verso do programa
Regies
Criando
De corte
Definio
Desenhando
Operaes com
Registro
Abrindo chaves do
Criando chaves do
Excluindo chaves do
Excluindo valores do

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

41
46
63
45
42
42
54
46
54
46
170
175
170
171
173
201
203
204
206

211

212

Programao Windows: C e Win32 API com nfase em Multimdia

Fechando chaves do
Gravando valore do
Hierarquia
Obtendo valores do
Sons
MCI
Msicas MIDI
Reproduo de mltiplos
Reproduzindo
Windows Multimedia

202
205
199
206
183
188
185
181
182

Teclado
Teclas aceleradoras
(ver Teclas virtuais)
Teclas virtuais
Textos
Escrevendo
Modificando atributos
Threads
Timers
Criar
Destruir
Funo callback
Processar

111, 117

189
191
190
190

Visual Basic

Wave
(ver Sons)
Win32 API
Windows
Windows.h
WinMain()

5
5
9
9

26
95
100
208

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto

Pgina em branco

Programao Windows:
C e Win32 API com nfase em Multimdia
Copyright 2006-2012, Andr Kishimoto
kishimoto@tupinihon.com
http://www.tupinihon.com

E-Book gratuito disponvel em http://www.tupinihon.com


2006-2012, Andr Kishimoto