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

Message Box (masm)

Sab

16

Dez

2006


11:41

(11 votos, média 4.55 de 5) 


Avançado Se a sua plataforma é Windows, então você quer ver pelo menos uma janela. Neste tutorial vamos usar novamente a API do Windows para fazer a maior parte do trabalho. Como o SO é baseado em janelas, existem algumas delas prontinhas para serem usadas. A escolhida é a Caixa de Mensagem (Message Box), com a qual vamos colocar um recado na tela.

Projeto

  1. O sistema operacional é o Windows de 32 bits.
  2. Não precisamos mais do que o conjunto de instruções do processador 386.
  3. O MASM vai fazer o trabalho pesado.
  4. O objetivo do programa é mostrar uma janela do tipo Message Box com um texto.

Botando a mão na massa

Abra o QEditor do MASM32 e digite o esqueleto de um programa que possa ser finalizado (Exit Process). É idêntico ao programa do tutorial "O Folgado":

.386
.MODEL FLAT,STDCALL
includelib \masm32\lib\kernel32.lib
include \masm32\include\kernel32.inc

.CODE
inicio:
invoke ExitProcess,0
end inicio

Vamos novamente usar uma função da API do Windows mas, antes de analisá-la, é bom saber alguma coisa a mais sobre as funções. Existem dois tipos de funções na API: do tipo ANSI e do tipo Unicode. Os nomes das funções da API para ANSI possuem um sufixo "A", por exemplo, MessageBoxA. As para Unicode têm o sufixo "W" (acho que é para Wide Char). O Windows 9x/Me suporta ANSI e o Windows NT, o Unicode.

As strings ANSI são as mais conhecidas. Elas são arrays de caracteres terminados em NULL. Um caractere ANSI tem o tamanho de 1 byte. Se o padrão ANSI é para 1 byte, isto significa que podem existir 256 caracteres diferentes (1 byte = 8 bits = 2ˆ8 = 256). Para as línguas européias o código ANSI é suficiente, pois não existem mais do que 256 caracteres diferentes. Este padrão, no entanto, não é adequado para muitas das línguas orientais, que possuem alguns milhares de caracteres únicos. Este é o motivo da existência do UNICODE. Um caractere UNICODE tem o tamanho de 2 bytes, tornando possível a existência de 65.536 caracteres únicos nas strings.

A função MessageBox

Na maioria das vezes usaremos um arquivo include que pode determinar e selecionar as funções da API apropriadas para a plataforma. Use apenas o nomes das funções API sem o sufixo que o MASM se encarrega do resto smile

A função da API do Windows que "fabrica" uma janela do tipo Message Box é a MessageBox e faz parte da biblioteca user32.dll. Dando uma olhada na referência da API do Windows, encontramos o seguinte:

int MessageBox(
HWND hWnd, // manipulador da janela proprietária
LPCTSTR lpText, // endereço do texto da message box
LPCTSTR lpCaption, // endereço do título da message box
UINT uType // estilo da message box
);

O valor de retorno da função é um inteiro e os parâmetros exigidos são:

  • hWnd: é o manipulador (handle) da janela-mãe. Você pode considerar o manipulador como um número que representa a janela. O valor deste número não é importante, apenas lembre-se de que representa uma janela. Quando você quiser fazer alguma coisa com a janela, refira-se a ela através do seu manipulador.
  • lpText: é um ponteiro para o texto que se quer mostrar na área cliente da janela. Um ponteiro, na realidade, é o endereço de alguma coisa. Um ponteiro para uma string de texto é igual ao endereço de memória onde está esta a string.
  • lpCaption: é um ponteiro para o título da janela.
  • uType: especifica o ícone e o número e tipo de botões na janela message box.

Se conhecemos o nome da função e a biblioteca à qual ela pertence, além de informar o assembler/linker que esta função deve ser vinculada ao programa, podemos adicionar sem susto as linhas seguintes:

.386
.MODEL FLAT,STDCALL
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc

.CODE
inicio:
invoke ExitProcess,0
end inicio

Os parâmetros exigidos pela função MessageBox são:

  • hWnd é o manipulador da janela-mãe. Como não existe uma janela-mãe, porque nossa janela é a única, então este parâmetro pode ser NULL.
  • lpText é o texto da janela - uma string ANSI terminada em zero. Lembre-se de que no Windows toda string ANSI precisa ser terminada em NULL (0 hexadecimal). Quem determina o texto que deve ser apresentado somos nós, portanto, vamos ter que inicializar esta string.
  • lpCaption é o título da janela - mais uma string terminada em zero que precisa ser inicializada.
  • uType determina o tipo da Message Box. Existem várias flags, agrupadas pelo tipo de aplicação, que determinam o conteúdo e o comportamento da MessageBox. Estas flags possuem nomes para facilitar o trabalho dos programadores. Assim, o grupo que determina os botões, possui flags como MB_OK (0 hexa), MB_YESNO (4 hexa), etc. O grupo do ícone possui MB_ICONWARNING (30 hexa), MB_ICONSTOP (10 hexa) e outros. Podemos fazer uma composição de flags para associar vários comportamentos e características fazendo um OR lógico com as flags desejadas. Por exemplo, para obter uma Message Box com botões Yes e No e com um ponto de interrogação como ícone, indica-se MB_YESNO (4 hexa) OR MB_ICONQUESTION (20 hexa).

