USANDO RECURSOS |
|
Somos felizes possuidores de uma classe janela, o que nos permite criar janelas
com a nossa grife. A janela que produzimos no tutorial anterior estava peladinha
da silva, faltavam muitos recursos que costumam acompanhar as janelas.
O presente tutorial tem justamente este propósito: discutir os RECURSOS.
Como exemplo, vamos colocar um bitmap numa janela.
|
| PROJETO BITMAP NA JANELA |
|
Como sempre, nosso primeiro passo é planejar nosso programa:
- O que são recursos
- Como criar arquivos de recursos
- Criar o arquivo de recursos que contenha o gráfico
- Criar o código fonte do programa teste.
- O código fonte completo (download do tutorial
completo)
- NumaBoa com Recursos
|
| 1. O que são recursos
|
|
Recursos são dados binários que um compilador de recursos ou
o programador adiciona ao arquivo executável de um aplicativo. Recursos
podem ser do tipo padrão ou do tipo definido. Os dados de um recurso padrão
descrevem ícones, cursores, menus, caixas de diálogo, gráficos
do tipo .bmp e .emf, fontes, tabelas de teclas de atalho, tabela de mensagens,
tabela de strings ou versão. Um recurso definido pelo aplicativo, também
chamado de recurso personalizado (custom resource), contém quaisquer dados
requeridos por um aplicativo específico.
Os recursos são descritos em arquivos texto próprios, chamados
arquivos de recurso, geralmente com a extensão .rc. Estes arquivos precisam
ser compilados (no menu do MASM [Project / Compile Resource File]) e depois são
combinados com o arquivo de código fonte durante o estágio de link.
O produto final é um arquivo executável que contém instruções
e recursos.
|
| 2. Como criar arquivos
de recursos |
|
Podemos usar qualquer editor de texto para escrever arquivos de recursos. O
texto é composto por frases que descrevem a aparência e os atributos
dos recursos desejados para um determinado programa. Os recursos possuem uma linguagem
própria, a Resource Script Language. Conhecendo um mínimo desta
linguagem é o suficiente para podermos trabalhar (o help do Resource Workshop
da Borland é uma referência muito boa).
Existem editores de recursos que facilitam muito o trabalho por oferecerem
uma plataforma de trabalho visual. Editores de recursos geralmente estão
incluídos nos pacotes de compiladores como Visual C++, Borland C++, etc.
Você pode usar o excelente Resource
Builder, da SiComponents, o ResourceStudio da Symantec (encontrei a versão
1.0 para download no site do hutch) ou o tradicionalíssimo Resource
Workshop da Borland (a versão 4.5 de 1994 funciona muito bem!).
|
| 3. Criar o arquivo de
recursos |
|
Use o programa gráfico da sua preferência para criar um gráfico
ou escolha um da sua preferência. Salve-o ou transfira-o para o diretório
de trabalho deste tutorial. O arquivo de recursos deve ficar no mesmo diretório
do arquivo de código fonte. O gráfico que preparei para este tutorial
recebeu o nome de "bits.bmp" e é o que se vê abaixo:
| Gráfico em formato bmp (bits.bmp) |
 |
