| Tutorial 2: MessageBox PL (masm32) |
|
|
|
| Wpisał: Iczelion's Win32 Assembly | ||
| 23.07.2007. | ||
Tutorial 2: MessageBoxW tym tutorialu, stworzymy w pełni funkcjonalny program pod Windows, który wyświetla okno z informacją Ściągnij przykładowy plik tutaj. Teoria:Windows zawiera bogactwo zasobów dla swoich programów. Centrum tego jest Windows'owe API (Interfejs Programowania Aplikacji, z ang. Application Programming Interface). API Windows'a jest olbrzymią kolekcją bardzo przydatnych funkcji, które zawarte są w samym systemie, gotowe do użycia przez jakikolwiek program pod Win32. Funkcje te są zawarte w kilku dynamicznie połączonych bibliotekach (z ang. Dynamic-Linked Libraries - DLLs), takich jak kernel32.dll, user32.dll i gdi32.dll. Kernel32.dll zawiera funkcje API odnoszące się do pamięci i zarządzania procesami. User32.dll kontroluje aspekty interfejsu użytkownika programu. Gdi32.dll jest odpowiedzialny za operacje graficzne. Poza "główną trójką" są inne DLL'e, które twój program może użyć, dzięki czemu zapewnia ci to dosyć informacji o pożądanych funkcjach API. Przykład:Poniżej zaprezentuje goły szkielet programu. Wypełnimy go później. .386 Wykonywanie programu rozpoczyna się od pierwszej instrukcji zaraz pod etykietą określoną po dyrektywie end. W powyższym szkielecie, wykonywanie programu rozpoczyna się zaraz pod etykietą start. Proces ten będzie podążać instrukcja po instrukcji, aż pojawią się jakieś instrukcje kontrolujące bieg procesu. Instrukcjami tymi mogą być jmp, jne, je, ret itd. Te instrukcje przekierowują bieg procesu to jakiś innych instrukcji. Kiedy program musi wyjść do Windows'a, powinien wywołać funkcję API - ExitProcess. ExitProcess proto uExitCode:DWORD Powyższa linia to tzw. prototyp funkcji. Prototyp funkcji definiuje atrybuty tej funkcji assembler'owi/linker'owi więc może on wykonać dla ciebie weryfikację typów zmiennych. Format prototypu funkcji wygląda następująco: NazwaFunkcji PROTO [NazwaParametru]:TypDanych,[NazwaParametru]:TypDanych,... Krótko, nazwa funkcji, następnie słowo PROTO, a potem lista typów danych i parametrów oddzielonych przecinakmi. W powyższym przykładzie ExitProcess jest zdefiniowane jako funkcja, która przybiera tylko jeden parametr typu DWORD (z ang. Double Word - podwójne słowo). Prototypy funkcji są bardzo przydatne kiedy używasz składnię wysokiego poziomu - invoke. Invoke to po prostu call ze sprawdzaniem typów zmiennych. Na przykład jeżeli użyjesz: call ExitProcess bez włożenia na stos parametru DWORD to assembler/linker nie będzie w stanie poinformować cię o błędzie. Zauważysz to później, gdy program się zwiesi :) Ale kiedy użyjesz: invoke ExitProcess Linker poinformuje cię, że zapomniełeś ułożyć na stosie parametr DWORD w celu uniknięcia błędu. Polecam ci używanie invoke zamiast prostego call. Składnia invoke jest następująca: INVOKE wyrażenie [,argumenty] Wyrażeniem może być nazwa funkcji lub wskaźnik funkcji. Parametry funkcji są oddzielone przecinkami. Większość protoypów funkcji API jest zawartych w plikach include. Jeżeli używasz MASM'a hutch'a będą one w folderze MASM/include/ . Pliki include mają rozszerzenie .inc, a prtotypy funkcji zawartych w poszczególnych DLL-ach są zawarte w pliku .inc o nazwie tej samej co DLL. Na przykład ExitProcess jest ekspotowany przez kernel32.dll więc prototyp ExitProcess jest zawarty w kernel32.inc. teraz z powrotem do ExitProcess, parametr uExitCode jest wartością, która powoduje, że program powróci do Windows po zakończeniu. Możesz wywołać ExitProcess w ten sposób: invoke ExitProcess, 0 Umieść tą linijkę zaraz pod etykietą startową, a uzyskasz program pod Win32, który natychmiast się zamyka, ale jest on poprawny... .386 Opcja casemap:none mówi MASM'owi, żeby "uważał na zmianę wielkości liter" tzn. że ExitProcess i exitprocess to nie to samo. Zwróć uwagę na nową dyrektywę, include. Po tej dyrektywie występuje nazwa pliku którą chciałbyś wstawić w miejsce tej dyrektywy. W powyższym przykładzie kiedy MASM zacznie przetwarzać linię include \masm32\include\windows.inc, otworzy plik windows.inc, który znajduje się w folderze \MASM32\include i przetworzy zawartość windows.inc tak jakbyś ją tam (do swojego programu) wkleił. Plik windows.inc hutch'a zawiera definicje stałych i struktur, które będą ci potrzebne w programowaniu pod Win32. Nie zawiera on żadnego prototypu funkcji. Hutch i ja próbujemy umieścić tam tyle definicji stałych i struktur ile się da, ale jeszcze wiele zostało do wliczenia. Plik windows.inc jest cały czas update'owany. Sprawdź strony hutch'a i moje dla nowszych wersji.
Program l2inca.exe wyciągnie informacje z bibliotek importów i utworzy pliki include pełne prototypów funkcji.
W naszym przykładzie wywołujemy funkcję eksportowaną przez kernel32.dll, więc musimy wliczyć prototypy funkcji zawartych w kernel32.dll. Ten plik to kernel32.inc. Jeżeli otworzysz ten plik edytorem tekstu, to zobaczysz że jest on pełny prototypów funkcji dla kernel32.dll. Jeżeli nie wliczysz kernel32.inc, nadal możesz wywołać ExitProcess, ale tylko prostą składnią call. Nie będziesz mógł użyć składni invoke. Wniosek jest następujący: aby móc użyc invoke, musisz wliczyć prototyp użytej funkcji gdzieś w kodzie źródłowym. W powyższym przykładzie, jeżeli nie wliczysz kernel32.inc, możesz zdefiniować prototyp funkcji dla ExitProcess gdziekolwiek w kodzie, ale wcześniej niż komenda invoke, a invoke będzie działać. Pliki include są po to aby zaoszczędzić ci pracy z wpisywaniem wszystkich prototypów funkcji samemu, więc używaj ich kiedy tylko chcesz. Teraz zapisz przykład jako msgbox.asm. Przypuszczając, że ml.exe jest w twojej ścieżce, zassembluj msgbox.asm wyrażeniem: ml /c /coff /Cp msgbox.asm
Po zassemblowaniu msgbox.asm, dostaniesz msgbox.obj. msgbox.obj jest plikiem obiektu. Plik obiektu jest tylko o krok od pliku wykonywalnego. Zawiera on instrukcje/dane w formie binarnej. Plikowi temu brakuje tylko kilku poprawek adresów, które to zrobi linker. Teraz możesz uruchomić linkera: link /SUBSYSTEM:WINDOWS /LIBPATH:c:\masm32\lib msgbox.obj /SUBSYSTEM:WINDOWS informuje linker'a jakim typem programu wykonywalnego jest ten program Linker czyta plik obiektu i poprawia go o adresy bibliotek importów. Kiedy proces ten zostanie zakończony dostaniesz msgbox.exe. Teraz masz msgbox.exe. Nie bój się, uruchom go :) Dojdziesz do tego, że nic nie robi. Hmmm... nie umieściliśmy jeszcze w nim nic ciekawego. Ale to wciąż program Win32. A popatrz na jego rozmiar ! Na moim PC to 1,536 bajtów. Teraz umieścimy tam okno z wiadomością. Jego prototyp funkcji to: MessageBox PROTO hwnd:DWORD, lpText:DWORD, lpCaption:DWORD, uType:DWORD hwnd jest zaczepieniem do okna macierzystego. Możesz myśleć o tym zaczepieniu jako o numerze, który reprezentuje okno, do którego się odnosisz. Jego wartość nie jest dla ciebie ważna. Tylko pamiętasz, że reprezentuje ono okno. Kiedy chcesz zrobić coś z tym oknem, musisz się do niego odnieść poprzez punkt zaczepienia. Zmodyfikujmy msgbox.asm, aby dodać tam okienko z naszą informacją. .386 .data .code Zassembluj to i uruchom. Powinieneś zobaczyć okienko z informacją "Win32 Assembly is Great!". Przyjżyjmy się jeszcze kodowi żródłowemu.
invoke MessageBox,NULL, addr MsgBoxText,addr MsgBoxCaption,MB_OK MASM poinformuje cię o błędzie. Jeżeli użyjesz offset zamiast addr w powyższym wycinku kodu, MASM zassembluje to bez problemu.
lea eax, LocalVar Kiedy tylko lea może zdeterminować adres etykiety podczas pracy programu, to działa to dobrze.
Powered by AkoComment 2.01 PL+ |
||
| Zmieniony ( 10.08.2007. ) | ||
| następny artykuł » |
|---|


