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) 


Instruções da linha de comando

A linha de comando geralmente se resume no nome do programa que queremos executar, ou seja, não contém parâmetros adicionais. Existem alguns raros casos em que é necessário enviar um ou alguns parâmetros para que o programa funcione corretamente ou de forma personalizada. Somente nestes raros casos é que precisamos usar a função da API GetCommandLine, também da kernel32.lib. Apenas a título de ilustração vamos inserir esta chamada.

.386
.MODEL FLAT,STDCALL
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib

.DATA?
mInstancia DWORD ?
linhaComando DWORD ?

.CODE
inicio:
invoke GetModuleHandle, NULL
mov mInstancia, eax
invoke GetCommandLine
mov linhaComando, eax

invoke ExitProcess,0
end inicio

A classe da janela

O Windows só consegue criar objetos a partir de um modelo - é como se o sistema precisasse da "planta da casa" para que poder construir a "casa". Primeiro é preciso criar a "planta" e depois entregá-la (fazer o registro) para que o Windows possa usá-la como modelo.

Normalmente a função padrão utilizada para esta dupla tarefa (criar e registrar) é a WinMain, que é chamada pelo sistema como ponto de entrada para um aplicativo win32. A referência da API nos mostra o seguinte:

int WINAPI WinMain(
HINSTANCE hInstance, // manipulador da instância
HINSTANCE hPrevInstance, // manipulador da instância anterior
LPSTR lpCmdLine, // ponteiro para a linha de comando
int nCmdShow // modo de apresentação da janela
);

Para poder utilizar esta função precisamos criar o protótipo da mesma. Se você esqueceu o que é um protótipo de função, refresque a memória relendo "O Folgado". Para criar o protótipo é necessário conhecer os tipos dos parâmetros que a função espera receber: HINSTANCE, LPSTR e int. Na verdade, todos eles são nomes diferentes que o Windows dá ao DWORD. Esta função recebe quatro parâmetros: o manipulador da instância do nosso programa, o manipulador de instância da instância anterior do nosso programa, a linha de comando e o estado da janela da primeira vez em que aparecer. No win32, NÃO existe uma instância anterior. Cada programa está sozinho no seu espaço de endereços, de modo que o valor de hPrevInstance será sempre 0 (NULL). Isto é uma sobra da época do win16 quando todas as instâncias de diversos programas rodavam no mesmo espaço de endereços e uma instância queria saber se era a primeira. No win16, se hPrevInstance for NULL, então esta instância é a primeira. O nome da função também pode ser um da nossa escolha, portanto, nosso protótipo pode ser

    gerenteJanela proto :DWORD, :DWORD, :DWORD, :DWORD

O manipulador da instância do nosso programa já está armazenado em mInstancia, o manipulador da instância anterior é NULL, o ponteiro para a linha de comando já está em linhaComando e o modo de exibição pode ser o padrão (SW_SHOWDEFAULT). Nosso código fonte passa a ser o seguinte:

.386
.MODEL FLAT,STDCALL
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib

gerenteJanela proto :DWORD, :DWORD, :DWORD, :DWORD

.DATA?
mInstancia DWORD ?
linhaComando DWORD ?

.CODE
inicio:
invoke GetModuleHandle, NULL
mov mInstancia, eax
invoke GetCommandLine
mov linhaComando, eax
invoke gerenteJanela, mInstancia, NULL, linhaComando, SW_SHOWDEFAULT
invoke ExitProcess,0
end inicio

gerenteJanela proc mInst:DWORD, mInstAnt:DWORD, linhaCmd:DWORD, Mostra:DWORD
...
gerenteJanela endp

A função gerenteJanela é um procedimento que separamos do corpo principal do código (que fica entre o par de rótulos "inicio:" e "end inicio"). Fiz isto apenas para destacar e individualizar este procedimento do resto do código. Se você quiser, não precisa criar o protótipo da função, não precisa fazer o invoke e nem criar o procedimento gerenteJanela. Pode simplesmente colocar todo o código que vem a seguir no corpo principal.

Além disso, se você suprimiu o código correspondente à linha de comando, basta enviar um parâmetro NULL no lugar de linhaComando.

A estrutura WNDCLASSEX

A "planta" da classe da nossa janela é "desenhada" numa estrutura. Uma estrutura agrupa dados de tal forma que possam ser endereçados num bloco único (Leia mais sobre estruturas em "Trabalhando com Estruturas"). Usaremos uma estrutura predefinida no Windows, chamada WNDCLASSEX.

A estrutura WNDCLASSEX foi planejada para conter todas as informações de uma classe janela e a referência da API nos mostra o seguinte:

typedef struct _WNDCLASSEX {
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;

A seguir, a explicação para cada um dos membros desta estrutura:

  • cbSize: O tamanho da estrutura WNDCLASSEX em bytes. Podemos usar o operador SIZEOF para obter este valor.
  • style: O estilo da janela criada a partir desta classe. Você pode combinar diversos estilos usando o operador "or".
  • lpfnWndProc: O endereço do procedimento da janela (window procedure) responsável pelas janelas criadas a partir desta classe.
  • cbClsExtra: Especifica o número de bytes extras que podem ser alocados logo após a estrutura. O sistema operacional inicializa os bytes com zero. Aqui você pode armazenar dados específicos da classe.
  • cbWndExtra: Especifica o número de bytes extras que podem ser alocados logo após a instância da janela. O sistema operacional inicializa estes bytes com zero. Se o aplicativo usar a estrutura WNDCLASS para registrar uma caixa de diálogo usando a diretiva CLASS do arquivo de recursos, ele precisa indicar este membro como DLGWINDOWEXTRA.
  • hInstance: O manipulador da instância do módulo (programa).
  • hIcon: O manipulador do ícone. Obtenha-o através da chamada de LoadIcon.
  • hCursor: O manipulador do cursor. Obtenha-o através da chamada de LoadCursor.
  • hbrBackground: A cor de fundo das janelas criadas a partir desta classe.
  • lpszMenuName: O manipulador de menu default para janelas criadas a partir desta classe.
  • lpszClassName: O nome desta classe.
  • hIconSm: O manipulador do ícone pequeno associado a esta classe. Se este membro for NULL, o sistema procura nos recursos de ícones especificado pelo membro hIcon por um ícone de tamanho apropriado que possa ser usado.

Informações adicionais