A diretiva para indicar um recurso bitmap é a seguinte:
IDentificador BITMAP [tipo de carregamento] [opção de memória]
NomeDoArquivo
- Identificador é o ID do recurso, indicado por um número. O ID
será usado quando quisermos usar este recurso no programa (Obrigatório).
- BITMAP é uma palavra chave para indicar o tipo de recurso (Obrigatório).
- Tipo de carregamento é opcional. Indica se queremos que o bitmap seja
previamente carregado (PRELOAD) ou apenas seja carregado quando solicitado (LOADONCALL).
O default é LOADONCALL.
- Opção de memória indica como o recurso deve ser carregado
na memória. Pode ser descartável para livrar espaço de memória
(DISCARDABLE), ficar fixo num endereço de memória (FIXED), ser modificado
após o carregamento (IMPURE), pode ser deslocado na memória (MOVEABLE),
precisa permanecer na memória (NONDISCARDABLE), não é modificado
após o carregamento (PURE). O default é MOVEABLE e DISCARDABLE.
- NomeDoArquivo é o nome do bitmap
Podemos resumir nosso arquivo RSRC.RC numa linha que contenha apenas o ID,
a palavra chave BITMAP e o nome do arquivo. O restante deixamos como default.
Abra um editor de texto (pode ser o GUN do MASM que você encontra em [Tools
/ TheGUN Text Editor]) e digite a linha abaixo:
760 BITMAP "bits.bmp"
Você pode usar qualquer número para o ID, contanto que não
seja o mesmo usado por outro recurso. Salve o arquivo com o nome de "RSRC.RC"
no mesmo diretório onde estará o código fonte do nosso programa
teste. Por enquanto é só.
|
| 4. Criar o programa
teste |
|
Vamos criar uma janela que conterá o bitmap do recurso, portanto podemos
partir do modelo "Janelinha NumaBoa" que criamos no tutorial anterior.
|
| 4.a. O modelo |
|
.386
.MODEL FLAT,STDCALL
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
gerenteJanela proto :DWORD, :DWORD, :DWORD, :DWORD
.DATA?
mInstancia DWORD ?
linhaComando DWORD ?
.DATA
NomeClasse db "JanelaNua",0
TituloJanela db "Janelinha NumaBoa",0
.CODE
inicio:
invoke GetModuleHandle, NULL
mov mInstancia, eax
invoke GetCommandLine
mov linhaComando, eax
invoke gerenteJanela, mInstancia, NULL, linhaComando,
SW_SHOWDEFAULT
invoke ExitProcess,0
gerenteJanela proc mInst:DWORD, mInstAnt:DWORD, linhaCmd:DWORD,
Mostra:DWORD
LOCAL ej:WNDCLASSEX
LOCAL mJanela:HWND
LOCAL malote:MSG
mov ej.cbSize, SIZEOF WNDCLASSEX
mov ej.style, CS_HREDRAW or CS_VREDRAW
mov ej.lpfnWndProc, OFFSET gerenteMensagem
mov ej.cbClsExtra, NULL
mov ej.cbWndExtra, NULL
push mInst
pop ej.hInstance
invoke LoadIcon, NULL, IDI_WINLOGO
mov ej.hIcon, eax
mov ej.hIconSm, eax
invoke LoadCursor, NULL, IDC_ARROW
mov ej.hCursor, eax
mov ej.hbrBackground, COLOR_WINDOW+1
mov ej.lpszMenuName, NULL
mov ej.lpszClassName, OFFSET NomeClasse
invoke RegisterClassEx, ADDR ej
invoke CreateWindowEx, NULL, ADDR NomeClasse, ADDR TituloJanela,
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, NULL, NULL, mInst, NULL
mov mJanela,eax
invoke ShowWindow, mJanela, SW_SHOWNORMAL
invoke UpdateWindow, mJanela
.WHILE TRUE
invoke GetMessage, ADDR malote, NULL, 0, 0
.BREAK .IF (eax < 1)
invoke TranslateMessage, ADDR malote
invoke DispatchMessage, ADDR malote
.ENDW
mov eax, malote.wParam
ret
gerenteJanela endp
gerenteMensagem proc hWnd:HWND, uMsg:UINT, wParam:WPARAM,
lParam:LPARAM
.IF uMsg == WM_CREATE
.ELSEIF uMsg == WM_SIZE
.ELSEIF uMsg == WM_PAINT
.ELSEIF uMsg == WM_COMMAND
.ELSEIF uMsg == WM_CLOSE
.ELSEIF uMsg==WM_DESTROY
invoke PostQuitMessage, NULL
xor eax,eax
ret
.ENDIF
invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
gerenteMensagem endp
end inicio
Vamos mudar o título da janela para "NumaBoa com Recursos"
só para identificá-la melhor:
.DATA
NomeClasse db "JanelaNua",0
TituloJanela db "NumaBoa com Recursos",0
|
| 4.a. A área do bitmap |
|
Como queremos que o gráfico seja mostrado assim que a janela aparecer
na tela, precisamos gerenciar a mensagem WM_CREATE que é enviada ao gerenteMensagem
assim que a janela é criada. Primeiramente vamos criar uma área
dentro da janela principal onde o bitmap deve ser mostrado. Essa área especial
nada mais é que um controle, ou seja, uma janela especial. Já
sabemos que, para criar uma janela/controle, precisamos de uma classe registrada
que servirá como modelo. No Windows existem classes predefinidas para controles:
BUTTON, COMBOBOX, EDIT, LISTBOX, SCROLLBAR e STATIC. Usaremos a STATIC porque
não esperamos adicionar nenhuma funcionalidade ao nosso bitmap. A primeira
provicência, então, é inicializar uma variável com
o nome da classe na seção .DATA:
.DATA
NomeClasse db "JanelaNua",0
TituloJanela db "Janelinha NumaBoa",0
ClasseAreaBMP db "STATIC",0
Recapitulando a função CreateWindowEx temos:
HWND CreateWindowEx(
DWORD dwExStyle, // estilo especial de janela
LPCTSTR lpClassName, // ponteiro para a classe registrada
LPCTSTR lpWindowName, // pointeiro para o nome da janela: NULL
DWORD dwStyle, // estilo da janela
int x, // posição horizontal da janela
int y, // posição vertical da janela
int nWidth, // largura da janela
int nHeight, // altura da janela
HWND hWndParent, // manipulador da janela-mãe ou proprietário
da janela
HMENU hMenu, // manipulador do menu ou identificador da janela-filha
HINSTANCE hInstance, // manipulador da instância do aplicativo
LPVOID lpParam // ponteiro para dados de criação da janela
);
- dwExStyle: não usaremos um estilo especial - NULL.
- lpClassName: o nome da classe está na variável ClasseAreaBMP
- seu endereço será ADDR ClasseAreaBMP.
- lpWindowName: a janela não precisa de título - usaremos
NULL.
- dwStyle: a composição do estilo será "Estilo
Janela (WS) Filha" + "Estilo Janela (WS) Visível" + "Controle
Estático (SS) com Bitmap" que é indicado com WS_CHILD or WS_VISIBLE
or SS_BITMAP.
- x e y: a posição horizontal e vertical do canto
superior esquerdo da janela do controle dentro da janela-mãe - indicamos
ambos como 20 pixels.
- nWidth e nHeight: a largura e a altura da janela em pixels -
indicamos temporariamente como 10. O porque do temporário será explicado
logo adiante (4.4. Preparando a pintura).
- hWndParent: o manipulador da janela-mãe - no nosso exemplo é
o parâmetro hWnd do procedimento gerenteMensagem.
- hMenu: não existe menu no controle, portanto NULL.
- hInstance: o manipulador do módulo, mInstancia.
- lpParam: não há dados na criação da janela
- NULL
Tudo em riba para podermos incluir a chamada à função
que criará o controle com a área que deve conter o bitmap:
gerenteMensagem proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg == WM_CREATE
invoke CreateWindowEx, NULL, ADDR ClasseAreaBMP, NULL,
WS_CHILD or WS_VISIBLE or SS_BITMAP, 20, 20, 10, 10,
hWnd, NULL,
mInstancia, NULL
...
.ELSEIF ...
A função CreateWindowEx retorna o valor do manipulador da janela
em EAX. Precisaremos deste valor logo adiante, portanto, criaremos uma variável
local e a inicializamos com o valor de retorno:
gerenteMensagem proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL mAreaBMP: DWORD
.IF uMsg == WM_CREATE
invoke CreateWindowEx, NULL, ADDR AreaBitmap, NULL,
WS_CHILD or WS_VISIBLE or SS_BITMAP, 20, 20, 10, 10, hWnd, NULL,
mInstancia, NULL
mov mAreaBMP, eax
...
.ELSEIF ...
|
| 4.b. Localizando o bitmap |
|
Nosso bitmap está nos recursos e tem o identificador 760. Agora precisamos
obter um manipulador para o bitmap para que possamos acessá-lo. Usamos
a função LoadBitmap:
HBITMAP LoadBitmap(
HINSTANCE hInstance, // manipulador da instância do aplicativo
LPCTSTR lpBitmapName // endereço do nome do recurso bitmap
);
Da mesma forma que acima, precisamos de uma variável local que receba
o manipulador:
gerenteMensagem proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL mAreaBMP: DWORD
LOCAL mBMP: DWORD
.IF uMsg == WM_CREATE
invoke CreateWindowEx, NULL, ADDR AreaBitmap, NULL,
WS_CHILD or WS_VISIBLE or SS_BITMAP, 20, 20, 10, 10, hWnd, NULL,
mInstancia, NULL
mov mAreaBMP, eax
invoke LoadBitmap, mInstancia, 760
mov mBMP, eax
...
.ELSEIF ...
|
| 4.c. Pintando o bitmap |
|
O sistema possui um "pintor" de plantão que pode ser acionado
sempre que necessário. Basta enviar uma mensagem com os dados necessários
para que ele possa trabalhar. A função SendMessage envia a mensagem
especificada para uma ou mais janelas. Esta função chama o gerente
de mensagens do(s) destinatário(s) e não retorna enquanto o pedido
não for integralmente realizado.
LRESULT SendMessage(
HWND hWnd, // manipulador da janela destino
UINT Msg, // mensagem a ser enviada
WPARAM wParam, // primeiro parâmetro da mensagem
LPARAM lParam // segundo parâmetro da mensagem
);
- hWnd: nossa janela destino é a janela do controle com a área
que foi preparada para receber o bitmap - mAreaBMP
- Msg: a mensagem é dirigida a um controle estático (STatic
control Message), ou seja, do tipo STM_ alguma coisa. As mensagens que
existem são STM_GETICON, STM_SETICON, STM_GETIMAGE e STM_SETIMAGE. Obviamente
é da STM_SETIMAGE que estamos precisando.
- wParam: o primeiro parâmetro de uma mensagem do tipo STM_SETIMAGE
refere-se ao tipo de imagem e pode ser IMAGE_BITMAP, IMAGE_CURSOR, IMAGE_ENHMETAFILE
e IMAGE_ICON. O tipo da nossa imagem é IMAGE_BITMAP.
- lParam: o segundo parâmetro da mensagem STM_SETIMAGE refere-se
ao manipulador da imagem. No nosso caso, mBMP.
Vamos enviar nossa mensagem com:
gerenteMensagem proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL mAreaBMP: DWORD
LOCAL mBMP: DWORD
.IF uMsg == WM_CREATE
invoke CreateWindowEx, NULL, ADDR AreaBitmap, NULL,
WS_CHILD or WS_VISIBLE or SS_BITMAP, 20, 20, 10, 10, hWnd, NULL,
mInstancia, NULL
mov mAreaBMP, eax
invoke LoadBitmap, mInstancia, 760
mov mBMP, eax
invoke SendMessage, mAreaBMP, STM_SETIMAGE, IMAGE_BITMAP,
mBMP
.ELSEIF ...
Você ainda se lembra de que dimensionamos nosso controle para ter 10
x 10 pixels? Nosso gráfico tem 255 x 185 pixels. Vai faltar pixel para
abrigar o gráfico inteiro - problema do "pintor" de plantão.
Como enviamos as coordenadas da posição do controle estático,
o "pintor" vai transferindo a sequência de pixels que ele encontrar
nos recursos e "estica" o controle para fazer espaço para o gráfico.
Tão simples assim... mas precisamos saber disso para que o gráfico
não avance sobre outros controles desformatando nosso layout.
|
| 5. O código fonte
completo |
|
Para o código fonte completo, além do arquivo de recursos e o
bitmap do exemplo, faça o download do Tutorial Recursos
(tutNB04.zip 75 Kb).
|
| 6. NumaBoa com Recursos
|
A obra de arte ;-)

|
| ATÉLOGO |
|
O resumo do atélogo:
- O que são recursos: arquivos de recursos com dados
de menus, ícones, gráficos, etc
- Como criar arquivos de recursos: sintaxe e programas
de edição
- Criar o arquivo de recursos: programando um script
de recursos
- O programa teste: criando a janela que irá
conter um bitmap do recurso
- Controles: janelas especiais com classes predefinidas
- Localizando o bitmap: como obter um manipulador para
o bitmap
- "Pintando" o bitmap: enviando uma mensagem
para convocar o "pintor" de plantão
- O código fonte completo: faça o download
do tutorial e estude offline
|