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) 


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

Informações adicionais