Velká skupina programů je schopna pracovat na pozadí prováděné úlohy. Patří mezi ně ovladače (myši, klávesnice, . . .), utility (hodiny, antivirová kontrola, stahovače obrazovek, . . .), viry (bez komentáře). Těmto programům přidáváme označení rezidentní.
Jejich základní vlastností je jejich neustálá přítomnost v paměti počítače a schopnost se vyvolat, jestliže je to nutné. Z toho vyplývají i požadavky na ně: malá délka kódu (musí obsadit co nejméně paměti) a nezávislost na spuštěných aplikacích.
Činnost těchto programů na pozadí aplikací zaručuje jejich volání spolu s obsluhami přerušení. Jestliže tedy dojde k nějaké události (stisk klávesy, přijetí dat na port, uplynutí určité doby, . . .), je voláno přerušení obsluhující tuto událost. Po této obsluze (,nebo před ní) proběhne i část rezidentního programu připojeného k ní. Aby k tomu došlo, musí tvůrce rezidentního programu změnit adresu v tabulce vektorů přerušení na adresu svého podprogramu. Přitom si starou adresu obsluhy uschová, aby mohl zajistit volání původní obsluhy události. Je jen na tvůrci, jestli starou obsluhu bude volat nebo ne (jestliže ji ale nezavolá, mohou se vyskytnout problémy). Programátor se také může rozhodnout, ve které části svého programu bude obsluhu volat (např. nemohu číst jaká klávesa byla stisknuta, když ještě neproběhla obsluha klávesnice). Rezidentní program má tyto části:
GetIntVec
(číslo přerušení, adresa proměnné typu
procedure)
SetIntVec
(číslo přerušení, adresa našeho
podprogramu)
Writeln ('Rezidentní
program instalován.');
) Keep (0)
V Pascalu musíme navíc v rezidentním programu ohraničit podprogramy interrupt direktivou {$F+}, která zajistí, že bude uvnitř použito vzdálené volání (za podprogram napíšeme {$F-} pro návrat do automatického zjišťování vzdálených adres). Navíc musíme zajistit správnou alokaci paměti pro rezidentní program označením v úvodu programu {$M 400,0,0}, které vymezí oblast rezervovanou pro zásobník atd. (hodnoty je nejlepší vyzkoušet).
Nejčastěji se pro rezidentní programy používají přerušení:
Ostatní hodnoty přerušení se dají zjistit z literatury (nebo SYSMANu).
Na jaké přerušení rezident připojíme, závisí do značné míry na tom, co má dělat a na co má reagovat. Občas je dobré si v obsluze jednoho přerušení nastavit proměnné a v závislosti na jejich stavu vykonat (nebo nevykonat) určitou činnost v obsluze jiného přerušení. Často si ani neuvědomíme, že náš podprogram připojený k určitému přerušení, ho nepřímo volá. Dojde tak k zacyklení. Toho se částečně vyvarujeme tím, že veškeré činnosti, spojené se vstupy a výstupy, provádíme sami a nevoláme pascalovské procedury (např. výstup na obrazovku realizujeme přímým zápisem do VRAM, použití writeln vede k chybě).
Příklad:
{$M $400,0,0} {nastav paměť:
zásobník $400 slabik}
uses Dos;
var IntVec : Procedure; {proměnná pro adresu staré obsluhy}
{$F+} {vzdálená
volání}
procedure hodiny;interrupt;assembler; {nová obsluha
přerušení}
asm
JMP
@zac
{přeskoč data}
@vid:
DW
156,$B800
{adresa místa VRAM, kde budou hodiny}
@zac:
MOV
CL,2
{hodiny, minuty, vteřiny (cyklus)}
@c1 : {začátek cyklu}
LES
BX,CS:[
OFFSET
@vid]{naber adresu proměnné slovo do BX}
XOR
AH,AH
{vymaž horní polovinu registru AX}
MOV
AL,CL
{naber do dolní poloviny AX krok i}
SHL
AL,1
{vynásob, AL:=AL*2}
SUB
BX,AX
{odečti od BX obsah AX}
OUT
$70,AL
{pošli na CMOS adresu čtené slabiky}
SHL
AL,1
{vynásob, AL:=AL*2}
SUB
BX,AX
{odečti, to ovlivní tvaru výstupu}
IN
AL,$71
{přečti z CMOS obsah čtené slabiky}
MOV
DL,AL
{zkopíruj obsah této slabiky do AH}
SHR
DL,4
{desítky posuň do dolní poloviny
AH}
AND
AX,$F
{odstraň zbytečné bity}
AND
DX,$F
OR
AX,$1F30
{proveď převod do ASCII, přidej atr.}
OR
DX,$1F30
MOV
ES:2[BX],AX {nastav jednotky ve VRAM}
MOV
ES:[BX],DX
{nastav desítky ve VRAM}
DEC
CL
{snížit CL}
JNS
@c1
{konec cyklu}
MOV
WORD
PTR
ES:[154],$1F00+'.'{ve VRAM odděl vteřiny a minuty}
MOV
WORD
PTR
ES:[148],$1F00+'.'{ve VRAM odděl minuty a hodiny}
PUSHF
{do zásobníku registr
příznaků}
CALL
IntVec
{volej starou obsluhu $1C}
end;
{$F-} {konec vzdálených
volání}
begin {hlavní
program}
GetIntVec($1c,@IntVec); {čti adresu staré obsluhy}
SetIntVec($1c,Addr(hodiny));{na její místo dej adresu mojí
obsluhy}
Writeln('Rezidentní hodiny instalovány.');{informuj o
instalaci}
Keep (0); {ukonči s tím,
že zůstane program v paměti}
end.
Uvedený program čte při obsluze přerušení $1C stav hodin z paměti CMOS. Po přepočtu adres a úpravě znaků z BCD kódu do ASCII je informace o čase zobrazena v pravém horním rohu obrazovky. Hlavní program má za úkol jen změnu adresy původní obsluhy na naší.
© 1996-1997 Mgr. Tomáš Papoušek
Tento text je možné používat pro studijní účely bez omezení. V případě komerčního využití kontaktujte autora.