Informática Numaboa - Tutoriais e Programação

Cap.V - Nossa primeira janela

Seg

17

Dez

2007


19:40

  • Imprimir
(4 votos, média 4.75 de 5) 


Nível Intermediário

Masm32+RadASM

Capítulo V: Nossa primeira janela

Escrito por: ^A|An M0r3N0^
Conselheiro: RedH@wk
Tradução: ~Uglinho~
O presente texto foi escrito para fins educacionais e de pesquisa e é de livre distribuição contanto que se preserve o conteúdo e os direitos do autor.

Nossa primeira janela

Chegou o momento de criar aplicações com janelas e adicionar botões, imagens e outros controles.

Primeiro criaremos uma janela feita com APIs puras, como mostra o vídeo. Preste muita atenção:

Vídeo 1
prog009.exe

vovo Para assistir ao vídeo, faça o download de prog009.exe.

Biblioteca kernel32.lib GetModuleHandle, NULL

Esta função devolve o handle do módulo ou instância do programa. Todos os programas que utilizam janelas utilizam esta função, então guardamos o valor devolvido para EAX numa variável que, neste caso, se chama Hinstance:

mov Hinstance,eax

Depois precisamos utilizar a estrutura WNDCLASSEX que contém toda informação requerida para criar nossa janela. Colocamos essa informação com a instrução MOV e, para utilizá-la, declaramos a etiqueta wc como WNDCLASSEX desta maneira:

wc WNDCLASSEX <>

Se buscarmos ajuda no Win32 Programmer's Reference para saber sobre cada elemento da estrutura, ela mostrará o seguinte:

