Články

Tisk článku Tisk článku

Škodoradostné WIN API

[Zpět na kategorii]

Datum: 14. 4. 2008 22:59       Autor: Václav Antošík       Zobrazeno: 5474x

Kategorie: Aplikace

Témata: VB.NET, VbNet.cz

Článok ukazuje základy použitia Windows Api vo Visual Basic .NET


Úvod

V tomto článku si ukážeme, ako používať vo Visual Basic .NET funkcie z knižníc Windows Application Interface(WIN API). Pre názornú ukážku som naprogramoval jednoduchú škodoradostnú aplikáciu, ktorá po spustení roztrasie všetky otvorené okná v systéme, pričom svoje okno nezobrazí ani na ploche ani na taskbare. Pri pokuse o zavretie okna aplikácie program zachytí event a nastaví e.cancel = true. Čiže stornuje zavretie okna.

image

Technické riešenie

Vytvoríme si prázdnu štandardnú aplikáciu vo Visual Studiu. Hneď pod deklaráciu triedy okna vpíšeme deklaráciu funkcií WIN API, ktoré budeme používať. Pri deklarovaní API funkcie sa používajú rezervované slová

Declare Function <menoFunkcie> Lib <menoDllKniznice> (<atr1>,<atr2>,<atr3>,<…>) as <typ>

Pre naše potreby si teda deklarujeme nasledujúce dve funkcie :

  Declare Function MoveWindow Lib "user32.dll" (ByVal hwnd As IntPtr, ByVal x As Integer, ByVal y As Integer, ByVal Width As Integer, ByVal Height As Integer, ByVal Repaint As Integer) As Integer
Declare Function GetWindowRect Lib "user32.dll" (ByVal hwnd As IntPtr, ByRef lpRect As RECT) As Integer

Ako vidno obe sa nachádzajú v knižnici user32.dll. Funkcia MoveWindow presunie okno na pozície zadané v argumentoch tejto funkcie. Čiže x – Xová pozícia ľavého horného rohu okna, y – Ynová pozícia ľavého horného rohu okna, width – Šírka okna v pixeloch rátaná od premennej x, height – Výška okna v pixeloch rátaná od premennej y. Pozorný čitateľ si určite všimol, že som nespomenul argument hwnd. Urobil som tak naschvál lebo mu bude venovaný nasledujúci odstavec.

 

Window handle

Operačný systém Windows dostal názov aký má pravdepodobne preto, že sa skladá celý z okien. Pričom oknom nie je iba okno aplikácie, ale pri troche nadhľadu môžeme oknom pomenovať každý kontrol, ktorý je v systéme(napr. aj každé tlačítko má svoje vlastné hwnd). Aby sme vedeli s jednotlivými oknami rozumne pracovať potrebujeme aby každý prvok mal svoj jedinečný identifikátor. Tým je window handle, číslo, ktoré jednoznačne identifikuje okno v systéme. Takže do prvého parametru funkcie MoveWindow zadáme postupne identifikátory všetkých spustených okien.

Druhá WIN API funkcia, ktorú sme si zadeklarovali je GetWindowRect, ktorá nám zistí aktuálnu pozíciu otvoreného okna. Ako prvý parameter ide už teraz známi hwnd. S druhým parametrom je to trošku komplikovanejšie. Vstupom do tohto argumentu je štruktúra RECT, ktorá vypadá nasledovne.

 

 Public Structure RECT
Public left As Integer
Public top As Integer
Public right As Integer
Public bottom As Integer
End Structure

 

Zaujímavé ďalej je, že štruktúra vstupuje do funkcie s ByRef, čo znamená, že čokoľvek WIN API funkcia zmení v našej štruktúre ostane zmenené aj po dobehnutí funkcie. Jednoducho povedané funkcia naplní do štruktúry polohu okna.

Left – pozícia ľavého rohu okna od ľavého rohu monitora v pixeloch

Right – pozícia pravého rohu okna od ľavého rohu monitora v pixeloch

Top – pozícia horného rohu okna od horného rohu monitora v pixeloch

Bottom – pozícia dolného rohu okna od horného rohu monitora v pixeloch

Ďalšou vecou, čo musíme ešte na začiatku programu zadefinovať je timer, ktorý nám bude zabezpečovať nekonečnú slučku. Zadefinujeme ho cez rezervované slovo WithEvents aby sme dokázali zachytiť udalosť tiknutia timera.

 Private WithEvents timer As System.Windows.Forms.Timer

Štartujeme

Vytvoríme si metódu, ktorá zachytáva udalosť nášho formulára Load. Ako prvé pri štarte aplikácie nastavíme formuláru aby sa nezobrazil v lište nastavením jeho vlastnosti ShowInTaskBar na false a následne ho skryjeme aby užívateľ nemohol kliknúť na krížik pomocou jeho metódy Hide. Následne vytvoríme timer a nastavíme mu opakovanie tikania každú 1 milisekundu a spustíme ho. Timer.Enabled = True.

 Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Me.ShowInTaskbar = False
Me.Hide()
timer =
New System.Windows.Forms.Timer
timer.Interval = 1
timer.Enabled =
True
End Sub

Jadro aplikácie

Jadrom našej škodoradostnej aplikácie je určite metóda timer_Tick, ktorá sa vykoná pri každom tiknutí časovača. Ako teda celé jadro funguje. Najprv si vytvoríme zoznam všetkých procesov, ktoré sú v systéme. Pomocou cyklu prechádzame celý zoznam pričom zaujímavé sú pre nás iba tie procesy, ktoré majú okno s vyplneným titulkom. Ak sa nájde také okno vygeneruje sa náhodné číslo od -5 po 5 a uloží sa do premennej ranNum. Pomocou funkcie GetWindowRect zistíme aktuálnu polohu okna a uložíme ju do štruktúry r. Nakoniec zavoláme funkciu MoveWindow a do parametrov jej zadáme položky zo štruktúry r a pričítame náhodne vygenerované číslo. V poslednom argumente funkcie je zadané číslo jedna. Tento argument totiž môže nadobúdať iba dva stavy. Nula a Jedna. Nula znamená, že pri presune okna sa jeho stará pozícia neprekreslí a vykreslí sa len nová. V praxi to potom vypadá tak, akoby okno za sebou nechávalo pás. Keď nastavíme argument na jednotku okno sa štandardne pri presune prekresľuje. Keď túto operáciu opakujeme rýchlo a často vytvára sa efekt akoby okno kmitalo okolo určitého miesta.

 

  Private Sub timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles timer.Tick
Dim processes() As Process = Process.GetProcesses 'Nacitame vsetky procesy v systeme
Dim r As RECT, random As New Random, ranNum As Integer
For i As Integer = 0 To processes.Length - 1 'Cyklus cez vsetky procesy
If Not processes(i).MainWindowTitle = String.Empty Then 'Ak ma okno procesu vyplneny titulok
ranNum = random.Next(-5, 5) 'Vygenerujeme nahodne cislo
GetWindowRect(processes(i).MainWindowHandle, r) 'Do r nahrame aktualnu poziciu okna
'Presunieme okno
MoveWindow(processes(i).MainWindowHandle, r.left + ranNum, r.top + ranNum, r.right - r.left + ranNum, r.bottom - r.top + ranNum, 1)
End If
Next
End Sub

Nedám sa zavrieť

Cieľom našej škodoradostnej aplikácie je ostať čo najdlhšie v behu. To znamená nedať sa zatvoriť. V metóde Form1_FormClosing potom nastavíme CancelArgument rovné True. To spôsobí, že sa aplikácia pri požiadavke systému o zavretie nezavrie.

 Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
e.Cancel =
True
End Sub

Záver

Naša aplikácia je hotová a pripravená na poslanie mailom neskúsenému kamarátovi alebo na predvedenie v školských učebniach :-). Dúfam, že som aspoň načrtol cestu ako sa dá pracovať vo Visual Basic .NET s Windows Application Interface.

