A Aldeia Numaboa ancestral ainda está disponível para visitação. É a versão mais antiga da Aldeia que eu não quis simplesmente descartar depois de mais de 10 milhões de pageviews. Como diz a Sirley, nossa cozinheira e filósofa de plantão: "Misericórdia, ai que dó!"

Se você tiver curiosidade, o endereço é numaboa.net.br.

Leia mais...

Informática Numaboa - Tutoriais e Programação

Janelas (masm)

Dom

7

Jan

2007


10:34

(12 votos, média 4.83 de 5) 


Registro da classe

Após criar uma classe (a "planta de uma casa"), é obrigatório registrá-la para que o sistema permita usá-la como modelo para criar uma ou mais instâncias de objetos ("uma ou mais casas") baseados nesta classe. Como utilizamos a estrutura WNDCLASSEX para definir as caracteríticas da nossa classe de janela, para registrá-la precisamos usar a função que "faz par" com ela: a RegisterClassEx. Caso tivéssemos utilizado WNDCLASS, a função para registro seria RegisterClass.

ATOM RegisterClassEx(
CONST WNDCLASSEX *lpwcx // ponteiro para a estrutura com os dados da classe
);

Tranquilo. Temos a estrutura pronta e a função pede um ponteiro. Usando invoke podemos usar o operador ADDR para fornecê-lo. Acontece que esta função faz parte da user32.lib e esta biblioteca, assim como o arquivo include correspondente, precisa ser incluída:

...
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 proc mInst:DWORD, mInstAnt:DWORD, linhaCmd:DWORD, Mostra:DWORD
LOCAL ej:WNDCLASSEX
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
gerenteJanela endp

Criando a janela

Se a nossa classe foi aceita pelo sistema para registro, isto significa que possuímos um "alvará de construção". Podemos criar quantos objetos quisermos usando a classe registrada como modelo. Registra-se apenas uma vez, usa-se quantas vezes forem necessárias.

A função CreateWindowEx

A função para criar uma janela de acordo com a classe que registramos é do grupo Ex, ou seja, CreateWindowEx (WNDCLASSEX -> RegisterClassEx -> CreateWindowEx). Seria CreateWindow caso tivéssemos usado uma estrutura WNDCLASS.

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
);

Esta função pede um caminhão de parâmetros (12 ao todo, se você tiver o trabalho de contar). Então, vamos lá:

  • dwExStyle: Estilo extra da janela. Este é um parâmetro novo, adicionado ao CreateWindow antigo. Aqui podemos colocar os novos estilos das janelas do Windows 9x, NT e XP. Você pode especificar o estilo de janela comum em dwStyle porém, se você desejar estilos especiais, como janelas sempre no topo, você precisa especificá-los aqui. Usa-se NULL caso estilos extras não sejam requeridos.
  • lpClassName: (Requerido) Endereço da string ASCIIZ (string terminada em zero) que contém o nome da classe que serve de modelo para esta janela. A classe pode ser uma que você tenha criado e registrado ou uma classe predefinida do Windows.
  • lpWindowName: Endereço da string ASCIIZ que contém o nome da janela. O nome mostrado na barra de título da janela. Se este parâmetro for NULL, a barra de título ficará em branco.
  • dwStyle: Estilos da janela. Aqui você pode especificar a aparência da janela. Passar NULL também é aceito mas, neste caso, a janela não terá uma caixa de menu do sistema, botões minimizar-maximizar e botão fechar (a janela não teria muito uso e você teria que usar Alt+F4 para fechá-la). O estilo mais comum é o WS_OVERLAPPEDWINDOW. Um estilo de janela é apenas um bit de flag, portanto, você pode combinar diversos estilos com o operador "or" para obter a aparência desejada. O estilo WS_OVERLAPPEDWINDOW nada mais é do que a combinação dos estilos mais comuns obtido através deste método.
  • X, Y: As coordenadas do canto superior esquerdo da janela. Normalmente, estes valores deveriam ser CW_USERDEFAULT, ou seja, você deixa o Windows decidir onde colocar a janela no desktop.
  • nWidth, nHeight: A largura e a altura da janela em pixels. Aqui você também pode usar CW_USERDEFAULT e deixar o Windows escolher a largura e a altura apropriadas.
  • hWndParent: O manipulador da janela-mãe (se existir). Este parâmetro indica ao Windows se esta janela é uma janela-filha (subordinada) ou algum outro tipo de janela e, se for, qual é a janela-mãe. Este relacionamento é apenas para uso interno do Windows. Se a janela-mãe é destruída, todas as janelas-filhas serão automaticamente destruídas. É realmente simples. Como no nosso exemplo há apenas uma janela, nós especificamos este parâmetro como NULL.
  • hMenu: Um manipulador para o menu da janela. NULL se for para usar a classe menu já definida na classe da janela. Dê novamente uma olhada no membro lpszMenuName da estrutura WNDCLASSEX. Este membro especifica o menu *default* para a classe. Toda janela criada a partir desta classe terá o mesmo menu por default, a não ser que você especifique aqui em hMenu um menu que se sobreponha ao menu default - isto se chamda overriding. hMenu é na verdade um parâmetro com dois objetivos. Se a janela que está sendo criada é do tipo predefinido, como button (botão) ou edit box (caixa de edição), esta janela/controle não pode possuir um menu. Neste caso, o hMenu é usado como identificador (ID) do controle. O Windows distingue se hMenu é realmente um manipulador de menu ou um ID de controle olhando no parâmetro lpClassName. Se for o nome de uma classe predefinida, o hMenu é um ID de controle. Se não for, então é um manipulador do menu da janela.
  • hInstance: O manipulador da instância para o módulo do programa que cria a janela.
  • lpParam: Um ponteiro opcional para uma estrutura de dados passada para a janela. É usado por janelas MDI para passar os dados de CLIENTCREATESTRUCT. Normalmente este valor é NULL, significando que não há dados sendo passados via CreateWindow(). A janela pode obter o valor deste parâmetro através da chamada da função GetWindowLong.

Chamando a função

É explicação que não acaba mais e tudo isso só para chamar uma funçãozinha! Para todos os parâmetros já temos os valores, exceto para o título da janela. Este vocês já tiram de letra: basta inicializar uma variável na seção .DATA. Também vamos precisar do valor de retorno da função CreateWindowEx, que é o manipulador da instância da janela que acabamos de criar. Sem este manipulador, ou seja, sem o número identificador desta janela recém criada, não teremos como acessá-la. Como vamos precisar deste manipulador apenas no âmbito da função gerenteJanela, podemos declarar uma variável LOCAL para armazená-lo.

...
.DATA
NomeClasse db "JanelaNua",0
TituloJanela db "Janelinha NumaBoa",0
...

gerenteJanela proc mInst:DWORD, mInstAnt:DWORD, linhaCmd:DWORD, Mostra:DWORD
LOCAL ej:WNDCLASSEX
LOCAL mJanela:HWND

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

gerenteJanela endp

Você deve estar pensando "até que enfim a janela está na tela"... ledo engano. A janela foi criada (a "casa foi construída"), está prontinha para uso, só que ninguém contou ao sistema que é para abrí-la ao público.

Informações adicionais