Os parâmetros que precisam ser inicializados são o lpText e o lpCaption. A seção .DATA é onde estes dados podem ser inicializados. Os outros podem ser passados diretamente como valores ou como constantes predefinidas. Se quisermos utilizar as constantes predefinidas, é preciso incluir um arquivo include que contenha as definições. É onde entra o excelente arquivo windows.inc do Iczelion & Hutch (está no pacote do MASM32 versões 8 e 9).

O assembler faz distinção entre letras maiúsculas e minúsculas. Assim, nomejanela é diferente de NomeJanela. A sintaxe do MASM aceita uma diretiva que determina seu comportamento com letras maiúsculas e minúsculas: é a option casemap. Option casemap pode ser ALL, NONE e NOTPUBLIC (a última é o default). Usando option casemap:none logo abaixo da diretiva .MODEL, o MASM preserva a caixa dos identificadores. Usando option casemap:all, o MASM passa todos os identificadores para maiúsculo (por exemplo, tanto nomejanela quanto NomeJanela são transformados em NOMEJANELA). Queremos a caixa dos nossos identificadores preservada, então, para ir preparando o terreno, inclua o seguinte no script do seu programa:

.386
.MODEL FLAT,STDCALL
option casemap:none
include \masm32\include\windows.inc

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

.DATA
TituloJanela db "Tutorial NumaBoa 3",0
TextoJanela db "Message Box NumaBoa",0


.CODE
inicio:
invoke ExitProcess,0
end inicio

offset e addr

As variáveis TituloJanela e TextoJanela são as duas que precisavam ser inicializadas antes de se chamar a função MessageBox. De acordo com a referência da API, a função pede o PONTEIRO para estas variáveis e não o valor das mesmas. Para enviar um ponteiro de endereço como parâmetro usa-se tradicionalmente o operador offset. Se optarmos por chamar a função através de INVOKE, podemos utilizar o operador addr. Os dois modos são válidos, mas você precisa conhecer a diferença entre eles:

  • addr não aceita referências posteriores, enquanto offset aceita. Por exemplo, se o rótulo/variável for definido no código fonte adiante da linha que o invoca, addr não irá funcionar.
    invoke MessageBox, NULL, addr TextoJanela, addr TituloJanela, MB_OK
    ...
    TituloJanela db "Tutorial NumaBoa 3",0
    TextoJanela db "Message Box NumaBoa",0
    O MASM vai informar um erro. Se você usar offset ao invés de addr no trecho de código acima, o MASM vai assemblar numa boa.
  • addr pode lidar com variáveis locais, o offset só com variáveis globais. Uma variável local é apenas algum espaço reservado na pilha. Você vai conhecer seu endereço apenas em tempo de execução. offset é interpretado pelo assembler em tempo de construção (assemblamento, assemblagem, assemblação, sei lá :blush: ) e aí fica claro porque offset não pode funcionar para variáveis locais. addr é capaz de lidar com variáveis locais devido ao fato do assembler primeiro checar se a variável referenciada por addr é global ou local. Se for uma variável global, ele põe o endereço dessa variável no arquivo objeto. Sob este aspecto, addr funciona como o offset. Se for uma variável local, ele gera uma sequência de instruções, antes da chamada à função, parecida com o seguinte:
    lea eax, LocalVar
    push eax
    Uma vez que lea pode determinar o endereço do rótulo em tempo de execução, a coisa funciona bem.

Então vamos lá. Após todo este trabalho de preparação, adicione a chamada à função na área de código:

.386
.MODEL FLAT,STDCALL
option casemap:none
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\windows.inc

.DATA
TituloJanela db "Tutorial NumaBoa 3",0
TextoJanela db "Message Box NumaBoa",0

.CODE
inicio:
invoke MessageBox, NULL, addr TextoJanela, addr TituloJanela, MB_OK
invoke ExitProcess,0
end inicio

Pelo exposto acima, você deve ter sacado que existem outras chamadas válidas. A tradicional seria fazer um push para a pilha dos parâmetros em ordem inversa (convenção C de passagem de parâmetros) e depois chamar a função com um call:

push MB_OK
push offset TituloJanela
push offset TextoJanela
push NULL
call MessageBox

Criando a Janela

Se você optou pelo texto com a chamada de alto nível, o arquivo texto completo deve estar como o mostrado logo a seguir. Note que foi adicionado um ícone à janela, o MB_EXCLAMATION. Podemos enviar o parâmetro do tipo de janela como MB_OK OR MB_ICONEXCLAMATION ou como MB_OK+MB_ICONEXCLAMATION. O assembler aceita as duas versões.

.386
.MODEL FLAT,STDCALL
option casemap:none
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\windows.inc