typedef struct _WNDCLASSEX { // wc UINT cbSize; UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; HICON hIconSm; } WNDCLASSEX;
  1. cbSize - é aqui que especificamos o tamanho da estrutura. Quando não sabemos o tamanho, utilizamos o operador SIZEOF:
    mov wc.cbSize, SIZEOF WNDCLASSEX
  2. style - especificamos o estilo da nossa janela. Há vários tipos (ver a ajuda antes mencionada) como, por exemplo, os que utilizamos: CS_HREDRAW e CS_VREDRAW. Se quisermos combiná-los podemos utilizar a instrução OR:
    mov wc.style, CS_HREDRAW or CS_VREDRAW
  3. lpfnWndProc - definimos o endereço da etiqueta dos procedimentos:
    mov wc.lpfnWndProc, offset WinProC
  4. cbClsExtra - especificamos o número de bytes extras para localizar a estrutura da janela, mas nós não a utilizamos e movemos o valor zero ou NULL:
    mov wc.cbClsExtra,NULL
  5. cbClsExtra - especificamos o número de bytes extras para localizar a instância da janela. Como no anterior, não precisaremos dele e movemos o valor zero.
    mov wc.cbWndExtra,NULL
  6. hInstance - especificamos o manipulador (handle) da instância do módulo:
    push Hinstance pop wc.hInstance
  7. hIcon - especificamos o manipulador do ícone. Para isto utilizamos a função LoadIcon:
    invoke LoadIcon,Hinstance,IDI_APPLICATION mov wc.hIcon,eax
  8. hCursor - especificamos o manipulador de cursor. Para isto utilizamos a função LoadCursor:
    invoke LoadCursor,NULL,IDC_ARROW mov wc.hCursor,eax
  9. hbrBackground - especificamos a cor de fundo da nossa janela:
    mov wc.hbrBackground, COLOR_BTNFACE + 1
  10. lpszMenuName - especificamos o manipulador do Menu.
    mov wc.lpszMenuName,NULL
  11. lpszClassName - definimos o endereço da etiqueta onde se encontra o nome (ASCII) da classe da janela.
    mov wc.lpszClassName,offset Classname
  12. hIconSm - especificamos o manipulador de ícone pequeno.

Isto serviu para personalizar a janelinha que vamos criar. Agora falta registrar sua classe. Para isto precisamos da função RegisterClassEx:

invoke RegisterClassEx,addr wc

Ao colocar wc, registramos todas as mudanças que fizemos nos elementos da estrutura. Isto é muito importante porque, se não o fizermos, nossa janela não abrirá.

Já definimos as características da nossa janela e sua classe também foi registrada. Agora falta criar a janela. O faremos com a seguinte função:

Biblioteca kernel32.lib CreateWindowEx, NULL, addr Classname, addr Appname, \ WS_OVERLAPPEDWINDOW, 150,210,00,200,NULL,NULL,Hinstance,NULL

Esta função da API é a encarregada de criar nossa janela e devolve o manipulador no registrador EAX. É recomendável guardá-lo em uma variável para, quando quisermos nos referir a ele, o identificarmos por meio desta variável. Esta função não só serve para isto, também pode criar controles de janelas chamadas de "filhas", como botões, campos de edição, testos estáticos, caixas de lista, etc. É por isto que vamos analisar o papel de cada parâmetro desta função:

HWND CreateWindowEx( DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam );
  1. dwExStyle - especificamos o estilo extra da nossa janela extendida, como por exemplo:
    WS_EX_TOPMOST - Cria uma janela por cima de todas. WS_EX_TRANSPARENT - Cria uma janela transparente. WS_EX_TOOLWINDOW - cria uma janela de ferramenta.
    Se quiserem comprovar, vocês podem colocar estes estilos no primeiro parâmetro e a função ficaria desta maneira:
    Invoke CreateWindowEx, WS_EX_TOPMOST, addr Classname... Se quiser saber mais sobre estilos veja o Win32 Programmer's Reference.
  2. lpClassName - definimos o endereço da etiqueta onde se encontra o nome (ASCII) da classe da janela.
  3. lpWindowName - definimos o endereço da etiqueta onde se encontra o nome da janela. Se não existir, pode-se usar o NULL.
  4. dwStyle - neste parâmetro especificamos a aparência da janela. Nós colocamos WS_OVERLAPPEDWINDOW porque combina vários estilos de aparência como:
    WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX e WS_MAXIMIZEBOX
    Se quisermos uma janela que só tenha o botão maximizar habilitado, nossa função ficaria assim:
    CreateWindowEx, NULL, addr Classname, addr Appname, WS_SYSMENU or WS_MAXIMIZEBOX,...
    Não esquecer que, se quisermos combinar estilos, usamos a instrução OR.
  5. X - especifica a coordenada da posição horizontal da janela cliente.
  6. Y - especifica a coordenada da posição vertical da janela cliente. Observemos as imagens:
Posição da janela
Fig. 1

Quando criamos controles de janela filha, como por exemplo um botão, o alcance das coordenadas estará dentro da janela mãe:

Janela filha
Fig. 2

  1. nWidth - especificamos a largura do controle que criamos.
  2. nHeight - especificamos a altura do controle que criamos.
  3. Dimensões
    Fig. 3
  4. hWndParent - identificamos a janela mãe, se existir, quando criamos controles de janelas filhas. Este parâmetro é utilizado, por exemplo, se quisermos criar um botão numa janela mãe (Fig.3). Devemos especificar o manipulador da nossa janela e, como recordamos, nós o guardamos na variável hwnd.
  5. hMenu - especificamos o manipulador do menu. Este parâmetro só é utilizado com controles (janelas filhas). Por exemplo, se quisermos por um menu no botão da Fig.3, usamos este parâmetro, mas não quando criamos janelas do tipo WNDCLASSEX, porque estas têm um elemento específico que faz isto.
  6. hInstance - especificamos a instância do módulo associado à janela.
  7. lpParam - este ponteiro é usado quando criamos janelas MDI. Se não as utilizamos, colocamos o valor NULL.

.while TRUE invoke GetMessage,addr msg,NULL,NULL,NULL .break .if !eax invoke TranslateMessage,addr msg invoke DispatchMessage,addr msg .endw

Como expliquei no vídeo, este loop é executando até que se feche a janela. Nesta parte do código vimos um novo bloqueio, o .break. Este bloqueio é de interrupção e serve para terminar o loop se a condição for cumprida. Suas sintaxe é:

.break condicão ; se a condição for cumprida, sairá do loop

No nosso programa a condição é .if !EAX, que compara se EAX é igual a zero. Ela é equivalente a .if EAX == 0.

Outro ponto importante do loop é que ele sempre está pegando as mensagens do programa. Quando nós fechamos a janela, a função GetMessage devolverá a EAX o valor 0, o que provoca a saída do loop para terminar o programa.

Depois vem o procedimento da janela. É aí que usamos as mensagens para chamar funções:

WinProC proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM .if uMsg == WM_DESTROY invoke PostQuitMessage,NULL .else invoke DefWindowProc,hWnd,uMsg,wParam,lParam ret .endif xor eax,eax ret WinProC endp

Tudo o que queremos que nosso programa faça, nós colocamos aqui. Como diz o vídeo, este é o cérebro do programa, o responsável pela colocação de diferentes funções na nossa janela. O parâmetro uMsg é que contém o valor das mensagens; a função DefWindowProc recicla todas as mensagens que não utilizamos.

WM_DESTROY - Esta mensagem é enviada quando a janela é destruída ou quando desaparece do desktop.


Daremos alguns exemplos de janelas, mas primeiro vamos criar um novo modelo a partir do que existe no RadAsm. Ele será modificado para que se veja melhor:

Vídeo 2
Plantilla02.exe

vovo Para assistir ao vídeo, faça o download de plantilla02.exe.

Se repararmos no modelo que vimos, foi criada uma função com o propósito de carregar os elementos da estrutura wc:

invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT

Não tem nada de novo, já vimos tudo isto no capítulo III quando criamos funções. Nós carregamos os parâmetros das funções da API para carregar os elementos da estrutura.

O que é novo no código é como se declara as variáveis locais. Este tipo de variável só pode ser usado desde o início do procedimento até o final dele, como mostra a seguinte imagem:

Escopo
Fig. 4

Sua sintaxe é a seguinte: LOCAL Etiqueta : tipo de Variável/Estrutura

Outra coisa importante que observamos são estes tipos de variáveis:

HWND
UINT
WPARAM
LPARAM
HINSTANCE
LPSTR

Não pensem que são novas variáveis. Elas têm nomes diferentes, mas são do mesmo tipo e são DWORD. Se quiserem comprovar, procurem no arquivo windows.inc que vão encontrar algo como:

HWND EQU DWORD

O operador EQU significa equivalente ou igualdade, em outras palavras HWND é igual a DWORD.

Já analisamos todo o código para criar nossa janela, agora criaremos um par de janelas com botões e campos de edição. Também adicionaremos funções aos botões.

Para começar faremos esta janela:

Janela 1
Fig. 4

Depois esta:

Janela 2
Fig. 5

Solução da Fig. 4

Vídeo 3
prog010.exe

vovo Para assistir ao vídeo, faça o download de prog010.exe.

No vídeo encontramos a mensagem WM_CREATE. Esta mensagem se envia antes de mostrar a janela e, como seu nome indica, serve para criar novas janelas filhas, mas também pode ser usada para outros fins.

.ELSEIF uMsg==WM_CREATE invoke CreateWindowEx,NULL,addr Class_boton,addr Texto_boton01,\ WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\ 10,75,100,25,hWnd,NULL,hInstance,NULL mov hwnd_botao01,eax

Já sabemos para que serve cada parâmetro desta função. O novo é que encontramos uma nova classe de janela filha e também carregamos o 9º parâmetro.

A classe nova da janela filha é:

Class_boton db "button",0

Com esta classe se cria um botão. No 9º parâmetro colocamos hWnd porque contém o handle da janela mãe e serve para criar outros controles (janelas filhas) na janela principal.

Se quisermos criar vários botões, declaramos apenas uma vez a classe da janela. Outra coisa importante é que, quando formos criar o controle, se formos fazer algo com ele, será necessário guardar seu handle em uma variável como no meu caso:

mov hwnd_botao01,eax

O conteúdo do registrador EAX é movido para hwnd_botao01 para que, no futuro, possamos identificá-lo e utilizá-lo.

Logo depois encontramos outro tipo de mensagem, WM_COMMAND. Esta outra se envia quando tocamos ou quando clicamos um item ou controle. O manipulador do objeto tocado ou clicado se encontra em lParam. Também existe wParam, mas nele se encontram a ID e o código de notificação. Isto veremos mais adiante quando entrarmos em janelas com diálogo.

.elseif uMsg== WM_COMMAND mov edx,lParam

Então movemos o handle que contém lParam para EDX porque, como se sabe, não se pode comparar variáveis com variáveis.

.if edx == hwnd_botao01 .elseif edx == hwnd_botao02 .endif

Com estas comprovações comparamos todos os manipuladores dos nossos botões para que, quando se pressionar só um, só este será igual. Logo, para estes botões serão atribuídas diferentes funções.

if edx == hwnd_boton01 invoke MessageBox,hWnd,........ . elseif edx== hwnd_boton02 invoke DestroyWindow,hWnd .endif

Aqui damos para cada botão uma função. Neste caso o botão 01 mostrará uma mensagem e o botão 02 fechará o programa.

Nota: se você agragar uma nova mensagem, façca-o com .elseif uMsg==MINHA_MENSAGEM.

Biblioteca kernel32.lib DestroyWindow,hWnd

Com esta função destruímos a janela mãe.


Seguimos com o programa da Fig 5.

Vídeo
prog011.exe

vovo Para assistir ao vídeo, faça o download de prog011.exe.

Encontramos 2 funções da API novas:

Biblioteca kernel32.lib GetWindowText, hwnd_edit01,addr buffer,100

Esta função pega o texto das janelas e tem 3 parâmetros. São eles:

  • hWnd - identificamos a janela colocando o manipulador de controle.
  • lpString - endereço da memória onde o texto será armazenado.
  • nMaxCount - número máximo de caracteres que serão guardados.

Biblioteca kernel32.lib SetWindowText,hwnd_edit02,addr buffer

Com esta função enviamos o texto para as janelas. Ela tem 2 parâmetros:

  • hWnd - onde identificamos a janela colocando o manipulador do controle.
  • Lpsz - o endereço da memória onde se encontra o texto.

Nos dois programas definimos ícones diferentes para as janelas. A seção .const serve para colocar constantes, que são apenas para leitura. Quando declaramos um objeto que está nos recursos, é importante colocar a mesma ID que definimos no recurso.

Sintaxe:

Etiqueta equ valor

Nos exemplos:

app equ 100 ;programa Fig.4 Icono equ 100 ;programa Fig.5

Nos damos conta de que a etiqueta não importa, o que serve na verdade é o valor 100 que é a ID de nosso ícone no recurso.

Utilizando a mensagem WM_CLOSE: Fonte prog012

Vamos criar uma janela que, quando Image for clicado, a seguinte mensagem seja mostrada:

Mensagem
Fig. 6

Com a condição de que se pressionamos o botão Sim/Yes para fechar e Não/No para não fechar a janela, no modelo que temos devemos adicionar esta menssagem:

WM_CLOSE

Esta mensagem se envia quando a janela deve ser fechada mas ainda está no desktop. Depois desta mensagem segue:

WM_DESTROY

para que a mensagem da figura Fig.06 seja mostrada. Chamamos a função MessageBox desta maneira:

invoke MessageBox,hWnd,addr MsgSair,addr TitSair, MB_YESNO+MB_ICONINFORMATION

Depois, para comparar qual botão foi pressionado, chamamos o bloqueio .if e nosso código ficará assim:

.elseif uMsg == WM_CLOSE invoke MessageBox,hWnd,addr MsgSair,addr TitSair, MB_YESNO + MB_ICONINFORMATION .if eax == IDYES invoke DestroyWindow,hWnd .endif

Com isto comprovamos qual botão que foi pressionado.


Exercícios

  1. Crie uma janela do tamanho do seu desktop.
  2. Crie uma janela com 5 botões. Cada botão deve mostrar uma mensagem diferente.
  3. Crie um programa igual a este:

    Exercício

    Nota: ao pressionar o botão Enviar, o título da janela da janela deve ser enviado. Não esquecer de determinar o handle da janela mãe para a função SetwindowText. O ícone pode ser qualquer um.

Lembrando

Não esquecer de perguntar na lista MASM32-RadASM. As soluções destes exercícios serão enviados para a lista dentro de uma semana. Vocês também podem enviar suas prórias soluções.

Se tiverem dúvidas, sugestões ou outros, faça-as na lista de discussão.

O autor pode ser contactado

eMail: O endereço de e-mail address está sendo protegido de spambots. Você precisa ativar o JavaScript enabled para vê-lo. ou O endereço de e-mail address está sendo protegido de spambots. Você precisa ativar o JavaScript enabled para vê-lo.

Lista de discussão MASM32-RadASM

http://groups.google.es/group/MASM32-RadASM

www


Novembro-2006
Copyright(c) 2005-2006 RVLCN



Recado da vó vovo

Aqui está o código fonte dos exercícios deste tutorial:



Вадим Логофет семьяфутляр для кистей для макияжаооо полигон официальный сайтresearch Ventatranslator english to arabicкупить резиновоелобановский харьков