Okno z komunikatem

Jak to zwykle w tego typu kursach bywa, część praktyczną zaczniemy od prostego programu, który wyświetla komunikat tekstowy. Tego typu komunikaty są niezwykle często stosowane w programach Windows’owych i służą najczęściej do powiadomienia użytkownika o błędzie.

Szkielet programu

Pisanie niemal każdego programu w assemblerze zaczynamy od wstawienia następującego fragmentu:

.386
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc
;deklaracje bibliotek, których będziemy używać

.const
;stałe

.data
;zmienne, którym nadajemy początkowe wartości

.data?
;zmienne niezdefiniowane (podajemy tylko typ zmiennej)

.code
start:
;kod
end start

W pierwszej linii określamy zestaw instrukcji assemblera, których będziemy używać. Już procesor klasy 386 dostarcza nam tyle instrukcji, że możemy z powodzeniem stosować ten model nawet będąc zaawansowanymi koderami i nie będziemy odczuwać niedosytu. Zamiast 386 można w razie potrzeby użyć 486, 586, MMX itp. Kolejna linijka oznacza model pamięci stosowany w programie. Jedynym dopuszczalnym w Windows jest model flat. Myślę, że na tym etapie nauki nie ma potrzeby dalszego rozwodzenia się na ten temat. „Option casemap: none” mówi kompilatorowi, że ma rozróżniać wielkość liter w nazwach zmiennych i innych symboli. Natomiast plik windows.inc, który poprzez dyrektywę include dołączamy do programu, zawiera definicje wszystkich stałych używanych w API Windows.

Aby wyświetlić komunikat, musimy wiedzieć która funkcja API jest za to odpowiedzialna i w jakiej bibliotece się znajduje. Te informacje można znaleźć w „Win32 Programmer’s Reference”. Stąd wiemy, że ta funkcja to MessageBox i aby zadziałała, należy jej podać kolejno następujące parametry:

  • Uchwyt okna nadrzędnego (jeżeli takowego nie mamy, podajemy 0)
  • Adres w pamięci tekstu, który zostanie wyświetlony w głównej części okna
  • Adres tekstu, który pojawi się na pasku tytułowym
  • Styl komunikatu – w tym miejscu wybieramy przyciski i ikonę, które pojawią się w oknie

Aby rozpocząć kodowanie programu, uruchamiamy Quick Editor, znajdujący się w katalogu Macro Assemblera, tworzymy w nim nowy plik o dowolnej nazwie (z rozszerzeniem asm) i umieszczamy w nim powyższy szkielet.

Funkcje, których bedziemy używać znajdują się w bibliotekach kernel32 i user32, musimy wiec je zadeklarować w przeznaczonym do tego miejscu.

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

W sekcji data definiujemy zmienne zawierające to, co chcemy wyświetlić w okienku, np.

msgTytul db "MASM32 Tutorial",0
msgTekst db "Pierwszy komunikat.",0

MsgTytul i msgTekst to nazwy zmiennych, db oznacza typ zmiennej (w tym przypadku jest to bajt, a właściwie zbiór bajtów – każda litera, każdy znak zajmuje w pamięci jeden bajt). Poza db możemy stosować jeszcze dw (word – dwa bajty, których używa się do zapisu liczb z przedziału 0..65535), dd (double word – 4 bajty), dq (quad word – 8 bajtów) oraz kilka innych typów danych, które nie będą nam potrzebne (zainteresowanych odsyłam do pomocy dołączanej do Macro Assemblera). Bajt 0 natomiast musi konczyć kazdy ciąg tekstowy.

W miejscu przeznaczonym na kod, należy wywołać funkcję wyświetlającą okienko z naszym komunikatem. MASM posiada specjalną pseudo-instrukcję służącą do wywoływania funkcji i procedur – invoke, która bardzo ułatwia pisanie kodu. Parametry dla funkcji podajemy po prostu po przecinku:

invoke MessageBox,0,addr msgTekst,addr msgTytul,MB_OK

„Addr” przed nazwami zmiennych jest potrzebny po to, aby kompilator zamienił całe wyrażenie na adres, a nie na zawartość zmiennej.

Aby program działał prawidłowo i nie wykonywał nieprawidłowej operacji, należy go zakończyć. Służy do tego funkcja ExitProcess. Dopisujemy więc do kodu jeszcze fragment:

invoke ExitProcess,0

Sekcje „.const” oraz „.data?” są puste, więc można je spokojnie usunąć. Cały kod 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 „MASM32 Tutorial”,0
msgTekst db „Pierwszy komunikat.”,0

.code
start:
invoke MessageBox,0,addr msgTekst,addr msgTytul,MB_OK
invoke ExitProcess,0
end start

Po kompilacji programik ten wyświetli okienko z komunikatem i przyciskiem OK. Jeżeli chcemy, aby zamiast OK były inne przyciski, wpisujemy odpowiednie wartości zamiast MB_OK:

  • MB_ABORTRETRYIGNORE – przerwij, ponów próbę, zignoruj
  • MB_OKCANCEL – ok, anuluj
  • MB_RETRYCANCEL – ponów próbę, anuluj
  • MB_YESNO – tak, nie
  • MB_YESNOCANCEL – tak, nie, anuluj

Gdy chcemy dodatkowo wyswietlic ikonkę, dopisujemy słowo „or” oraz odpowiednią wartość z listy poniżej.

  • MB_ICONEXCLAMATION
    MB_ICONWARNING – wykrzyknik
  • MB_ICONINFORMATION
    MB_ICONASTERISK – mała litera „i”
  • MB_ICONQUESTION – znak zapytania
  • MB_ICONSTOP
    MB_ICONERROR
    MB_ICONHAND – krzyżyk

Przykład – wyświetlanie komunikatu z przyciskami przerwij, ponów próbę, zignoruj i znakiem zapytania:

invoke MessageBox,0,addr msgTekst,addr msgTytul,\
       MB_ABORTRETRYIGNORE or MB_ICONQUESTION

Utworzyliśmy więc okienko z komunikatem. Czasem przydałoby się jednak wiedzieć który przycisk został naciśnięty przez użytkownika. Z pomocą przychodzi nam znowu „Win32 Programmer’s Reference”, w którym 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.
IDYES Yes button was selected.”

Zatem funkcja zwraca np. IDYES gdy użytkownik nacisnął przycisk „Tak”. Warto wiedzieć, że funkcje API zawsze zwracają wartości w rejestrze EAX. Zatem aby sprawdzić czy „Tak” został naciśnięty, należy porównać rejestr eax ze stałą IDYES. Assembler posiada specjalną instrukcję służącą do porównywania dwóch wartości, jednak na razie możemy sobie ułatwić kodowanie, używaćjąc tzw. high-level syntax, czyli pseudo-instrukcji, które kompilator zamieni na odpowiadające im instrukcje procesora. Aby sprawdzić jaką wartość zawiera zmienna lub rejestr i odpowiednio na to zareagować, stosujemy blok instrukcji IF. Składnia wygląda następująco:

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

Jako warunek podajemy zwyczajne, matematycznie zapisane równanie. Możemy korzystać z następujących operatorów porównawczych: == (równy), > (większy), >= (większy lub równy), < (mniejszy), <= (mniejszy lub równy), != (różny) oraz ze spójników logicznych: || (alternatywa – lub), && (koniunkcja – i), ! (negacja).

Za wywołaniem funkcji wyświetlającej komunikat wpisujemy następujący kod:

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

Natomiast w sekcji data deklarujemy potrzebne zmienne:

YesTxt db "Wcisnąłeś 'Tak' !",0
NoTxt db "Wcisnąłeś 'Nie' !",0

Powyższe fragmenty spowodują, że gdy użytkownik wciśnie przycisk „Tak”, zostanie wyświetlony komunikat z tekstem „Wciśnąłeś ‚Tak’ !”, a w innym przypadku na ekranie pojawi sie napis „Wcisnąłeś ‚Nie’ !”.

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 „MASM32 Tutorial”,0
msgTekst db „Wciśnij tak lub nie.”,0
YesTxt db „Wcisnąłeś ‚Tak’ !”,0
NoTxt db „Wcisnąłeś ‚Nie’ !”,0

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

Przykładowy program do tej części kursu można pobrać stąd (836 bajtów). W następnym odcinku zajmiemy sie tym, co w Windows najważniejsze, czyli tworzeniem okien.

4 myśli nt. „Okno z komunikatem

  1. student

    Uczę się właśnie do kolokwium z MASM’a. Ten poradnik jest genialny:) chwała za to AUTOROWI!!

    Odpowiedz

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *