Image
8.6.2016 0 Comments

Delphi / 3. časť: Ladenie aplikácií II

Späť na úvod >> Späť na seriál

V tejto časti budeme pokračovať vo výklade problematiky ladenia aplikácií, nech sa vám príjemne číta.

Výnimky a ladenie

O výnimkách sme už v Delfináriu veľakrát hovorili, bloky try...except a try...finally vám preto akiste nemusím predstavovať. Systém výnimiek bol vytvorený preto, aby sa uľahčil a sprehľadnil vývoj komplexnej aplikácie a aby bolo možné čo najjednoduchšie reagovať na rôzne chybové stavy, ktoré sa počas behu programu môžu vyskytnúť. Vďaka nim nemusíme používať systém návratových hodnôt, ktorý je bežný pri práci s Windows API funkciami. Pokiaľ API funkcii zadáte nesprávne hodnoty, vráti vám buď nulu, alebo false. Teoreticky by takýto prístup bolo možné použiť aj v Delphi, no vývoj programu by bol podstatne menej pohodlný. Po každučkom volaní akejkoľvek funkcie by sme totiž museli testovať jej návratovú hodnotu a ďalej postupovať v závislosti od nej. Ak máme k dispozícii výnimky, situácia je oveľa prehľadnejšia. Kód procedúry je potom rozdelený na dve časti: prvú časť, ktorá sa vykonáva za normálnych okolností, a druhú časť, ktorá sa vykonáva iba vo výnimočných situáciách, teda vtedy, keď vznikne výnimka. Okrem toho sa však výnimky dajú využiť aj iným spôsobom, čoho dôkazom budú nasledujúce riadky.

Predstavme si takúto situáciu: máme dva prepojené komponenty TDirectoryListBox a TDriveComboBox. Pracujú síce správne, ale je tu jeden problém: ak v komponente TDriveComboBox nastavíme jednotku A: a nie je v nej disketa, vznikne výnimka. To by príliš neprekážalo, je to koniec koncov logické a prirodzené, horšie však je, že sa automaticky objaví anglické chybové hlásenie „I/O Error 21“.  Keďže sú komponenty prepojené, neexistuje tu nijaký kód,  ktorý by sme mohli dať do bloku try...except. S podobným problémom ste sa mohli stretnúť napríklad pri práci s komponentom TDBGrid, ktorý neakceptoval určitý formát dátumu a „obšťastnil“ vás anglickým chybovým hlásením typu: „Invalid date format. Use Esc to abort changes.“ Našťastie riešenie tohto problému je pomerne jednoduché: využívať udalosť OnException objektu TApplication. Táto udalosť sa vyvolá pri vzniku akejkoľvek výnimky, preto napísaním obslužnej rutiny pre túto udalosť môžeme vytvoriť obslužnú rutinu pre akúkoľvek výnimku v programe. To sa nám bude hodiť napríklad pri databázových programoch. Predstavme si, že pracujeme s databázami a potrebujeme odchytiť výnimku „Key violation“. S použitím štandardného postupu by sme museli pri každej citlivej manipulácii s databázou použiť blok try...except. Inými slovami, čo operácia s databázou, to ďalší blok try...except, obsahujúci totožný kód, ktorý zobrazí napríklad slovenské chybové hlásenie alebo výnimku obslúži nejakým iným spôsobom. S použitím udalosti OnException sa tomu môžeme elegantne vyhnúť, ako uvidíme v nasledujúcom ukážkovom programe.

Na formulár pridáme komponent TDirectoryListBox, ktorý nazveme DirList, a komponent TDriveComboBox, ktorý pomenujeme DriveCombo. Potom ich štandardným spôsobom prepojíme (vlastnosť DirList komponentu TDriveComboBox nastavíme na DirList čiže komponent typu TDirectoryListBox). Potom napíšeme nasledujúci kód:

procedure TForm1.AppException(Sender: TObject; E: Exception);

begin

  if Pos('21',E.Message)>0 then

  begin

    ShowMessage('Neplatná jednotka!')

  end

   else begin

    Application.ShowException(E);

  end;

end;

Ako vidíme, rutina najprv testuje, či chybové hlásenie (teda vlastnosť Message objektu E) obsahuje číslo 21, a ak áno, zobrazí sa slovenské chybové hlásenie; v opačnom prípade sa pomocou metódy ShowException vykoná implicitná obsluha výnimky. Nech budete vytvárať akúkoľvek aplikáciu, vždy vychádzajte z uvedenej schémy. Ak totiž zabudnete zavolať metódu ShowException, o všetkých výnimkách vás bude informovať iba debugger, aj to iba v prípade, že máte zapnutú voľbu Break on Exception. Inými slovami, pokiaľ program spustíte mimo Delphi, o výnimke sa jednoducho nedozviete.

Uvedený kód však, bohužiaľ, nebude fungovať okamžite, na to je totiž potrebná malá úprava, ktorou je priradenie procedúry AppException udalosti OnException. Pamätajte, že uvedená univerzálna obsluha výnimiek bude fungovať až od toho okamihu, keď sa toto priradenie uskutoční. Priradenie som umiestnil do obslužnej rutiny udalosti OnShow hlavného formulára:

procedure TForm1.FormShow(Sender: TObject);

begin

  Application.OnException:=Form1.AppException;

end;

Udalosť OnException je možné použiť napríklad aj na zaznamenávanie všetkých výnimiek, ktoré v programe nastali. To je vhodné najmä vtedy, ak ste vydali beta verziu svojho programu, ktorá ešte nejaké „muchy“ môže obsahovať. Koncoví používatelia majú vo väčšine prípadov dosť veľké problémy pri zapamätávaní si chybových hlásení, pretože v prípade vzniku chyby v programe sústreďujú všetku energiu na vulgarizmy adresované autorovi aplikácie. Aby sme v takýchto situáciách neboli odkázaní na pamäť používateľov, napíšeme si kód, ktorý bude zapisovať do textového súboru chybové hlásenia takmer všetkých výnimiek, ktoré v programe nastali. Použitie slovka „takmer“ nie je náhodné, pretože nie všetky výnimky je potrebné zaznamenávať. Tie, ktoré sme už odchytili a spracovali (v našom prípade výnimka „I/O Error 21“), jednoducho nemá zmysel logovať, nás zaujímajú predovšetkým neočakávané výnimky. Okrem toho je potrebné poznamenať, že napríklad výnimku EAbort takýmto spôsobom ani nie je možné odchytiť, pretože pri výskyte tejto výnimky systém nevyvolá udalosť OnException.

Upravená rutina AppException bude pracovať tak, že najskôr text výnimky zobrazí, potom chybové hlásenie zapíše do súboru s názvom LOGFILE.TXT, ktorý sa vytvorí v tom istom adresári, v ktorom sa nachádza EXE súbor nášho programu. Kód upravenej rutiny AppException vyzerá takto:

procedure TForm1.AppException(Sender: TObject; E: Exception);

var f:TextFile;

FileName:ShortString;

i:integer;

begin

  if Pos('21',E.Message)>0 then

  begin

   ShowMessage('Neplatná jednotka!')

  end

   else begin

    Application.ShowException(E);

    {$IOCHECKS OFF}

    FileName:=ExtractFileDir(Application.ExeName)+'\logfile.txt';

    AssignFile(f,FileName);

    if not FileExists(FileName) then Rewrite(F);

    Append(F);

    i:=IOResult;

    WriteLn(f,E.Message);

    WriteLn(f,'*************************');

    CloseFile(f);

    {$IOCHECKS ON}

  end;

end;

Zrejme vás prekvapí použitie direktív {$IOCHECKS OFF} a {$IOCHECKS ON}. Pokiaľ ich nepoznáte, prezradím vám, že prvá z nich vypína konvertovanie runtime chýb na výnimky a druhá ho zapína. Pýtate sa, na čo je to dobré? Treba si uvedomiť, že kód sa nachádza v obsluhe výnimky a príkazy na prácu so súbormi môžu tiež spôsobiť výnimku. Viete, čo by sa stalo, keby sme uvedené direktívy nepoužili a náhodou by vznikla výnimka? Systém by sa snažil obslúžiť túto výnimku volaním obsluhy výnimky, ktorou je vlastne procedúra, v ktorej výnimka vznikla, čiže procedúra, v ktorej sa práve nachádzame. Táto procedúra sa vyvolá a niektorý z I/O príkazov vzápätí opäť spôsobí ďalšiu výnimku, v dôsledku čoho procedúra bude volať seba samu až donekonečna, presnejšie povedané, kým nepretečie zásobník. Pri pretečení zásobníka však tiež vznikne výnimka, takže ako vidíte, použitie direktív je celkom oprávnené. V záujme objektivity však musím dodať, že je síce oprávnené, ale nie nevyhnutné. Výnimka v kóde pre zapisovanie síce môže nastať, stáva sa to však iba zriedkavo. Ja osobne sa aj napriek tomu domnievam, že vypínať konvertovanie runtime chýb na výnimky v uvedenej situácii je potrebné. O Titanicu sa tiež tvrdilo, že sa nemôže potopiť, a predsa sa potopil...

Jedinou nevýhodou takéhoto postupu je, že musíte podobne ako v starom dobrom Turbo Pascale sledovať premennú IOResult, ktorá vracia chybový kód. To však nie je žiadny problém, no túto premennú musíte vo svojom kóde použiť aspoň raz, inak ju nebude možné v okne Watches sledovať (linker ju bude ignorovať).

Problematika použitia výnimiek počas fázy ladenia programu je teda objasnená. V nasledujúcej sekcii sa budeme venovať ladiacim nástrojom Delphi 5.

 

Ladenie v Delphi 5

Delphi 5 prinieslo okrem zlepšenej podpory ladenia aj nové možnosti úpravy pracovnej plochy, presnejšie povedané, možnosti dokovania okien. Hoci sa niektorým z vás môže zdať, že ide iba o kozmetické úpravy, v skutočnosti môžu tieto nové vymoženosti dramaticky zvýšiť produktivitu práce (to znie ako reklamný slogan, však?). Aby som bol konkrétnejší, tu je príklad: ak program práve píšete, celú obrazovku v podstate zaberá okno s kódom programu a Object Inspector, prípadne ešte niekoľko formulárov, ktoré práve navrhujete. Počas ladenia programu je situácia opačná: Object Inspector je takpovediac mimo hry a najviac vás zaujímajú ladiace informácie (teda napr. body prerušenia a hodnoty premenných, resp. vlastnosti objektov). Preto príde nesmierne vhod, ak si viete pracovnú plochu upraviť tak, aby bola počas písania programu usporiadaná inak ako počas jeho ladenia.

Aby sme nechodili okolo horúcej kaše, hneď si aj ukážeme, ako na to. Na osvieženie pamäte pripomínam, že v Delphi 5 sa pracovná plocha nazýva desktop. Z hľadiska použitia by sme desktopy mohli rozdeliť na editovacie a ladiace (debug desktop). Prvý typ desktopu slúži na bežnú prácu a druhý na ladenie. Hlavný rozdiel medzi nimi tkvie v tom, že „obyčajných“ desktopov môže byť niekoľko, zatiaľ čo ladiaci môže byť iba jeden. Ten sa po spustení programu automaticky aktivuje.

Aby sme iba neteoretizovali, ukážeme si, ako môže vyzerať vytváranie a ukladanie desktopov v praxi. Ešte predtým však budete musieť absolvovať malý tréning, ktorý si bude vyžadovať trochu trpezlivosti. Budete sa totiž musieť naučiť ukotvovať (dokovať) okná. Najjednoduchšie si to precvičíte tak, že si otvoríte ľubovoľné okno z kategórie Debug okien (teda napr. okno Watches) a budete ho pomaly ťahať nad oknom editora zdrojového kódu. V určitom okamihu sa tvar okna zmení: znamená to, že okno je pripravené na ukotvenie. Pustite ho a udivíte, čo sa bude diať. Zaujímavosťou je, že okno je možné ukotviť aj na Object Inspector.

Prejdime teraz k samotnej schéme, teda k spôsobu usporiadania pracovnej plochy. Najskôr si vytvoríme pracovnú plochu, ktorú budeme používať počas písania programu. Hneď na úvod upozorňujem, že takéto nastavenia sú subjektívne, preto vám môj návrh nemusí vyhovovať. Predovšetkým sa  sústredím na to, aby som objasnil, kedy a ktoré okno by malo byť otvorené a z akého dôvodu by malo byť otvorené. Začneme tým, že ukotvíme Code Explorer do Object Inspectora. To je možné urobiť viacerými spôsobmi, jeden z nich vidíte na obrázku č. 1. Code Explorer považujem za potrebný z toho dôvodu, že prostredníctvom neho sa môžeme rýchlo dostať k procedúram, metódam či deklaráciám. Veľkosť okna editora zdrojového kódu si upravte tak, aby vám vyhovovala, a potom vyberte voľbu Save Desktop z menu View|Desktops. Delphi vás vyzve, aby ste novú pracovnú plochu pomenovali.

Prvú pracovnú plochu máme teda hotovú, pristúpme teraz k vytvoreniu pracovnej plochy, ktorú budeme používať pri ladení. Tá sa bude skladať z okien Code Explorer, WatchesBreakpoints. Code Explorer som ponechal pre lepšiu orientáciu v zdrojovom kóde a význam okien WatchesBreakpoints nemusím vysvetľovať. Nastavenia uložíme pomocou známej voľby Save Desktop, pričom novú pracovnú plochu pomenujeme Debug. Tento desktop potom prostredníctvom voľby Set Debug Desktop z menu View|Desktops nastavíme ako debug desktop. Jeden z možných výsledkov vidíme na obrázku č. 2.

Pracovná plocha je teda nastavená, môžeme začať pracovať. O bodoch prerušenia sme si už čo-to povedali, to však platilo pre Delphi 3. V Delphi 5 sa vám bude s bodmi prerušenia pracovať oveľa komfortnejšie, najmä ak pracujete na väčších projektoch. Jedným zo zlepšení oproti starším verziám Delphi je možnosť združovať body prerušenia do skupín. Ak napríklad máte dlhú procedúru s veľkým množstvom breakpointov, môžete skupinu týchto bodov prerušenia deaktivovať a neskôr aktivovať bez toho, aby ste body prerušenia museli opätovne nastaviť ručne. Okrem toho je tu možnosť ignorovania výnimky, takže Delphi vás o vzniknutej výnimke vôbec nebude informovať (platí to však vždy iba pre vymedzený blok kódu). Teraz si možno poviete, že ignorovanie výnimiek je nezmysel, veď výnimka predsa znamená, že niečo nie je v poriadku, a my by sme mali vedieť o všetkých nezrovnalostiach v našom programe. Nuž, čiastočne je to pravda, neplatí to však vždy. Aby ste mi verili, napíšeme si krátky program, kde ignorovanie výnimky príde veľmi vhod.

Predstavme si, že ideme kopírovať súbor. Prv než sa súbor začne kopírovať, mali by sme si overiť, či je cieľová jednotka platná. Na tento účel sa celkom dobre hodí procedúra Chdir – ak jej ako parameter odovzdáte koreňový adresár neplatného disku, vznikne výnimka. Program najskôr overí, či je jednotka dostupná, a v prípade, že je, vypíše hlásenie o ukončení operácie. Samozrejme, súbor v skutočnosti nebudeme kopírovať, aby sme si zbytočne nekomplikovali život. Problém demonštruje nasledujúci ukážkový kód:

procedure TForm1.Button1Click(Sender: TObject);

var ok:boolean;

begin

 try

  Chdir('a:\');

  Chdir('c:\');

  ShowMessage('Kopírovanie dokončené');

 except

  ShowMessage('Jednotka je neplatná');

 end;

end;

Ak v jednotke A: nebude disketa, Delphi program zastaví a my budeme musieť „odklepnúť“ anglické chybové hlásenie, potom stlačiť F9 a opäť „odklepnúť“ chybové hlásenie, tentoraz slovenské. Našťastie v Delphi 5 sa dá tento problém veľmi elegantne vyriešiť. Výnimku, ktorú spôsobil príkaz Chdir, jednoducho zablokujeme, budeme ju ignorovať, takže IDE program nezastaví a my budeme musieť „odklepnúť“ iba jedno chybové hlásenie. Ako na to? Veľmi jednoducho: nastavíme bod prerušenia. Ten môže okrem iného slúžiť aj na to, aby udával miesto, počnúc ktorým sa majú výnimky ignorovať. V našom prípade je najvhodnejším kandidátom príkaz try, pretože sa nachádza pred problematickou procedúrou Chdir.  Od tejto chvíle sa budú v celom bloku začínajúcom sa príkazom try výnimky ignorovať. Program spustíme a preskúšame. Tentoraz debugger vykonávanie kódu nezastaví a my uvidíme iba slovenské chybové hlásenie.

Mimochodom, viete prečo je v procedúre aj druhý príkaz Chdir? Táto procedúra je totiž nanajvýš prešibaná, a pokiaľ pri stlačení tlačidla ponecháte disketu v mechanike, pri nasledujúcom volaní sa procedúra bude tváriť, že v mechanike disketa je, a to aj vtedy, keď tam nie je. Inými slovami, ak stlačíte tlačidlo a disketa bude v mechanike, zobrazí sa správa o ukončení operácie; ak však disketu vyberiete a tlačidlo opäť stlačíte, procedúra Chdir sa nebude na jednotku A: „dobýjať“ ešte raz, pretože si zapamätá, že raz to už robila, pokus bol úspešný, a teda nie je dôvod skúšať znova. Toto správanie je možné korigovať druhým volaním procedúry Chdir, pričom jej ako parameter odovzdáme koreňový adresár disku C: alebo akéhokoľvek iného disku.

Vráťme sa však k pôvodnej téme, ktorou je blokovanie výnimiek. Je potrebné podotknúť, že takýto postup má aj svoje nevýhody. Upravme si teraz kód podľa nasledujúceho výpisu:

procedure TForm1.Button1Click(Sender: TObject);

var ok:boolean;

a,b:integer;

begin

 try

  a:=50;

  b:=0;

  Chdir('a:\');

  Chdir('c:\');

  ShowMessage('Kopírovanie dokončené');

 except

  ShowMessage('Jednotka je neplatná');

 end;

 a:=a div b;

end;

Ako vidíme, na jeho konci spôsobíme delenie nulou. Problém je v tom, že chybové hlásenie sa síce ukáže, ale debugger vykonávanie programu nepreruší, a teda pri zložitejších programoch by bolo ťažšie identifikovať riadok, ktorý vznik výnimky spôsobil. Našťastie riešenie je veľmi jednoduché: veľkosť bloku, v ktorom sa výnimky ignorujú, je možné ohraničiť bodmi prerušenia. Prvý breakpoint, ktorý ignorovanie výnimiek aktivuje, už máme nastavený. Nastaviť však musíme aj druhý bod prerušenia, ktorý ignorovanie výnimiek vypne. Tento breakpoint nastavíme na riadok

a:=a div b;

Parametre bodu prerušenia potom nastavíme podľa obrázka č. 4. Teraz funguje všetko presne tak, ako sme si to predstavovali: debugger nás neobťažuje v prípade, ak výnimku spôsobila procedúra Chdir; ak však nastala iná, neočakávaná výnimka, všetko prebehne tak, aby sme sa o nej včas dozvedeli (debugger program zastaví a ukáže nám riadok, ktorý výnimku spôsobil). Znalci Delphi ma teraz istotne obvinia, že som používal zbytočne komplikovaný postup, pretože testovanie platnosti jednotky by sa dalo vykonať aj tak, že by sme vypli konvertovanie I/O chýb na výnimky prepínačom {$IOCHECKS OFF} a po zavolaní procedúry Chdir by sme testovali premennú IOResult. Áno, aj toto je jedno z riešení. Ja som však použil tento trochu nezmyselný postup preto, aby som demonštroval špeciálne vlastnosti bodov prerušenia.

Ďalšou zaujímavou vlastnosťou Delphi 5 je možnosť združovania breakpointov do skupín. Predstavme si nasledujúcu situáciu: ladíme procedúru, ktorá volá určitú funkciu. Ani procedúra, ani funkcia nie sú celkom bez chýb, a preto ešte musia obsahovať body prerušenia. V Delphi 3 by sme nemali na výber, keby sme sa nechceli zdržiavať krokovaním funkcie, museli by sme body prerušenia vymazať či prácne po jednom deaktivovať. To môže byť obzvlášť nepríjemné najmä vtedy, ak je bod prerušenia niečím podmienený (teda ak ide o conditional breakpoint). Ak by sa neskôr ukázalo, že body prerušenia vo funkcii sú ešte stále potrebné, museli by sme obnoviť do pôvodného stavu nielen samotné breakpointy, ale aj podmienkové výrazy, ktoré ich aktivujú. Našťastie v Delphi 5 sa dá tento problém elegantne vyriešiť. Napíšme si dve rutiny:

procedure Dummy;

var i,x:integer;

begin

x:=0;

for i :=1  to 20 do

begin

  Inc(x);

  x:=x*2;

end;

end;

 

procedure TForm1.Button2Click(Sender: TObject);

var i,w:integer;

begin

w:=0;

for i :=1  to 200 do

begin

  Dummy;

  Inc(w);

end;

Tento kód nemá absolútne nijaký zmysel, na demonštráciu problému je však dostačujúci. Prvý bod prerušenia zaradíme na ľubovoľné miesto v druhej procedúre. Skupinu, do ktorej bude tento bod prerušenia patriť, nazveme Prvá. Pokiaľ chcete, môžete do druhej procedúry umiestniť viacero breakpointov, nezabudnite ich však zaradiť do skupiny Prvá. Analogicky postupujeme pri vytváraní bodov prerušenia v procedúre Dummy, ale skupinu nazveme Druhá. Keď máme skupiny nadefinované, presunieme sa do okienka s bodmi prerušenia a stlačíme pravé tlačidlo myši. Objaví sa menu podobné tomu na obr. 6. Mimochodom, toto menu sa správa trošku neposlušne. Aby sa vám zobrazilo, musíte kliknúť do dolnej polovice okienka, teda mimo popisných textov bodov prerušenia. Ako vidíme, niekoľkými pohybmi myšou máme možnosť aktivovať a deaktivovať viacero bodov prerušenia, združených do skupiny.

Počas ladenia aplikácie môže nastať situácia, keď procedúru síce nepotrebujeme krokovať, radi by sme však vedeli, či vôbec bola zavolaná, prípadne či vykonávanie procedúry dospelo k určitému bodu. Nie je síce žiadny problém upraviť procedúru tak, aby pri svojom ukončení ukázala správu, existuje však aj pohodlnejšie riešenie, opäť postavené na bode prerušenia. Ten je možné nadefinovať tak, aby miesto prerušenia programu zapísal správu do Event Logu. Takýto bod prerušenia sa dá veľmi jednoducho nadefinovať. Ako pomôcka nám poslúži obr. 7. Ako vidíme, tento bod prerušenia bude nastavený na konci procedúry Dummy. Na obr. 8 vidíme Event Log v akcii.

Delphi 5 obsahuje ešte jedno zlepšenie: komponent TApplicationEvents. Keď ho bližšie preskúmame, zistíme, že umožňuje vytvoriť obslužné rutiny na rôzne udalosti objektu TApplication. Môžeme pomocou neho napríklad o trošku jednoduchšie napísať univerzálnu rutinu na obsluhu výnimiek, o ktorej sme hovorili na začiatku článku. Aby sme však hrali s odkrytými kartami, musím prezradiť, že tento komponent nie je žiadna novinka, knižnica RX Library ho obsahovala už dávno. Ukážkový kód na univerzálnu obsluhu výnimiek už písať nebudem, aby som sa neopakoval.

Základy ladenia máme teda za sebou. Je pritom potrebné zdôrazniť slovo „základy“, pretože problematika ladenia je veľmi komplexná. Bolo by veľmi ťažké opísať postup ladenia, ktorý by vyhovoval všetkým, lebo rôzne typy aplikácií vyžadujú rôzne ladiace postupy. Preto si treba uvedomiť, že skutočná sila ladiacich nástrojov sa prejaví až vtedy, ak sú ich schopnosti vhodne skombinované. Nebojte sa preto experimentovať, čas strávený nad pokusmi sa vráti v podobe rýchlejšie odladenej aplikácie.

Nabudúce

Neoddeliteľnou súčasťou programov sú okrem kódu aj ikony. Iste sa vám stalo, že ste v nejakom programe našli zaujímavú ikonu, ktorú by ste radi použili vo svojej aplikácii. Aby bolo možné takúto ikonu takpovediac „dostať z programu von“, je potrebný špeciálny program, ktorý ju dokáže vyextrahovať. A práve taký program si napíšeme o mesiac, dovtedy sa majte pekne.


Nechajte si posielať prehľad najdôležitejších správ emailom

Mohlo by Vás zaujímať

Ako na to

Ako funguje sandbox?

08.12.2016 15:36

Každá aplikácia môže pre operačný systém počítača či mobilného zariadenia predstavovať potenciálnu hrozbu, a to aj v prípade, ak neobsahuje žiadne bloky škodlivého kódu. Murphyho zákony neúprosne defi ...

Ako na to

Tipy a triky: Ako na snímku obrazovky na akomkoľvek počítači s Windows?

02.12.2016 00:13

Ak snímky obrazovky robíte často apotrebujete napríklad funkcie na posun stránok alebo snímanie zobrazenia pri vyššom rozlíšení displeja, zrejme používate nejakú špecializovanú aplikáciu. Väčšina použ ...

Ako na to 1

Tipy a triky: Ako aplikácii prednastaviť spúšťanie s administrátorskými právami?

30.11.2016 00:10

Väčšina aspoň trochu skúsenejších používateľov vie, že aj keď máte na operačnom systéme Windows vytvorený administrátorský účet, aplikácie pre bezpečnosť nefungujú vždy splnými administrátorskými práv ...

Žiadne komentáre

Vyhľadávanie

Kyocera - prve-zariadenia-formatu-a4-s-vykonom-a3

Najnovšie videá