.DATA
TituloJanela db "Tutorial NumaBoa 3",0
TextoJanela db "Message Box NumaBoa",0

.CODE
inicio:
invoke MessageBox, NULL, addr TextoJanela, addr TituloJanela, MB_OK+MB_ICONEXCLAMATION
invoke ExitProcess,0
end inicio

Agora é só produzir o executável. No tutorial anterior, "O Folgado", vimos como assemblar e linkar o arquivo texto usando as opções correspondentes do menu do MASM. Desta vez, vamos fazer o trabalho na unha:

  1. Salve o exemplo com um nome qualquer, por exemplo, msgbox.asm
  2. Transforme o arquivo texto em arquivo objeto usando o construtor do MASM chamado ML.EXE. Este programa fica no diretório \masm32\bin. Se este diretório estiver no path, use a seguinte linha de comando: ml /c /coff /Cp msgbox.asm
    • /c indica ao MASM para apenas assemblar, ou seja, ele não vai chamar o link.exe automaticamente. É conveniente rodar apenas o construtor para verificar se há algum erro no arquivo texto. Se tudo estiver correto, chamamos o link.exe posteriormente.
    • /coff indica ao MASM para criar o arquivo .obj no formato COFF. O MASM usa uma variação do COFF (Common Object File Format) que é usado em sistemas UNIX como formato próprio de arquivos objeto e executáveis.
    • /Cp indica ao MASM para preservar maiúsculas e minúsculas dos identificadores usados. Se você incluir \masm32\include\windows.inc, então pode colocar "option casemap:none" no cabeçalho do código fonte, logo abaixo da diretiva .model, para obter o mesmo resultado.
  3. Se não houve mensagens de erro, você pode transformar o arquivo objeto msgbox.obj em executável. Use o linker do MASM, o LINKER.EXE, que também se encontra no diretório \masm32\bin, com a seguinte linha de comando: link /SUBSYSTEM:WINDOWS/LIBPATH:c\masm32\lib msgbox.obj
    • /SUBSYSTEM:WINDOWS informa ao linker o tipo de executável que deve ser criado.
    • /LIBPATH: informa a localização das bibliotecas de importação. No MASM32, elas estarão no diretório masm32\lib.

Se tudo correu bem, agora você é o feliz possuidor de um executável denominado msgbox.exe, de apenas 2.560 bytes, cuja função é mostrar esta janelinha:

Message Box
Message Box Numaboa

Conferindo o trabalho do MASM

Usando novamente o OllyDbg como desassemblador, encontramos o seguinte:

00401000 	> $ 	6A 00 	PUSH 30 	; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
00401002 . 68 00304000 PUSH NUMABOAB.00403000 ; |Title = "Tutorial NumaBoa 3"
00401007 . 68 13304000 PUSH NUMABOAB.00403013 ; |Text = "Message Box NumaBoa"
0040100C . 6A 00 PUSH 0 ; |hOwner = NULL
0040100E . E8 0D000000 CALL ; \MessageBoxA
00401013 . 6A 00 PUSH 0 ; /ExitCode = 0
00401015 . E8 00000000 CALL ; \ExitProcess
0040101A $- FF25 00204000 JMP DWORD PTR DS:[<&KERNEL32.ExitProcess>
00401020 $- FF25 08204000 JMP DWORD PTR DS:[<&USER32.MessageBoxA>]

No endereço 401000, ponto de entrada do executável (module entrypoint), encontramos todos os push dos parâmetros da função USER32.MessageBoxA. Logo depois vem o call para a função. Somente quando retornamos da função MessageBoxA é que caímos no ExitProcess, que encerra nosso programa.

Observe que nos endereços 401002 e 401007 está sendo feito o push dos ponteiros para as strings. Verificando a área de memória indicada pelos ponteiros, o OllyDbg mostra as strings terminadas em zero:

00403000 	54 75 74 6F 72 69 61 6C 20 4E 75 6D 61 42 6F 61    Tutorial NumaBoa
00403010 20 33 00 4D 65 73 73 61 67 65 20 42 6F 78 20 4E 3.Message Box N
00403020 75 6D 61 42 6F 61 00 00 00 00 00 00 00 00 00 00 umaBoa..........

Os palpites da vó vovo

Já que você está com o MASM aberto e o código fonte na sua frente, dê uma boa estudada na referência da função MessageBox. Brinque com as flags e ponha mais botões, troque de ícone, defina o botão ativo, mude o alinhamento do texto, etc. Aproveite e dê uma olhada na função MessageBoxEx. Se você tiver interesse nas funções da user32.lib e não tiver uma referência da API, baixe o arquivo de Referências da API Win32 na seção de downloads da Aldeia (procure em Informática/Referências).

O arquivo zipado com este tutorial e seu código fonte está na seção de downloads da Aldeia. Procure na categoria tutoriais/Assembly Numaboa.

broker mfx отзывы кисти для макияжа отзывылобановский харьковлобановский александротзывы ооо полигонооо полигон киевцерковь возрождение

Informações adicionais