Pozyteczne procedury i tricki
Jak zdobyc wiersz polecen
Jak stworzyc Dialoga
mozliwosci funkcji ShellExecute
Watki
okna innych programow
pliki .ini, tworzenie i wykorzystywanie
Wiersz polecen
Zeby zdobyc wiersz polecen wystarczy wywolac funkcje GetCommandLineA i to wszystko,
w eax mamy adres naszej lini. Nasz wiersz polecen wyglada nastepujaco: [ "sciezka naszego proga" parametry ].
wystarczy tylko usunac to co jest pomiedzy " " i mamy parametry.
Ta mala procedurka zrobi to za ciebie:
znacznik db 0 ;naszza flaga
; jezeli po zakonczeniu funkcji
;znacznik=0 znaczy to ze nie ma argumentow
;znacznik=1 sa argumenty, ich adres wskazywany przez eax
wsk01:
mov dl,byte ptr [eax]
cmp dl,22h
je wiersz
inc eax
jmp wsk01
wiersz:
inc eax
mov dl,byte ptr [eax]
cmp dl,22h
je wsk02
jmp wiersz
wsk02:
inc eax
inc eax
mov dl,byte ptr [eax]
test dl,dl
je nie_ma
mov znacznik,1
ret
nie_ma:
ret
...i w eax mamy adres do argumentow z naszej lini.
go up
ShellExecuteA
Funkcja ShellExecuteA wywoluje programy lub polecenia.
O to jej opis:
HINSTANCE ShellExecute(hwnd, lpszOp, lpszFile, lpszParams, lpszDir, wShowCmd)
HWND hwnd; /* handle of parent window */
LPCTSTR lpszOp; /* address of string for operation to perform */
LPCTSTR lpszFile; /* address of string for filename */
LPTSTR lpszParams; /* address of string for executable-file parameters */
LPCTSTR lpszDir; /* address of string for default directory */
INT wShowCmd; /* whether file is shown when opened */
Teraz opisze kilka jej praktycznych zastosowan.
Pierwsza: wyslanie e-maila.
push 0
push 0
push 0
push offset komenda ;zaraz wwyjasnie
push 0
push 0
call ShellExecuteA
;lub
call ShellExecuteA,0,0, offset komenda,0,0,0 ;latwiej ;)
;teraz ta komenda, podam wam jeszcze kilka mozliwosci:
komenda db 'mailto:t0udi@box43.gnet.pl',0 ;mail
komenda db 'http://www.assembler.hg.pl',0 ;starona
komenda db 'calc.exe',0 ;calculator ;)
;dobra a teraz kolej na cos trudniejszego, powiedzmy: restart windy
call ShellExecuteA, 0, 0, offset komenda, offset parametr,0 ,0
komenda db 'rundll.exe',0
parametr db "user.exe,exitwindowsexec",0
;i jeszcze jedna rzecz: drukowanie
call ShellExecuteA, 0, offset znacznik, offset plik, 0,0 ,0
znacznik db 'print',0
plik db 'plik.doc',0
;powyzszy kod odpali worda, ktory zacznie drukowac plik
;jezeli czegos nie rozumiesz to polecam obejrzec dokladny opis tej funkcji
go up
Dilog box
Aby stworzyc dialoga nalezy uzyc funkcji DialogBoxParamA, oto opis jak jej uzywac (jednak z gory podkreslam ze najlepiej czytac i ogladac przyklad, jezeli czegos nie zrozumiesz to smailo pisz)
Dialog Box to nic innego niz okienko w ktorym mozemy umiescic rozne rzeczy ale "najwazniejsze" sa te miejsca gdzie mozna wpisywac txt;))). W przeciwienstwie do okien w dialogach mozemy miec kilka tych "miejsc"i zmieniac je za pomoca tab'a. Dialogi mozemy podzielic na dwa rodzaje: systemowe i modalne. Systemowa to sa te ktore bedziemy tworzyli czyli zwykle okienka zrobione przez usera, modalne natomiast to te ktore sa tzw. "Always on top" (aby zrobic modalnego boxa w pliku resource, tam gdzie jest opisany styl pudelka, trzeba dodac DS_SYSMODAL). Na poczatek kilka informacji o tym co potrzebujemy aby stworzyc takiego Dialoga. Najwarzniejsza rzecza jast plik resource, jest to plik txt z rozszerzeniem .rc lub binarny z .res. Mozna go napisac samemu lub skorzystac z gotowego edytora (ja korzystam z Resource Workshop firmy Borland). Dobrze a teraz przejdziemy do tego co w takim pliku zanjduje sie. Sa tam zawarte informacje o tym jak powinien wygladac nasz dialog, ile i jakie guziki lub/i inne elementy powinien zawierac... . Kazda rzecz zawarta w takim pliku aby mogla byc uzyta (np. chcemy wiedziec o tym czy jakis guzik zostal nacisniety) musi posiadac swoj identyfikator. Identyfikator musimy takze zdefiniowac w pliku asm najlepiej jako stala np.
guzik_1 equ 100
trzeba pamietac ze aby to wszystko dzialalo identyfikator z rc i asm musi byc taki sam, (tzn. numer) a nazwa moze byc dowolna. Zreszta lepiej to zrozumiesz ogladajac przyklad: example
Opis(z jakiegos "helpa" borlanda):
int DialogBoxParam(hinst, lpszTemplate, hwndOwner, dlgprc, lParamInit)
HINSTANCE hinst; /* handle of application instance */
LPCTSTR lpszTemplate; /* identifies dialog box template */
HWND hwndOwner; /* handle of owner window */
DLGPROC dlgprc; /* address of dialog box procedure */
LPARAM lParamInit; /* initialization value */
Teraz przedstawie kilka funkcji ktore pomoga przy dialogu:
EndDialog
Funkcja konczy "dialoga" wywolywana jest z dwoma argumentami:
pierwszy leci na stos "return value" (ja tu klade 0)
drugi to handle naszego naszego dialoga
SendDlgItemMessage
Ta funkcja jest bardzo przydatna, pozwala wykonywac wiele rzeczy z naszym DialogBox'em np. pobrac txt:
push offset bufor ;of. naszego bufora
push 20 ;max liczba znakow do pobrania
push WM_GETTEXT ;wiadomosc o tym ze chcemy zabrac tekst
push edit_id ;identyfikator naszego miejsca na tekst (tenz pliku .rc)
push hwnd ;hwnd naszego Box'a
I jeszcze jedna bardzo wazna rzecz, jezeli jestes leniwy mozesz zamiast klasc wszystkie argumenty na stos wywwolac funkcje call ze wszystkimi argumentami: call GDZIES ,arg_1, arg_2 ...
ale w tym przypadku argumenty musza isc w kolejnosci takiej jak sa podane (odpowiednik masmowego invoke).
Opis:
SendDlgItemMessage proto hwndDlg:DWORD,\
idControl:DWORD,\
uMsg:DWORD,\
wParam:DWORD,\
lParam:DWORD
go up
Watek(thread)
Watek jest czyms w rodzaju procesu ktory wykonuje sie nizaleznie od tego co dzieje sie z windowsem lub naszym programem, jest to procedura ktora dziala sobie w tle. Bardzo ciezko jest dokladnie opisac czym jest watek wiec jezeli Cie to bardzo interesuje to polecam tutotriale Iczeliona.
W naszym programie mozemy tworzyc nieskonczona ilosc watkow i wykorzystywac je do czego chcemy (np. do ciezkich obliczen, operacji na elementach okna...)
Tworzyc watki bedziemy za pomoca funkcji CreateThread, oto jej opis:
LPSECURITY_ATTRIBUTES lpsa; /* address of thread security attrs */
DWORD cbStack; /* initial thread stack size */
LPTHREAD_START_ROUTINE lpStartAddr; /* address of thread function */
LPVOID lpvThreadParm; /* argument for new thread */
DWORD fdwCreate; /* creation flags */
LPDWORD lpIDThread; /* address of returned thread ID */
Aby porozumiewac sie z watkami mozemy uzywac: zmienych globalnych (to te ktore deklarujemy na poczatku naszego programu, wiadomosci okna (windows message), oraz event object. Ja zajme sie tymi dwoma pierwszymi metodami.
A teraz opisze jak uzywac tej wyzej wymienionej funkcji.
push offset _hThread ; identyfikator watka
push 0
push 0
push offset procedura ; offset do procedury ktora zostanie wywolana
push 0
push 0
call CreateThread ;tworzymy watek
lub
call CreateThread,0,0, offset procedura,0,0, offset _hThread ;latwiej
Procedura do ktorej podalismy offset zostanie wywolana zaraz po stworzeniu watka. Windows zakonczy nasz watek w momencie gdy w zakonczymy nasza funkcje instrukcja: ret. Lub mozemy uzyc funkcji ExitThread. Przepraszam za chaotycznosc tego wszystkiego ale mam nadzieje ze wszystko rozumiesz, jezeli nie to pisz. Teraz pokaze jak moze wygladac procedura watku.
procedura PROC
wsk01:
... ;jakies instrukcje
jmp wsk01 ;jezeli chcemy aby w tym miejscy watek zakonczyl sie
;wystarczy uzyc instrukcji ret
ENDP
Jezeli chcemy przekazac cos do naszego okna mozemy uzyc funkcji PostMessageA
tylko MUSIMY PAMIETAC ZE UCHWYT OKNA MUSI BYC ZDEFINIOWANY W ZMIENNYCH GLOBALNYCH, czyli jezeli uchwyt okna zostal zdefiniowany w procedurze obslugi: "dlgproc PROC uses ebx edi esi, hwnd:DWORD..." to trzeba "przekopiowac" uchwyt do jakiejs zmiennej globalnej. Wiec w czesci .data naszego programu utworzyc taka zmienna np. thwnd dd 0, i podczas inicjalizacji dialoga:
push hwnd
pop thwnd
Caly czas mam nadzieje ze to rozumiesz ;). I teraz w watku mozemy smialo uzywac zmiennej thwnd. Jezeli chcesz zobaczyc do czego w praktyce mozna uzywac watkow mozesz sciagnac moje "intro". Pozostala jeszcze jedna sprawa
jak powinna wygladac wiadomosc ktora chcemy przeslac do okna. W windowsie jest taka wiadomosc: wm_user i kozystajac z nij mozemy stworzyc swoje wlane wiadomosci:
nasza_wiadomosc equ wm_user + 1
Jezeli cos jest nie jasne to sprobuj zobaczyc przyklad, lub napisz do mnie :).
cdn...
go up
Okna innych programow
Postanowilem napisac ta czesc gdyz pare osob pytalo mnie o ten program zmieniajacy nazwy innych okienek. Zaczne od opisu funkcji FindWindowA:
HWND FindWindow(lpszClass, lpszWindow)
LPCTSTR lpszClass; /* address of class name */
LPCTSTR lpszWindow; /* address of window name */
czyli:
call FindWindowA, 0, offset nazwa
(nazwa jest zdefiniowana jako zwykla zmienna: nana db 'dffdssfd',0).
Ja uzylem tylko drugiego parametru czyli nazwy okna (window's title) dlatego, ze nazwe okna mozna zawsze latwo zdobyc. Oczywiscie jezeli znasz mozesz uzywac parametru 'class name' ale jak juz wspomnialem nazwe okna jest latwiej zdobyc. Wiec gdy juz ja mamy wywolujemy funkcje FindWindowA a ona zwraca nam w eax uchwyt do tego okna (czyli hwnd). Majac hwnd chyba nie musze pisac co mozemy zrobic z oknem, jednak napisze ;).
teraz taka mala dygresja, opisze dwie funkcje: PostMessageA i SetWindowTextA.
Pierwsza PostMessageA sluzy do przekazywania wiadomosci do okna, oto jej opis:
BOOL PostMessage(hwnd, uMsg, wParam, lParam)
HWND hwnd; /* handle of destination window */
UINT uMsg; /* message to post */
WPARAM wParam; /* first message parameter */
LPARAM lParam; /* second message parameter */
czyli:
call PostMessageA, hwnd, wiadomosc, 0,0
wiadomosci jakie mozemy przekazac to glownie wiadomosci z serii WM_.
Druga funkcja: SetWindowTextA sluzy, wbrew pozorom, do zmiany nazwy okna. Wywolujemy ja z dwoma parametrami:
call SetWindowTextA, hwnd, offset nowa_nazwa_okna
;gdzie:
nowa_nazwa_okna db 'Moj program v.3.6',0
Wracajac do tematu, znajac juz te dwie funkcje mozemy zrobic z kazdym(prawie) oknem co chcemy
np. jezeli chcemy zniszczyc okno wystarczy wyslac mu wiadomosc (czas umierac ;) ): WM_CLOSE
Jezeli natomiast chcemy zmienic mu nazwe wystarczy uzyc funkcji SetWindowTextA.
Jezeli chcesz to mozesz sciagnac moj program sluzacy do zmieniania nazw okienek: sciagnij
go up
Pliki .ini
Czasami zdarza sie ze Twoj program musi sobie zapamietac jakies dane a Tobie nie bardzo sie chce towrzyc nowy plik i zapisywac w nim wszystko. Wtedy z pomoca przychodza nam rejestr i pliki .ini. O rejestrze windowsa napisze innym razem, teraz opisze podstawowe funkcje dotyczace plikow ini.
Zaczne od opisu w jaki sposob w plikach ini sa przechowywane dane:
[section]
entry=string
.
.
.
A teraz opis funkcji: WritePrivateProfileStringA:
BOOL WritePrivateProfileString(lpszSection, lpszEntry, lpszString, lpszFilename)
LPCSTR lpszSection; /* address of section */
LPCSTR lpszEntry; /* address of entry */
LPCSTR lpszString; /* address of string to add */
LPCSTR lpszFilename; /* address of initialization filename */
Funkcja ta zapisuje do pliku ini nowa wartosc (string). Wprzypadku kiedy funkcja nie znajdzie pliku ini jest on tworzony. Ponadto jezeli funkcja zanjdzie plik ale nie bedzie w nim podanej sekcji to tez zostanie ona stworzona itd...
...acha warto jeszcze wspomniec ze gdy nie podamy zadnej sciezki naszego pliku to plik ini zostanie utworzony w katalogu windowsa
plik db 'nowy.ini',0
string db 'bleble12345',0
entry db 'hej',0
section db 'nasze',0
call WritePrivateProfileStringA, offset plik, offset string, offset entry, offset section
Po wywolaniu powyzszego kody w katalogu Windowsa znajdzie sie plik o nazwie nowy.ini, ktory bedzie wygladal tak:
[nasze]
hej=bleble12345
Mam nadzieje, ze wszystko jasne. Teraz opisze jak odczytywac cos z tego pliku. Do odczytywania plikow ini sluzy funkcja: GetPrivateProfileStringA
DWORD GetPrivateProfileString(lpszSection, lpszKey, lpszDefault, lpszReturnBuffer, cchReturnBuffer, lpszFile)
LPCTSTR lpszSection; /* address of section name */
LPCTSTR lpszKey; /* address of key name */
LPCTSTR lpszDefault; /* address of default string */
LPTSTR lpszReturnBuffer; /* address of destination buffer */
DWORD cchReturnBuffer; /* size of destination buffer */
LPCTSTR lpszFile; /* address of initialization filename */
i jej zastosowanie:
plik db 'nowy.ini',0
entry db 'hej',0
section db 'nasze',0
string2 db 'xxx',0
bufor db 100 dup(0)
call GetPrivateProfileStringA, offset plik,100, offset bufor, offset string, offset entry, offset section
Wyjasnienia wymaga chyba tylko parametr 3: address of default string, u nas string2. Jest to string ktory znajdzie sie w buforze gdyby funkcja nie znalazla szukanego klucza ( key lub entry).
I to by bylo chyba na tyle, jezeli czego nie zrozumiales i masz z czyms problem to pisz.
go up
cdn...
na glowna
|