|
ApEl - Bedřich Havlíček Lužice 23, 785 01 Šternberk tel/fax 0643 - 411917 liwin@liwin.cz |
Pyrotechnikem
snadno a rychle
aneb Udělej si sám...
Stránka je dost bohatá
obsahem.
Vzhledem k výši telefonních poplatků doporučuji stáhnout a
prostudovat Offline.
A za výši telefonních poplatků doporučuji stáhnout
zaživa... však víte koho.
Nebudu vám radit, jak vyrábět
semtex, jak míchat Molotovovy koktejly, nebo jak foukat
do bublifuku, aby bubliny byly co největší,
nejnatlakovanější a s maximální explozivní silou. Dám vám jen pár tipů, jak zužitkovat počítač trochu jinak ( a lépe ), a taky jak dát svým bližním najevo svou náklonnost - pravda, trochu neobvyklým způsobem, ale lépe neobvykle, než vůbec. A hlavně snad konečně pohnu návštěvníky našich stránek a probudím je z jejich letargie -vždyť za dlouhé dva měsíce existence prachárny nepřišel žádný příspěvek, nápad, nebo alespoň litánie rozhořčeného postiženého. Jako by lidová tvořivost na tomto poli snad ani neexistovala. |
Princip atentátu - řečeno s klasikem - je
jednoduchý jako Kolumbovo vejce .
Stejně tak princip bomby je prost jakýchkoli obtížností a
záludností - alespoň co se softwarových bomb týče, i když
řekl bych, že to platí obecně.
Popíšeme si zde jeden typ bomby - ten nejjednodušší,
nejméně nebezpečný, ale současně mnohotvárný a poměrně
účinný.
Bombu samotnou můžeme rozdělit do tří základních částí:
Vytvořit bombu v LiWin je snadné. Však taky první naše bomby vznikly za účelem propagace tohoto programovacího prostředku.
Časovač
První potřebnou ingredienci - časovač - máme k dispozici v
každém objektu. Vložíme si tedy do aplikace nějaký objekt,
nejlépe univerzální vizuální objekt - to kdybychom chtěli
do časovače doplnit nějaké funkce, třeba nastavování
pomocí vložených řídících prvků. Objekt nazveme třeba
Timer.
Spuštění časovače je jednoduché:
Timer_Start( Elapse, Count);
kde Elapse udává časový
interval jednotlivých tiků, Count pak počet tiků, po kterém
je činnost časovače ukončena. Interval standartně
nastavujeme na 1sekundu, takže jako Count pak stačí zadat
požadované zpoždění v sekundách.
Spuštěný časovač pak v pravidelných intervalech volá
metodu UTM_Tick( Count ); které v parametru Count předává
zbývající počet tiků. Tuto metodu potřebovat nebudeme,
během čekání ( číhání ) nepožadujeme od bomby žádnou
činnost - naopak je žádoucí, aby zatěžovala systém co
nejméně. Takže tuto metodu nebudeme definovat. Nadefinujeme
pouze metodu UTM_Stop, která je volána při ukončení
činnosti časovače (přetečení).
A v této metodě pouze zavoláme další prvek naší bomby -
detektor aktivity.
A nějak takhle může vypadat programové vybavení objektu
Timer:
*********** Object
Timer ************
Func Start( Delay );
** Spusteni bomby se zpozdenim DELAY **
{
Show( MainWindow,0 ); ** Schovani okna bomby **
Timer_Start(
1, Delay ); ** Spusteni casovace **
}
Serve UTM_Stop; ** Preteceni casovace **
{ Detector.Start; ** Spusteni detekce aktivity **
}
Detekce aktivity
Příkaz v obsluze události
UTM_Stop je volání detektoru aktivity, který si nadefinujeme v
dalším objektu. Tentokrát můžeme použít nejjednodušší
objekt - aktivní rám - neboť v tomto prvku nebude třeba nic
nastavovat či zobrazovat. Využijeme opět pouze jeho časovač.
Detektor bude tikat donekonečna, a v pravidelných (opět
sekundových) intervalech kontrolovat, zda je počítač v klidu.
Zjistí-li aktivitu, odpálí nálož.
Pro detekci aktivity jsme do LiWin zařadili jednoduchou funkci
GetActivity ( ach ty názvy ), která zkoumá, zda se mezi
jednotlivými voláními funkce pohnul kurzor. Pravda, šlo by
zjistit daleko více, ale nechtěli jsme zbytečně zasahovat do
činnosti Windows - v praxi bohatě stačí uvedený způsob.
Takhle tedy bude vypadat programové vybavení detektoru:
************ Object
Detector ************
Func Start;
{ Timer_Start(1,0); ** nastaveni casovace na 1s,
nekonecne cyklu **}
serve
UTM_Tick; **
obsluha tiku casovace **
{ if ( GetActivity > 0 ) then {
timer_stop; ** pri
zjisteni aktivity stopni casovac **
Charge.Boom; **
a odpal naloz **
}
}
vizuální efekty mohou proběhnout v okně samotné bomby, které pro tento účel znovu ukážeme. Okno můžeme přemístit na požadovanou pozici a dát mu žádanou velikost příkazem MoveObject - při tom nezapomeňte, že musíte použít souřadnicovou soustavu LiWin, čili 0-100 v obou osách. Co v okně ukážete, záleží na vás, v tomto směru poskytuje LiWin dostatek možností.
vizuální efekt proběhne
v okně právě aktivní aplikace - tento způsob je
efektnější, ale nevyužijete zde plně grafické
možnosti LiWin - animace, pohyb a.j. - pro kreslení v
cizích oknech jsou možnosti poněkud omezené, neboť
se zde využívá standartní Windows mechanismus
kreslení.
Pro zjištění cíle využijeme funkci GetActiveWindow,
která vrací handle právě aktivního okna. A do
cizího okna můžeme vykreslit obsah určeného objektu,
respektive jeho aktuálně nastavený pohled, příkazem DrawToWin(
Source, Target, x, y, width, height), kde Source
je objekt nebo handle objektu, jehož pohled (grafické
rozhraní) chceme zobrazit, Target je handle objektu, do
něhož budeme promítat, a zbytek jsou souřadnice.
Například by to mohlo vypadat takhle - funkce je
definovaná v objektu Charge:
Func Boom;
{ View(1); DrawToWin( Self, GetActiveWindow, 0, 0, 100,
100); }
V tomto případě se v objektu Charge nastaví pohled
č.1, a promítne se do právě aktivního okna na celou
jeho plochu. Bude-li součástí pohledu animace,
nezobrazí se (respektive skrytě se přehraje v objektu
Charge).
Pozor - v tomto případě se pracuje s celým oknem,
nejen s jeho klientským prostorem.
Vizuální efekt proběhne
na ploše. Pro zobrazování na ploše jsme do LiWin
přidali několik účelových funkcí pro pro rychlé
překreslování a obnovování pozadí, takže je možno
realizovat zde velmi zajímavé efekty - pohyblivé a
animované objekty, scrolling, a já nevím co ještě.
Funkce SaveDesktop uloží aktuální
vzhled plochy do bitové mapy, kterou následně
používá pro obnovení pozadí při překreslování
objektů.
Funkce DrawToDesktop vymaluje nastavený
pohled kdekoli na ploše, a při přemístění obnoví
původní vzhled - to vše bez jediného bliknutí. Při
tom fungují všechny funkce nastavení pohledu:
zapínání a vypínání vrstev, posouvání vrstev a
další, pouze vrstvu automatické animace nelze
použít, neboť její režim vykreslování je příliš
specifický a nebylo jej možno zobecnit.
Pro uvedení plochy do původního stavu slouží funkce RestoreDesktop,
která na plochu promítne bitovou mapu vytvořenou
příkazem SaveDesktop, nebo funkce RedrawWindow(
0 ), která aktivuje standartní mechanizmus
Windows pro překreslení okna, v tomto případě
plochy.
Po ukončení činnosti na ploše doporučujeme uvolnit
kopii plochy z paměti - k tomu slouží funkce ReleaseDesktop.
pro explozi použijeme
nějaký standartní Windows box - například chybové
hlášení. V LiWin BASIC můžete takto použít zatím
pouze MessageBox, který slouží pro zobrazení
informací, hlášení, výstrah a podobně - v tom
případě nepotřebujeme objekt Charge, ale stačí
změnit volání nálože na volání přímo MessageBoxu
- bude to vypadat takto:.
MsgBox( Message, Title, Spec); viz manuál.
Jinak není žádný problém kterýkoli box napodobit -
většinou je to jen otázka kreslení.
Další možností je
použít zdroje, respektive aplikace přidružené k
vloženým snímkům. Tímto způsobem můžete třeba
přehrát video nebo jiný multimediální soubor v
přidruženém zařízení, či otevřít grafický nebo
textový editor - v podstatě můžete udělat cokoli.
V tomto případě nevkládejte do snímkové kolekce
objektu samotný soubor, ale propojovací balíček.
Uděláte to takhle:
- najděte požadovaný soubor, který budete chtít
spustit
- klikněte na jeho ikonu pravým tlačítkem a
zkopírujte do schránky
- v LiWin otevřete snímkovou kolekci (film) určeného
objektu (Charge), a vložte obsah schránky do filmu
V tomto případě se do filmu zkopíruje pouze
propojovací balíček s odkazem na vybraný soubor a s
některými dalšími informacemi. Tento balíček
zabírá jen málo místa v paměti.
Výbuch potom bude vypadat takhle:
Func Boom;
{ OpenObject( self, Slide, Verb); }
O funkci OpenObject se
dočtete v manuálu - stručně řečeno aktivuje OLE
objekt vložený do snímkové kolekce na pozici Slide
určeného objektu způsobem daným v parametru Verb.
Příkaz OpenObject(self, 1, 1)
například aktivuje první snímek vlastního objektu
prvním možným způsobem ( většinou je to editace)
O dalších možnostech a
způsobech by se daly napsat stohy stránek - Kenneth Starr by
jimi jistě naplnil pár kamionů, a zdaleka by danou
problematiku ani sebe nevyčerpal. Něco k tomu najdete v
manuálu, a něco zjistíte sami, takže půjdeme dál.
Výbuch lze samozřejmě doplnit zvukem - a to opět buďto
přehrávačem daného formátu prostřednictvím příkazu OpenObject,
a nebo vnitřním přehrávačem zvuků (u LiWin Basic pouze ve
formátu WAV) příkazem Sound_Play( FileName).
Co po výbuchu...
Tady jsou v podstatě dvě možnosti - buďto po výbuchu bombu
odstranit, nebo ji spustit znovu. Oba případy jsou stejně
jednoduché. V prvním případě vložíme do funkce Boom
příkaz CloseWindow( MainWindow). A v druhém
případě jednoduše zavoláme metodu Start objektu Timer - asi
takto: Timer.Start( NewDelay); kde newDelay je
nově zadané zpoždění.
Malý příklad
Zkusme si sestrojit
nejjednodušší LiWin bombu, která bude pouze zobrazovat
předdefinovaná chybová hlášení. Hlášení budou
definována v poli řetězců Error, a budou se náhodně
zobrazovat v "znáhodněných" pravidelných
intervalech. Časy budou zadávány jako parametry při
spuštění aplikace.
Bomba se bude skládat z objektů Timer a Charge, součástí
objektu Charge bude detekce aktivity. Objekty vložíme do
aplikace ( stačí aktivní rámy, i když je to jedno, můžete
tam vložit cokoli), a nadefinujeme jim následující program:
****** Bomba Errors - Object Timer *******
Func Init; **
Inicializace objektu Timer, lokalni definice**
{
Delay = getparam(1); **
Nastaveni Time podle prvniho parametru **
If (Delay = 0) then {Delay = 10;} ** Pokud
neni zadan, nastavi se na 10**
}
Func Start( Dl); **
spusteni budiku **
{
Show(MainWindow, 0); ** Schovej se **
timer_start(1, Dl); ** a
natoc si budika **
}
Func Run; **
start programu **
{ ** Spusteni bomby pri startu aplikace**
Start( Delay);
}
Serve UTM_Stop; **
Co delat, kdyz timer dotika **
{ Charge.GetUp; **Naloz!!! Vstavat !!! **
}
** Konec programove definice
objektu Timer **
****************** Object Charge ********************
Func Init; **
inicializace objektu Charge - lokalni definice ***
{ ArrayStr Error(1..100);
NextDelay
= GetParam(2); ** cas pro opakovane spousteni **
Errorcount
= 100; ** definujte podle
poctu skutecne definovanych hlaseni **
Error( 1) = ' Nevím, co se to se mnou děje,
kámo.
Nějak se mi to vymklo z rukou.' ;
Error( 2) = ' Porušení ochrany na adrese
00A7:78AC
Pravděpodobně přehřátá elektronka PCL85
Do jejího zchládnutí bude uvedená paměťová lokace
nepřístupná' ;
** Definice dalsich Erroruuu **
}
Func GetUp;
** Probuzeni bomby - start detekce aktivity**
{ Timer_Start(1, 0);}
Serve UTM_Tick; **
Obsluha tiku casovace **
{ if (GetActivity>0) then {
Timer_Stop; **
Zastaveni casovace **
MsgBox( ' Error', error( random( 1, ErrorCount)
), mb_Ok + mb_Exclamation); ** zobrazi se box **
if ( NextDelay>0 ) then
{
** pokud je zadan cas pro opakovani **
Timer.Start( noise(
NextDelay, NextDelay/3); ** znovu zapal doutnak **
} else
{
** jinak **
closewindow( MainWindow )
** se ztrat **
}
** Restart bomby s casem NextDelay ( plus minus
30%), je-li NextDelay > 0 **
}
Tak to je všechno. Není to
zrovna složité, co říkáte ?
Detekce aktivity a exploze byly sloučeny do jednoho objektu
(Charge). Zde je taky deklarováno pole řetězců, do kterých
můžete uložit text chybových hlášení. Při tom musíte
nastavit proměnnou ErrorCount, která musí obsahovat počet
definovaných hlášení. Zobrazené hlášení se vybírá
náhodně v rozpětí 1..ErrorCount ( funkce Random).
Pokud je program spuštěn s parametrem pro opakované
zobrazení, budou se zobrazovat další chybová hlášení v
zadaném intervalu - tento interval je znáhodněn funkcí Noise
o cca 1/3.
Není-li tento parametr zadán, program se ukončí
I když to zrovna není ukázka přehledného a srozumitelného
programování. Třeba použití názvu Timer pro objekt
časovače bomby je trochu nešťastné - asi se vám v textu
programu bude plést volání systémového časovače s
voláním objektu. Tak třeba Timer.Start volá časovač bomby,
tedy metodu Start objektu Timer, kdežto Timer_Start je volání
standartní funkce, která inicializuje časovač ve vlastním
objektu.Ale nechce se mi přepisovat předchozí text, takže to
nechám tak. Snažte se však podobným zádrhelům vyhnout,
fantazii se v pojmenovávání objektů meze nekladou.
Bomby je výhodnější ukládat jako objekty. V tom případě
je třeba napřed vložit do aplikace objekt, do kterého teprve
vložíte jednotlivé prvky bomby. Po odladění pak tento objekt
uložíte jako komponentu. Takto vytvořené komponenty pak
můžete podle potřeby nahrávat a spouštět ve speciálně pro
tento účel vytvořené aplikaci
Další možnost - a mnohem výhodnější - je ukládat pouze
samotné nálože, tedy objekty, realizující samotný výbuch.
Časovač a detekce aktivity budou pracovat vždy stejně, mohou
tedy být součástí spouštěcí aplikace. V tomto případě
bude spuštění nálože vypadat takto:
If ( Charge<> 0 )
then { DeleteObject(Charge); } ** Zruseni predchozi
naloze **
LoadObject( Self, ObjectFileName, 'Charge'); **
Nacteni naloze ze souboru ObjectFileName **
První příkaz zajistí
odstranění předchozí nálože - objektu Charge - pokud je
již v aplikaci. Druhý příkaz vytvoří ve volajícím objektu
objekt Charge tak, že jej načte ze souboru daného řetězcem
ObjectFileName. V praxi bude výhodnější nahrávat nálož
přímo do hlavního okna, tedy do objektu Application. Pak
můžeme objekt nálože použít pro překrytí hlavního okna,
což bude výhodné u bomb, které pro výbuch používají
vlastní okno bomby, např. pro chybová hlášení nebo
náročné grafické efekty (animace, pohyb). V tom případě
bude prvním parametrem v příkazu LoadObject
místo Self hodnota Application.
Spuštění nálože bude automatické - při vytvoření objektu
je volána jeho metoda Init, která zajistí vytvoření
místních definovaných prvků, a po zařazení objektu do
aplikace pak jeho metoda Run, která definuje jeho činnost při
spuštění.
Do metody Run tedy můžeme umístit volání funkce,
provádějící explozi, případně ji tam přímo definovat.
Předchozí příklad by v tom případě vypadal takto:
********************* Object Charge *******************
Func Init; **
inicializace objektu Charge - lokalni definice ***
{ ArrayStr Error(1..100);
Errorcount
= 100; ** definujte podle
poctu skutecne definovanych hlaseni **
Error( 1) = ' Nevím, co se to se mnou děje,
kámo.
Nějak se mi to vymklo z rukou.' ;
** Definice dalsich Erroruuu **
}
Func Run; **
Spusteni objektu naloze**
{ MsgBox( ' Error', error( random( 1, ErrorCount)
), mb_Ok + mb_Exclamation); ** zobrazi se box **
CloseWindow(Self); ** po explozi
vypadni ( zrus se ) **
}
V tomto případě se nálož po
explozi sama zruší. Pokud toto zajistíte u všech náloží,
můžete vypustit první řádek z předchozí ukázky
spouštění náloží ze souboru.
Pozor - pro zrušení sebe sama (Self) vždy používejte funkce
CloseWindow, a ne DeleteObject. Ve druhém případě totiž
objekt sám sebe zruší ještě před ukončením vlastního
programu, což zpravidla vede k chybě.
Tímto způsobem se celá věc značně zjednodušší -
vytvoříte si pouze univerzální aplikaci, která bude
spouštět určené nálože. Aplikace bude obsahovat blok
časovače a detekce aktivity, a můžete do ní zapracovat
nastavování základních parametrů bomby pomocí vhodných
ovládacích prvků. Aplikace pak bude spouštět vybrané
nálože v definovaných intervalech a libovolně dlouho - při
tom bude v paměti minimálně překážet.
A tak můžete svým bližním připravit doslova ohňostroj
překvapení, který promění jejich práci na počítači v
jedno veliké dobrodružství.
V náložích samotných se pak můžete soustředit pouze na co
nejpůsobivější zpracování efektu výbuchu, a nemusíte
řešit problémy s načasováním a ostatními funkcemi bomby.
Můžete tak realizovat složité nálože poskládané z
libovolného množství objektů, a rozehrát před udivenými
zraky postižených uživatelů opravdové divadlo plné
pohyblivých a animovaných objektů, barev a zvuků. Jediným
limitujícím faktorem bude jen vaše fantazie.
Časem se v Prachárně v rubrice Můžete si stáhnout objeví jednak univerzální spouštěč bomb, ale taky pár zajímavých náloží. Všechno bude otevřené, takže si to budete moci detailně prostudovat.
Výhody a nevýhody LiWin
bomb
K výhodám patří především
snadná a rychlá realizace složitějších a graficky
propracovanějších bomb - více času než samotné
programování vám zabere vizuální zpracování efektu.
Hlavní nevýhodou je především nižší mobilita - zpravidla
musíte přenášet přehrávač LiWin a zdrojový soubor
aplikace, plus samozřejmě další soubory použité při
explozi ( zvuky, multimediální soubory, nebo objekty
náloží). Dále pak trochu víc zabrané paměti a
systémových prostředků, a v neposlední řadě omezené
možnosti při zobrazování grafiky mimo vlastní okno aplikace.
Nevýhody tedy převažují - LiWin bomby nejlépe využijí ti,
kteří svůj počítač sdílejí s jinými osobami, aby jim tu
a tam zpříjemnili život. A nebo pro vývoj a testování
nových bomb, které potom předěláte do nějakého kódově
efektivnějšího jazyka.
Většina EXE bomb, které najdete
v Prachárně, byla vytvořena v Borland Pascalu pro Windows.
Tento jazyk je sice dost ukecaný ( což platí o Pascalu obecně
), ale má neobyčejně efektivní kompilátor vytvářející
velmi úsporný cílový kód. A dovolí taky sahat poměrně
hluboko do Windows, což je však trochu dvojsečná zbraň -
proto radím experimentovat opatrně.
Windows aplikace zde lze vytvářet v podstatě dvěma způsoby -
objektově a neobjektově. Doporučuji první způsob, i když je
na první pohled složitější a pracnější. Nebudu se zde
rozepisovat do podrobností - pokud máte BPW, máte jistě i
manuály ( nebo ne? ), a tam je toho k přečtení až až.
Tak hezky popořadě - časovač
tu taky najdeme. Pro jeho nastavení a spuštění slouží
následující funkce:
function SetTimer(Wnd: HWnd; IDEvent: Integer; Elapse:
Word; TimerFunc: TFarProc): Word;
Zavoláním této funkce otevřete časovač, který
bude posílat zprávu WM_Timer vašemu oknu, respektive oknu,
reprezentovanému manipulačním číslem Wnd. Časovač bude
tikat v intervalech zadaných v milisekundách parametrem Elapse.
Parametr IDEvent bude sloužit pro identifikaci příslušného
časovače - aby program věděl, který časovač zrovna tiknul,
pokud jich spustíte pro dané okno více. V parametru TimerFunc
můžeme zadat callback proceduru (bude volána
"zevnitř" při ticích časovače).
Funkce vrací identifikační hodnotu, kterou budeme potřebovat
pro zrušení daného časovače ( KillTimer).
Ukažme si činnost bomby na jednoduchém příkladu: v tomto
případě se jedná o ten druhý, méně vhodný způsob -
někomu se možná bude zdát jednodušší, ale složitost a
nepřehlednost programu v tomto případě roste se čtvercem
složitosti bomby (a možná i s krychlí).
Program Bombicka;
uses wintypes,winprocs,owindows,win31;
var timer:word;
counter:longint;
ExitLoop:boolean;
NewCursorPos,OldCursorPos: TPoint;
{ realizace vybuchu - v
tomto pripade bomba minimalizuje aktivni okno}
procedure Boom;
var dc:hdc;wnd:hwnd;r:TRect;
begin
Wnd := GetActiveWindow; { Vezmi aktivni okno, }
ShowWindow( Wnd, SW_MINIMIZE); { a minimalizuj ho
}
ExitLoop := True; { ukonceni cyklu Loop -
vyrazení aplikace }
end;
{ casovac a spoustec s
detekci aktivity }
procedure
TimerProc(wnd,msg,idTimer:integer;dwtime:longint);far;
begin
if Counter > 0 then { je-li neco v pocitadle }
begin
dec(Counter); { zmensi pocitadlo}
GetCursorPos(OldCursorPos);{Ulozeni
pozice kurzoru}
end
else
begin
GetCursorPos(NewCursorPos); {Nacteni
aktualni pozice kurzoru}
If Longint(NewCursorPos)<>Longint(OldCursorPos)
then boom; {je-li zmena, bouchni}
end;
end;
{ hlavni cyklus, zpracovani
zprav Windows }
procedure Loop;
var Msg: TMsg;
begin
while (GetMessage(Msg, 0, 0, 0)) and not ExitLoop do
begin
TranslateMessage(msg);
DispatchMessage(msg);
end;
end;
{ **** Hlavni program
****}
begin
exitLoop:=false;
counter := 10;
{ zpozdeni v sekundach }
timer:=settimer(0,1,1000,@timerproc); {spusteni
casovace}
loop;
{ hlavni cyklus }
KillTimer(0,Timer); {
zruseni casovace }
end.
Tato bombička, jak jste si jistě všimli,
pouze minimalizuje právě aktivní okno. Čas zpoždění v
sekundách vložíte do globální proměnné Counter.
Jak to pracuje vám asi nemusím moc vysvětlovat.
V programu jsou tři procedury - procedura TimerProc je callback
procedura, jejíž adresa je předána časovači při jeho
nastavení v hlavním programu. Tato procedura musí být vždy far
a s uvedenými typy parametrů ( na jejich jméně nezáleží).
Procedura je volána při každém tiknutí časovače. Při tom
se dekrementuje počítadlo, tedy proměnná Counter - pokud je
hodnota počítadla větší než nula - nebo se testuje, jestli
se pohnul kurzor myši, pokud je počítadlo vynulováno. A když
se nová pozice bude lišit od původní, zavolá se procedura
Boom.
Ta realizuje vlastní výbuch. Nejprve si zjistí manipulační
číslo (handle) právě aktivního okna (funkce
GetActiveWindow), a když je má, začne tam provádět své
nekalé rejdy.
A co všechno tam může dělat? Prakticky úplně všechno -
prostřednictvím handle je možno s oknem libovolně
manipulovat. Můžete ho přemístit, zavřít, kreslit do něj,
zjistit o něm spoustu věcí a já nevím co ještě.
Na konci výbuchu nastavením proměnné ExitLoop zajistíme
ukončení cyklu v proceduře Loop. Tím se ukončí běh úlohy
a program se vyřadí z cyklu zpráv Windows.
Procedura Loop zajišťuje vlastní běh bomby, respektive její
stálou přítomnost v cyklu Windows. Cyklus přijímá zprávy
Windows a v tomto případě je kompletně propouští dál. Jak
to funguje se opět dočtete v manuálu, ale doporučuji věnovat
tomu minimální pozornost, protože tímto způsobem se dnes
Window aplikace prostě nedělají.
Podívejme se teď, jak bude stejný příklad vypadat, když na to půjdeme přes objekty:
Program Bombicka; {
tentokrat ojektove }
uses wintypes,winprocs,owindows,win31,wincrt;
Type
PBomba = ^TBomba;
TBomba = object(TWindow)
Timer:word;
Counter:Longint;
Constructor Init(AParent:PWindowsObject);
Destructor Done; virtual;
Procedure SetupWindow;virtual;
Procedure WMTimer( var Msg: TMessage);
virtual WM_First + WM_Timer;
procedure Boom;
End; TBombaApp =
object(TApplication)
procedure InitMainWindow; virtual;
end; var
NewCursorPos,OldCursorPos: TPoint;
Application:TBombaApp;
Constructor
TBomba.Init(AParent:PWindowsObject);
begin
inherited Init(AParent,'Bomba');
counter := 10; {
zpozdeni v sekundach }
end;
Procedure
TBomba.SetupWindow;
begin
inherited setupWindow;
timer:=settimer(HWindow,1,1000,nil); {spusteni
casovace}
end;
Destructor
TBomba.Done;
begin
KillTimer(HWindow,Timer);
Inherited done;
end;
procedure TBomba.Boom;
var wnd:hwnd;
begin
Wnd := GetActiveWindow; { Vezmi aktivni okno, }
ShowWindow( Wnd, SW_MINIMIZE); { a minimalizuj ho
}
free; { a muzes jit treba do ...}
end;
{ obsluha casovace a
spoustec s detekci aktivity }
procedure TBomba.WMTimer(var msg:TMessage);
begin
if Counter > 0 then { je-li neco v pocitadle }
begin
dec(Counter); { zmensi pocitadlo}
GetCursorPos(OldCursorPos); {Ulozeni
pozice kurzoru}
end
else
begin
GetCursorPos(NewCursorPos); {Nacteni
aktualni pozice kurzoru}
If Longint(NewCursorPos)<>Longint(OldCursorPos)
then boom; {je-li zmena, bouchni}
end;
end;
{ **** Inicializace
aplikace ****}
PROCEDURE TbombaApp.InitMainWindow;
Begin
MainWindow := New(PBomba, Init(nil));
End;
{ **** Hlavni program
****}
begin
Application.Init('');
showWindow(Application.MainWindow^.hwindow,sw_Hide); {schovej
se}
Application.Run;
Application.Done;
end.
Program nám trochu nabyl na objemu, že jo.
Ale není to tak hrozné.
A jaké z toho plynou výhody?
Tak předně - máme teď bombu jako plnohodnotnou Windows
aplikaci, reprezentovanou hlavním oknem. To je sice během
hlavní činnosti bomby Offscreen, ale můžeme ho využít -
vložit do něj ovládací prvky, popisky, všelijaké
frajeřinky, aby svět viděl, jací jsme pašáci. Ono by to
sice v předchozím případě šlo taky, ale bylo by to mnohem
složitější.
Program funguje v podstatě stejně, ale jsou tu drobné
odlišnosti. Za prvé - místo chumlu funkcí a procedur máme
pěkně zapouzdřené objektové typy, které jen stačí vložit
do aplikace. Nemusíme se zabývat nějakou filtrací zpráv (
což bychom jinak museli ), překladač za nás všechno udělá
sám. Nám stačí jen "naladit" určitou metodu
určitého objektu na určitou zprávu - v tomto případě jsme
metodu WMTimer naladili na zprávu WM_Timer, která, jak jistě
víte, je našemu objektu, respektive oknu, vysílána při
každém tiknutí našeho časovače.
Uvedené příklady jsou jen programové kostry, a v praxi budou
víceméně nepoužitelné. Od bomby zpravidla vyžadujeme
možnost načasovat si ji, jak chceme, a nastavit další
parametry. Ale to si jistě doděláte sami.
Pokud jste již něco ve Windows vytvořili, jistě si aplikaci
dotvoříte k obrazu svému. Například okno bomby můžete
vytvořit z typu TDlgWindow a poskládat si jeho vizáž ve
Workshopu. Můžete do něj vložit ovládací a nastavovací
prvky atd. V tom případě přemístíme "schování"
okna aplikace, které je v příkladu umístěno v hlavním
programovém bloku, do metody, která bude startovat bombu.
Výhody a nevýhody BPW bomb
V tomto případě výhody převažují. Bombičky jsou pěkně
skladné, úsporné, a při troše fantazie a znalosti BPW
můžete udělat prakticky cokoli. Funkci bomby, respektive její
explozi, změníte pouhým předefinováním procedury Boom (nebo
jak si ji nazvete).
Jedinou nevýhodou je poměrně složité programování
grafických efektů, které vyžaduje poměrně hluboké znalosti
prostředí BPW, a taky dost programátorské kázně. Hlavně
nesmíte zapomínat, že co v grafickém rozhraní vytvoříte,
musíte po použití zrušit - jinak bude mít bomba druhotný
efekt žrouta paměti a systémových prostředků.
Programovat v DELPHI je radost. Ale co se
týče bomb, jsou zde možnosti velmi omezené.Máme tu
samozřejmě k dispozici časovače, funkce pro práci s grafikou
a vůbec všechno, co taková bomba potřebuje, ale chybí tady
jedna maličkost - jednoduchá cestička ven mimo vlastní
aplikaci.
Tak například nezjistíte handle právě aktivního okna -
pokud ovšem není aktivní právě některé okno bomby.
Grafické výstupy jsou jednoduché, ale jen do vlastních
objektů aplikace. Chcete-li kreslit ven, jste na tom stejně
jako u BPW - i když nevím, moc hluboko jsem do toho nešel,
možná existuje způsob, jak je jednoduše přesměrovat.
Na druhou stranu zde velmi snadno vytvoříte dokonalé
napodobeniny všech možných errorboxů, tipových oken,
terminálů, dotazníků, daňových formulářů a všelijakých
jiných bláznivin, které při správném podání dokáží
někdy uživatele vystresovat daleko účiněji, než skutečná
exploze monitoru a přilehlých budov.
Jak takovou bombičku udělat? Prostě si vytvoříte dva
formuláře - v jednom bude časovací mechanizmus, druhý pak
bude sloužit jako výbušný prostor.
K funkci programu samotného nemá cenu se rozepisovat - vše
bude fungovat jako v předchozích případech. Vy jen
nadefinujete obsluhu událostí jednotlivých prvků (nastavení
zpoždění aj.), a obsluhu události OnTimer vloženého
časovače - bude prakticky stejná, jako metoda WMTimer v
příkladu Borland Pascalu, bude se lišit jen hlavičkou:
procedure TForm1.OnTimer(Sender: TObject);
Ostatní bude prakticky stejné jako v
předchozích příkladech.
Trochu podrobněji se o možnostech DELPHI v tomto směru
rozepíši později, až prozkoumám jeho další možnosti.
Výhody a nevýhody...
S výhodami a nevýhodami je to tady podobné jako u LiWin -
snadná realizace některých typů bomb, ale na druhé straně
trochu omezené možnosti, co se týká využití grafických
funkcí pro úpravu cizích oken - i když lze využít (nevím
zatím, v jaké míře a s jakým omezením ) funkce Borland
Pascalu.
Hlavní nevýhodou zůstává nemožnost zjistit aktivní okno
mimo vlastní aplikaci. Pokud víte, jak na to, dejte mi prosím
vědět.
Další nevýhodou je dost nafouknutý cílový kód, který i u
jednoduchých aplikací nebude menší než čtvrt megabajtu.
Objekty DELPHI mají totiž spoustu užitečných vlastností -
ale mají je, i když je třeba právě nepotřebujete.