Všetky konštruktívne otázky, poznámky a opravy k článku sú vítané.

Celý zdrojový kód si môžete stiahnuť tu


> Na začátek

 

Hodnocení:

Hlasů: 12
Zvolte své hodnocení

Václav Antošík

Momentálne sa pohybujem prevažne v Bratislave, kde pracujem ako Visual Basic .NET junior vývojár. Popri tom študujem STU SjF - Mechatronika

Související články

Žádné související články nebyly nalezeny.

RSS Feed RSS Feed

Diskuse

Několik dotazů ohledně zdrojového kódu

Datum: 15.4.2008 13:51
Autor: Ondřej Linhart
Hodnocení autora: 422
Příspěvků: 1249
Měl bych několik dotazů k vašemu zdrojovému kódu:

- Z jakého důvodu voláte funkci Randomize() v metodě Form1_Load? Volání této funkce je zcela zbytečné, má smysl pouze v případě, že používáte zastaralou funkci Rnd, inicializace generátoru náhodných čísel proběhne automaticky v konstruktoru třídy Random...

- Z jakého důvodu přepisujete funkčnost metody OnClosing, když můžete použít událost FormClosing?

- Z jakého důvodu deklarujete timer jako Public?

Mimochodem zkratka API znamená Application Programming Interface a netýká se pouze Windows.
 
           [Odpovědět]
 
Hodnocení: 7 Čekejte, prosím...

Re: Několik dotazů ohledně zdrojového kódu

Datum: 15.4.2008 22:19
Autor: Václav Antošík
Hodnocení autora: 38
Příspěvků: 101
Článok prejde úpravou. Ďakujem za pripomienky.
To, že sa API týka výhradne windows tuším v článku nie je spomenuté.
 
           [Odpovědět]
 
Hodnocení: 6 Čekejte, prosím...

Praktická hodnota

Datum: 15.4.2008 16:35
Autor: Petr Zajíc
Hodnocení autora: 95
Příspěvků: 226
Mě hlavně fascinuje ten totální nedostatek invence. Nedala by se namísto škodolibé aplikace napsat - s využitím stejných postupů - aplikace nějakým způsobem užitečná?
 
           [Odpovědět]
 
Hodnocení: -10 Čekejte, prosím...

Re: Praktická hodnota

Datum: 15.4.2008 22:21
Autor: Václav Antošík
Hodnocení autora: 38
Příspěvků: 101
Áno skutočne by sa dala. Nech sa páči s chuťou do toho. Aplikácia v článku je na ilustračné účely. Na podobné pripomienky už nebudem reagovať.
 
           [Odpovědět]
 
Hodnocení: 6 Čekejte, prosím...

Re: Praktická hodnota

Datum: 23.4.2008 11:32
Autor: Tomáš Jecha
Hodnocení autora: 541
Příspěvků: 1088
Já si myslím, že článek hezky popisuje princip využívání API v .NETu. Díky.
 
           [Odpovědět]
 
Hodnocení: 3 Čekejte, prosím...

Je to OK.

Datum: 26.6.2009 14:41
Autor: Patrik Šimon
Hodnocení autora: 2
Příspěvků: 5
Toto je prvý článok v ktorom je API podané po lopate. Ja som spokojný. Poväčšinou nikdy nekopírujem použitý "učebný" materiál, radšej si vždy nájdem využitie na vlastnom nápade. Boli tu už aj užitočnejšie ukážky a tiež by im bolo možné čo to vytknúť. Myslím, že je dôležité podporiť všetkých, ktorí si nájdu čas a majú vôľu niečo "prezradiť". Niekedy aj v triviálnom programe sa nájdu veci užitočné alebo praktické.

Dík za ponúknuté informácie...
P.
 
           [Odpovědět]
 
Hodnocení: 1 Čekejte, prosím...
 

VBNET.CZ | © 2007 Tomáš Herceg, Tomáš Jecha | Kopírování a přejímání jakéhokoliv obsahu z tohoto webu je bez písemného svolení autorů zakázáno.