Informática Numaboa - Tutoriais e Programação
Cap.V - Nossa primeira janela
Seg 17 Dez 2007 19:40 |
- Detalhes
- Categoria: MASM + RadASM
- Atualização: Quinta, 18 Junho 2009 11:23
- Autor: Alan Moreno
- Acessos: 9596
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:
Para assistir ao vídeo, faça o download de prog009.exe.
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:
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:
Se buscarmos ajuda no Win32 Programmer's Reference para saber sobre cada elemento da estrutura, ela mostrará o seguinte:
- cbSize - é aqui que especificamos o tamanho da estrutura. Quando não sabemos o tamanho, utilizamos o operador SIZEOF:
mov wc.cbSize, SIZEOF WNDCLASSEX - 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 - lpfnWndProc - definimos o endereço da etiqueta dos procedimentos:
mov wc.lpfnWndProc, offset WinProC - 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 - 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 - hInstance - especificamos o manipulador (handle) da instância do módulo:
push Hinstance pop wc.hInstance - hIcon - especificamos o manipulador do ícone. Para isto utilizamos a função LoadIcon:
invoke LoadIcon,Hinstance,IDI_APPLICATION mov wc.hIcon,eax - hCursor - especificamos o manipulador de cursor. Para isto utilizamos a função LoadCursor:
invoke LoadCursor,NULL,IDC_ARROW mov wc.hCursor,eax - hbrBackground - especificamos a cor de fundo da nossa janela:
mov wc.hbrBackground, COLOR_BTNFACE + 1 - lpszMenuName - especificamos o manipulador do Menu.
mov wc.lpszMenuName,NULL - lpszClassName - definimos o endereço da etiqueta onde se encontra o nome (ASCII) da classe da janela.
mov wc.lpszClassName,offset Classname - 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:
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:
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:
- 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. - lpClassName - definimos o endereço da etiqueta onde se encontra o nome (ASCII) da classe da janela.
- lpWindowName - definimos o endereço da etiqueta onde se encontra o nome da janela. Se não existir, pode-se usar o NULL.
- 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. - X - especifica a coordenada da posição horizontal da janela cliente.
- Y - especifica a coordenada da posição vertical da janela cliente. Observemos as imagens:
Quando criamos controles de janela filha, como por exemplo um botão, o alcance das coordenadas estará dentro da janela mãe:
- nWidth - especificamos a largura do controle que criamos.
- nHeight - especificamos a altura do controle que criamos.
- 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.
- 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.
- hInstance - especificamos a instância do módulo associado à janela.
- lpParam - este ponteiro é usado quando criamos janelas MDI. Se não as utilizamos, colocamos o valor NULL.
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 é:
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:
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:
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:
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:
Sua sintaxe é a seguinte:
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:
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:
Depois esta:
Solução da Fig. 4
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.
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 é:
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:
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.
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.
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.
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.
Com esta função destruímos a janela mãe.
Seguimos com o programa da Fig 5.
Para assistir ao vídeo, faça o download de prog011.exe.
Encontramos 2 funções da API novas:
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.
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:
Nos exemplos:
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 for clicado, a seguinte mensagem seja mostrada:
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:
Esta mensagem se envia quando a janela deve ser fechada mas ainda está no desktop. Depois desta mensagem segue:
para que a mensagem da figura Fig.06 seja mostrada. Chamamos a função MessageBox desta maneira:
Depois, para comparar qual botão foi pressionado, chamamos o bloqueio .if e nosso código ficará assim:
Com isto comprovamos qual botão que foi pressionado.
Exercícios
- Crie uma janela do tamanho do seu desktop.
- Crie uma janela com 5 botões. Cada botão deve mostrar uma mensagem diferente.
- Crie um programa igual a este:
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
Copyright(c) 2005-2006 RVLCN
Recado da vó
Aqui está o código fonte dos exercícios deste tutorial: