Win32Asm 1 -Úvod - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



Assembler

Win32Asm 1 -Úvod

asm

10. ledna 2002, 00.00 | Ukážeme si jak vytvořit pomocí MASM ve Windows dvě jednoduché aplikace - MessageBox a klasickou "Hello World" aplikaci.

WIN32ASM - ÚVOD
Dnes si ukážeme jak vytvořit pomocí MASM ve Windows dva jednoduché programy.

1. Kostra souboru
.386
Tato direktiva povoluje překlad neprivilegovaných instrukcí procesoru 386.
.model flat, stdcall
Flat (plochý, lineární) paměťový model není založen na principu segmentových registrů, které obsahují adresu báze segmentu, v němž se orientujeme pomocí registru obsahujícího offset, čili posun oproti bázi segmentu. Jedná se o lineární prostor, v němž používáme k určení adresy 32bitové registry. Stdcall je definice pro typ předávání parametrů mezi volanou funkcí a programem, tj. na zásobník se uloží parametry funkce počínaje pravým a konče levým, přišemž úpravu vrcholu zásobníku provádí volaná funkce (calee).
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
Komunikaci s Windows zajišťuje Win32API což je množina funkcí, pomocí kterých voláme služby operačního systému. Mají C interface, který nahradil volání služeb pomocí přerušení, jako tomu bylo v MS-DOSu (INT 21h). Těchto funkcí je velké množství a jsou uchovávány v DLL knihovnách, které jsou v případě potřeby umístěny do paměti odkud je můžeme volat aniž by musely být součástí kódu EXE souboru. Tyto knihovny jsou uloženy v adresáři WINDOWS\SYSTEM, nejdůležitější jsou kernel32.dll, user32.dll a gdi32.dll. V souborech s příponou *.inc jsou uvedeny pouze prototypy (deklarace) těchto funkcí, tj. názvy a parametry. Soubory *.lib slouží k využití příslušných funkcí (jejich nalezení) za běhu aplikace. Doporučuji připojit i soubor windows.inc (nebo jakýkoliv jiný podobný), který obsahuje předdefinované všechny možné konstanty a struktury Windows. Ukázka obsahu kernel32.inc:
BackupSeek PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
BackupWrite PROTO :DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
Beep PROTO :DWORD,:DWORD
Prototypy funkcí slouží příkazu invoke názevFunkce parametr1,...,parametrN, který na základě parametrů definovaných v prototypu názevFunkce PROTO parametr1,...,parametrN ověří, zda byly správně zadány všechny parametry. Příkaz invoke také poněkud ulehčuje práci pushnutím všech uvedených parametrů na zásobník a zavoláním příslušné funkce. Program si můžeme rozdělit na několik sekcí použitím direktiv .data pro data nebo .data? pro data, která nejsou inicializovaná (tj. nemají na začátku přiřazenou nějakou konkrétní hodnotu) nebo .code pro sled instrukcí. Je důležité si uvědomit že se jedná jen o jakési logické uspořádání zdrojového kódu a v žádném případě se nejde o samostatné 64kB segmenty. Ostatně k určení adresy slouží příkaz offset nebo addr (především lokální proměnné na zásobníku).

2. Hello world
Podívejme se na následující příklad:
;------------------------------------------
.386
.model flat, stdcall
;------------------------------------------
include \include\user32.inc
include \include\kernel32.inc
includelib \lib\user32.lib
includelib \lib\kernel32.lib
;------------------------------------------
NULL equ 0h
MB_OK equ 0h
;------------------------------------------
.data
   szDlgTitle db "Aplikace1",NULL
   szMsg db " Ahoj světe ",NULL
.code
start:
   push MB_OK
   push offset szDlgTitle
   push offset szMsg
   push NULL
   call MessageBox
   push NULL
   call ExitProcess
end start

Program zobrazí dialogové okno s nápisem "Ahoj světe". Pokud do souboru přidáme include \include\windows.inc můžeme vynechat řádky MB_OK equ 0h a NULL equ 0h. Parametry funkce MessageBox jsou uvedeny například v Microsoft Win32 Developers Reference. Všechny řetězce mají formát ASCIIZ, tj. jsou ukončené nulou. Parametry v pravolevém pořadí uložíme na zásobník a zavoláme funkci MessageBox, pro ukončení programu potom voláme funkci ExitProcess. Pokud se podíváte na názvy parametrů funkcí do helpu, zjistíte, že začínají prefixem složeným z několika málo malých písmen, které určují jeho typ, např. sz je řetězec ukončený nulou, h je handle. Jinou možností jak zavolat funkci MessageBox je použít příkaz invoke: (v tom případě ovbšem musíme mít deklarovaný prototyp této funkce) invokeMessageBox,0,offset szMsg,offset szDlgTitle,MB_OK

3. Tvorba okna
Tvorba jednoduchého okna není na první pohled příliš jednoduchá, jedná se o cca 100 řádků kódu, který je přítomný v každé aplikaci (uvědomme si ovšem, že v MS-DOSu by napsání podobné aplikace, která "nic nedělá", lze ji jen zavřít, zvětšit její okno, atd. byla výsledkem velice složitého a dlouhého kódu), kterou budeme pod Windows psát a která je na obrazovce představována grafickým oknem.

3.1 Popis celého zdrojového kódu
GetModuleHandle - Funkce vrátí handle modulu (EXE nebo DLL). Pokud je parametr NULL, vrací handle souboru (spíše instance) ze kterého byla funkce volána. GetCommandLine - funkce vrací adresu řetězce parametrů příkazového řádku Obě tyto funkce voláme na samém začátku programu a zadefinujeme si i globální proměnné do kterých získané údaje uložíme. Funkce WinMain je definovaná ve Win32 jako funkce se čtyřmi parametry, což je standardem a taková je taky používaná např. v C++ a představuje v něm vstupní bod programu (podobně jako v C funkce main()). V assembleru už vstupním bodem není a je taky na programátorovi, zda ji vůbec vytvoří a o parametrech ani nemluvě. Budeme se ale držet standardu a fukci vytvoříme kompletní. Paramery jsou: hInstance což je handle (rukojeť) insatnce, kterou jsme získali voláním funkce GetModuleHandle, hPrevInstance je NULL (tento parametr se používal ve Win16), lpCmdLine je ukazatel na řetězec parametrů příkazové řádky, poslední parametr nCmdShow je způsob zobrazení okna.
WinMain PROTO hInstance:DWORD,
	     hPrevInstance:DWORD,
	     lpCmdLine:DWORD,
	     nCmdShow:DWORD
Velice důležitá je struktura WNDCLASSEX, která definuje parametry třídy okna (je vpodstatě shodná s WNDCLASS). Významy jednotlivých položek jsou následující: cbSize je velikost struktury , style definuje některé vlastnosti okna, které jsou bitovými příznaky, jež lze libovolně spojovat operátorem OR, nastaveno máme CS_HREDRAW (0001h) a CS_VREDRAW (0002h) což znamená, že při změně velikosti bude okno překresleno, lpfnWndProc je adresa procedury okna s názvem WndProc, cbClsExtra a cbWndExtra jsou rezervovány, hInstance je handle programu, hIcon je handle ikony souboru, který získáme použitím funkce LoadIcon s parametry NULL a IDI_APPLICATION, což znamená využití již existující (nějaké default) ikony, podobně je to s položkou hCursor, hbrBackground je identifikátor (číslo) barvy pozadí, lpszMenuName jméno nabídky, lpszClassName jméno třídy a hIconSm handle malé ikony, která se objevuje v levém horním rohu záhlaví aplikace, hodnota NULL znamená, že se zmenší ikona jejíž handle je uložena ve hIcon.
WNDCLASSEX STRUCT
  cbSize            DWORD   ? 
  style             DWORD   ? 
  lpfnWndProc       DWORD   ? 
  cbClsExtra        DWORD   ? 
  cbWndExtra        DWORD   ? 
  hInstance         DWORD   ? 
  hIcon             DWORD   ? 
  hCursor           DWORD   ? 
  hbrBackground     DWORD   ? 
  lpszMenuName      DWORD   ? 
  lpszClassName     DWORD   ? 
  hIconSm           DWORD   ? 
WNDCLASSEX ENDS
Před samotným vytvořením okna je třeba třídu okna zaregistrovat, to provedeme funkcí RegisterClassEx, jejímž jediným parametrem je ukazatel na sktrukturu WNDCLASSEX (všechny následující procedury již budou vypsány s parametry, s jakými budou v příkladu použity):
invoke RegisterClassEx ADDR wc
Kde wc je lokální proměnná (typu WNDCLASSEX) procedury WinMain. Po zaregistrování již můžeme vytvářet okna dané třídy, tyto okna mohou mít některé rozdílné vlastnosti, které jsou parametry funkce CreateWindowEx, která nové okno vytvoří. Okno však ještě stále není zobrazeno, pouze je mu v paměti vyhrazená potřebná část pro veškerá data.
invoke CreateWindowEx,WS_EX_OVERLAPPEDWINDOW,
                      ADDR szClassName,
                      ADDR szDisplayName,
                      WS_OVERLAPPEDWINDOW,
                      0,0,100,100, 
                      NULL,NULL,
                      hInst,NULL
Parametry jsou postupně: WS_EX_OVERLAPPEDWINDOW je styl okna (všimněte si funkcí a datových struktur odlišujících se prefixem nebo postfixem EX, což je asi zkratka od extended, což znamená prodloužený nebo expanded, což by bylo rozšířený, prostě se jedná o novější verzi původních funkcí a struktur dat, ty původní ale zůstaly zachovány kvůli zpětné kompatibilitě),adresa názevu třídy okna, adresa textu v záhlaví okna, styl okna (nějaké parametry - hodnota WS_OVERLAPPEDWINDOW je normální překryvné okno), x-ová pozice levého horního rohu, y-ová pozice levého horního rohu, šířka okna, výška okna, handle rodičovského okna, handle menu, handle instance programu a ukazatel na nějaká dodatečná data. Funkce vrací handle vytvořeného okna, což je nejdůležitější handle (už jsme měli handle ikony, kursoru, instance programu), který si uložíme do globální proměnné hWnd. Aby se okno zobrazilo musíme dále zavolat funkci ShowWindow, která má parametry: handle okna a velikost okna při zobrazení (maximalizované, minimalizované, schované...), což je parametr nCmdshow, který jsme předali funkci WinMain v parametru nCmdShow. V podstatě jenom určí způsob zobrazení okna. Nakonec zavoláme funkci UpdateWindow, která by měla okno zobrazit. Jejím jediným parametrem je handle okna. Tato funkce v podsatě poprvé vyšle zprávu WM_PAINT, která říká, že grafické okno není platné a má být překresleno, v tomto případě je vykresleno poprvé.

3.2 Smyčka zpráv
Každá událost (např.zavření okna) vede k vytvoření zprávy, která se uloží do fronty zpráv, odkud si je vyzvedává funkce GetMessage:
 GetMessage ADDR msg, NULL,0,0
Návratová hodnota funkce je číslo identifikující zprávu, 0 znamená zprávu VM_QUIT (Tu generuje zavolání funkce PostQuitMessage, kterou voláme dochází-li k destrukci okna. Zpráva WM_QUIT slouží k opuštění nekonečné smyčky) , což vede k ukončení běhu programu, všechny ostatní zprávy vracejí nenulovou hodnotu. Struktura MSG je:
MSG STRUCT
  hwnd      DWORD      ?
  message   DWORD      ?
  wParam    DWORD      ?
  lParam    DWORD      ?
  time      DWORD      ?
  pt        POINT      <>
MSG ENDS
Parametry jsou: hWnd je handle okna, kterému je zpráva určena, message je číslo zprávy, wParam a lParam jsou další informace týkající se zprávy, time je čas kdy byla zpráva poslána a pt jsou souřadnice myši v okamžiku odeslání zprávy.
POINT STRUCT
  x  DWORD ?
  y  DWORD ?
POINT ENDS
Smyčka:
StartWhile:
   invoke GetMessage,ADDR msg,NULL,0,0 ; vyzvednuti zpravy z fronty zprav
   cmp eax, 0 ; 0=WM_QUIT= konec
   je KonecWhile ; konec
   invoke TranslateMessage, ADDR msg ; prevod stisknutych klaves zpravy
   invoke DispatchMessage, ADDR msg ; odeslani zpravy procedure okna
  jmp StartWhile
KonecWhile:
Důležité je volání funkce DispatchMessage, která předá zprávu proceduře okna (window procedure) , tj. funkci WndProc. Kód programu je až do této chvíle je v podstatě totožný v řadě různých aplikací. Hlavní rozdíl je právě v proceduře okna, která určuje, jak bude program reagovat na různé zprávy.

3.3 Zprávy a procedura okna WndProc
Podívejme se jak systém zpráv funguje: Nejdříve musí nastat nějaká událost, Windows tuto událost převedou na zprávu a umístí ji do fronty zpráv, odtud ji získá aplikace (GetMessage) a předá ji proceduře okna (DispatchMessage), což probíhá v nekonečné smyčce. Procedura okna (WndProc) provede nějakou akci v závislosti na tom jaká zpráva ji byla doručena. Procedura okna:
WndProc proc hWin :DWORD,uMsg :DWORD,uMsg :DWORD,wParam :DWORD,lParam :DWORD
LOCAL hdc : HDC ;handle kontextu zarizeni
LOCAL ps : PAINTSTRUCT
LOCAL rect: RECT
cmp uMsg, WM_DESTROY ; zniceni okna
   je wmdestroy
cmp uMsg, WM_MOVING ; pohyb okna
   je wmoving
cmp uMsg, WM_PAINT ; prekresleni okna
   je wmpaint
invoke DefWindowProc,hWin,uMsg,wParam,lParam
   ret
; DefWindowProc zpracovava zpravy, ktere neosetri aplikace
wmdestroy: ; vyslani zpravy WM_QUIT
  invoke PostQuitMessage,NULL
ret
wmoving: ; pri pohybu vydava PCSpeaker zvuk
  invoke MessageBeep, 0FFFFFFFFh
ret
wmpaint: ; zobrazeni textu "Ahoj svete"
  invoke BeginPaint , hWin, ADDR ps
  push eax
  pop hdc
  invoke GetClientRect, hWin, ADDR rect
  invoke DrawText , hdc , OFFSET szText,-1, ADDR rect, DT_CENTER or DT_VCENTER or DT_SINGLELINE
  invoke EndPaint , hWin, ADDR ps
ret
WndProc endp
V této proceduře okna ošetřujeme tři zprávy, WM_DESTROY, WM_MOVING a WM_PAINT. Na zprávu WM_DESTROY reagujeme voláním funkce PostQuitMessage (viz. výše). Na zprávu WM_MOVING, která říká, že se okno přesouvá po ploše, "drnčením" PCSpeakeru a na zprávu WM_PAINT, což je zpráva vyžadující překreslení vždy, když dojde k posunu okna, nebo odkrytí nějaké jeho části schované např. za jiným oknem nebo okrajem obrazovky, opakovaným vypisováním textu "Ahoj světe" Funkce DefWindowProc zpracovává standardním způsobem všechny ostatní zprávy, které jsme v proceduře okna neošetřili.

4. Shrnutí
1. Nejdříve voláme funkce GetModuleHandle k získání handle instance programu a GetCommmandLine, která vrací adresu řetězce příkazového řádku.
2. Voláme funkci WinMain
3. Naplníme strukturu WNDCLASSEX
4. Zaregistrujeme třídu okna voláním funkce RegisterClassEx
5. Alokujeme paměť pro okno funkcí CreateWindowEx, čímž získáme handle okna hWnd
6. Voláme funkci ShowWindow a UpdateWindow, která poprvé vyšle zprávu WM_PAINT
7. Vytvoříme nekonečnou smyčku, která bude ukončena zprávou WM_QUIT. Smyčka obsahuje volání funkcí GetMessage, TranslateMessage a DispatchMessage
8. Vytvoříme proceduru okna WndProc, ve které reagujeme na jednotlivé události
9. Po ukončení WinMain ještě voláme ExitProcess

Download zdrojáků zde

Tématické zařazení:

 » Rubriky  » Assembler  

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: