CZĘŚĆ 2. - INSTRUKCJE WARUNKOWE

Ok, a więc mamy okienko z komunikatem. Ale jak teraz odczytać, który przycisk został wybrany przez użytkownika? Służą do tego tzw. instrukcje warunkowe, czyli IF. Napiszmy następujący program:

.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
msgTytul db "MASM Tutorial",0
msgTekst db "Wciśnij tak lub nie.",0

.code
start:
  invoke MessageBox, 0, addr msgTekst, addr msgTytul, MB_YESNO or MB_ICONQUESTION
  invoke ExitProcess, 0
end start

Jak się zapewne domyślacie, służy on do wyświetlenia okienka z odpowiednim komunikatem i przyciskami tak/nie. W pomocy (winapi.hlp) do funkcji MessageBox czytamy:

"The return value is zero if there is not enough memory to create the message box. If the function succeeds, the return value is one of the following menu-item values returned by the dialog box:
Value Meaning
IDABORT Abort button was selected.
IDCANCEL Cancel button was selected.
IDIGNORE Ignore button was selected.
IDNO No button was selected.
IDOK OK button was selected.
IDRETRY Retry button was selected.
IDYESYes button was selected."

Należy więc sprawdzić, czy zwrócona wartość jest równa IDYES czy IDNO. Warto wiedzieć, że funkce API zawsze zwracają wartości w rejestrze EAX. Sprawdzania wartości dokonujemy za pomocą bloku instrukcji .IF-.ENDIF. Składnia wygląda tak:

.IF warunek
     polecenia
.ELSEIF warunek
     polecenia
.ELSE
     polecenia
.ENDIF

Warto wiedzieć, że IF nie jest standardową instrukcją assemblera, tzn. nie występuje w assemblerze jakim posługuje się procesor. Kompilator po prostu "tłumaczy" każdy blok IF na odpowiadające mu polecenia assemblera. Omówię je, jak zajdzie taka potrzeba. Na razie możemy z powodzeniem używać instrukcji IF.
Wszyscy, którzy programowali już w jakimś języku wyższego poziomu, więdzą zapewne, że po MessageBoxie można dopisać na przykład taki oto zestaw poleceń:

.IF eax==IDYES
  invoke MessageBox, 0, addr msgYesTekst, addr msgTytul, MB_OK or MB_ICONEXCLAMATION
.ELSE
  invoke MessageBox, 0, addr msgNoTekst, addr msgTytul, MB_OK or MB_ICONEXCLAMATION
.ENDIF

Wstawiamy go bezpośrednio po poleceniu "invoke MessageBox". A dlaczego piszemy ".else" zamiast ".elseif eax==IDNO"? Żeby zaoszczędzić trochę pamięci i czasu procesora (przyda wam się to później, gdy będziecie chcieli napisać jakiegoś vira ;-)). Oczywiście w tym fragmencie jest pewne niedopatrzenie - nie ma jeszcze zmiennych msgYesTekst oraz msgNoTekst. Definiujemy je oczywiście w sekcji .data. Możemy napisać np.

msgYesTekst db "Wcisnąłeś ",34,"Tak",34,"!",0
msgNoTekst db "Wcisnąłeś ",34,"Nie",34,"!",0


Dociekliwi pewnie zaraz zapytają: A co to jest 34? Jest to kod ASCII cudzysłowu. A skąd my to wiemy? Z tablicy znaków (ta windowsowa posiada znaki jedynie od 32, poza tym nie podaje kodu znaku. Warto więc zaopatrzyć się w jakąś lepszą - na mojej stronie jest jeszcze (chyba) mój stary programik tego typu o nazwie ArAscii [jeszcze z czasów, kiedy programowalem ;) w VB]. Nie jest to może najlepszy program tego typu ale na początek wystarczy - ci co chcą więcej muszą poszperać w czeluściach internetu).
Oczywiście analogicznie można reagować na inne przyciski (IDABORT, IDCANCEL, IDIGNORE, IDOK, IDRETRY).
Cały program wygląda więc tak:

.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
msgTytul db "MASM Tutorial",0
msgTekst db "Wciśnij tak lub nie.",0
msgYesTekst db "Wcisnąłeś ",34,"Tak",34,"!",0
msgNoTekst db "Wcisnąłeś ",34,"Nie",34,"!",0

.code
start:
  invoke MessageBox, 0, addr msgTekst, addr msgTytul, MB_YESNO or MB_ICONQUESTION
  .IF eax==IDYES
     invoke MessageBox, 0, addr msgYesTekst, addr msgTytul, MB_OK or MB_ICONEXCLAMATION
  .ELSE
     invoke MessageBox, 0, addr msgNoTekst, addr msgTytul, MB_OK or MB_ICONEXCLAMATION
  .ENDIF
  invoke ExitProcess, 0
end start


Chyba nie muszę wyjaśniać, co on robi... Cały programik można pobrać stąd.

Arkadiusz "Czajnick" Robiński
arekrob@kki.net.pl
http://www.antywin.ko.pl