Der Speicheraufbau unter DOS & TSR-Programmierung



Der Speicheraufbau
unter DOS
&
TSR - Programmierung
1. Der Speicheraufbau unter DOS

Der PC kam zunĂ€chst mit einer Speicherausstattung von 16 KByte auf den Markt, die man auf der Hauptplatine bis zu 64 KByte ausbauen konnte. Außerdem vertrieb IBM - Speichererweiterungskarten, die jeweils 64 KByte faßten und in einem der fĂŒnf ErweiterungssteckplĂ€tze plaziert wurden. Maximal drei dieser Karten konnten installiert werden, um den PC auf die damals gigantische Speichermenge von 256 KByte aufzurĂŒsten.

Die Entwickler der PCs wußten jedoch, dass das nicht das Ende der Entwicklung sein wĂŒrde und legten deshalb ein Speicher - Layout fest, dass den Ausbau des RAM - Speichers bis zu einer Marke von 640 KByte erlaubte. Sie glaubten dabei zukunftsweisend zu sein, wurden von der Zukunft aber nur allzu schnell ĂŒberholt, wie jeder DOS - Anwender heute weiß.

Neben dem RAM planten sie in dem 1 MByte umfassenden Adreßraum der 8088 - CPU Raum fĂŒr den RAM - Bereich der Video - Karten (den sog. Video - RAM), fĂŒr das ROM - BIOS und einige ROM - Erweiterungen ein. Ob sich hinter einer Speicherstelle RAM oder ROM befindet, ist fĂŒr den Prozessor gleichgĂŒltig, mit dem einzigen Unterschied, dass sich Speicherbereiche im ROM nun einmal nicht beschreiben lassen. Der Prozessor lehnt auch nicht ab, Speicherstellen anzusprechen, die physikalisch gar nicht vorhanden sind. Denn die Tatsache, dass der Prozessor bis zu 1 MByte Speicher verwalten kann, bedeutet noch lange nicht, dass sich hinter jeder Speicheradresse auch wirklich ein RAM - oder ROM - Baustein verbirgt.

Wie die folgende Tabelle (Abbildung 1) zeigt, erfolgte die Planung des Speicherlayouts auf Basis von 64 - KByte - Segmente, denn der 8088 und seine Nachfolger verwalten den Speicher in Blöcken dieser GrĂ¶ĂŸe. 16 dieser Blöcke faßt der Adreßraum von 1 MByte.

Die ersten zehn Speichersegmente sind fĂŒr das Hauptsspeicher - RAM reserviert, wodurch es in seiner GrĂ¶ĂŸe auf maximal 640 KByte beschrĂ€nkt ist. Dem Speichersegment 0 kommt dabei eine besondere Rolle zu, da es wichtige Daten und Routinen des Betriebssystems aufnimmt.

Block
Adresse
Inhalt
15
F000:0000 - F000:FFFF
BIOS - ROM
14
E000:0000 - E000:FFFF
frei fĂŒr ROM - Cartridges
13
D000:0000 - D000:FFFF
frei fĂŒr ROM - Cartridges
12
C000:0000 - C000:FFFF
zusÀtzliches BIOS - ROM
11
B000:0000 - B000:FFFF
Video - RAM
10
A000:0000 - A000:FFFF
zusÀtzliches Video - RAM (EGA/VGA)
9
9000:0000 - 9000:FFFF
RAM von 576 KB bis 640 KB
8
8000:0000 - 8000:FFFF
RAM von 512 KB bis 576 KB
7
7000:0000 - 7000:FFFF
RAM von 448 KB bis 512 KB
6
6000:0000 - 6000:FFFF
RAM von 384 KB bis 448 KB
5
5000:0000 - 5000:FFFF
RAM von 320 KB bis 384 KB
4
4000:0000 - 4000:FFFF
RAM von 256 KB bis 320 KB
3
3000:0000 - 3000:FFFF
RAM von 192 KB bis 256 KB
2
2000:0000 - 2000:FFFF
RAM von 128 KB bis 192 KB
1
1000:0000 - 1000:FFFF
RAM von 64 KB bis 128 KB
0
0000:0000 - 0000:FFFF
RAM von 0 KB bis 64 KB

Abbildung 1: Die Aufteilung des PC - RAM - Speichers

Auf den RAM - Speicher folgt das Speichersegment A, das mit einer EGA - und VGA - Grafik - Karte installiert wird. Es dient als Speicher fĂŒr den Bildschirmaufbau in den verschiedenen Grafikmodi dieser Karten.

Das Speichersegment B ist den monochromen Videokarten MDA und Herclues sowie der Farbgrafikkarte CGA zugeordnet. Beide teilen sich dieses Segment als Speicher fĂŒr den Bildschirmaufbau, wobei die monochrome Karte die unteren 32 KByte und die Color - Karte die oberen 32 KByte dieses Segments in Anspruch nimmt.

Die Speichersegmente hinter dem Video - RAM werden nicht mehr mit RAM, sondern mit ROM belegt, wobei das C - Segment den Anfang macht. In diesem Segment sind bei einigen Rechnern BIOS - Routinen untergebracht, die nicht Teil des ursprĂŒnglichen BIOS - Kerns sind. Beim XT sind dies zum Beispiel die Routinen zur UnterstĂŒtzung der mit ihm eingefĂŒhrten Festplatte.

Die Segmente D und E waren ursprĂŒnglich fĂŒr ROM - Cartridges vorgesehen, wie man sie bei Homecomputer - und Telespielen zur Einbringung von Software in das System nutzt. Davon wurde allerdings nie richtig Gebrauch gemacht, so dass dieser Bereich fast immer ungenutzt blieb und heutzutage als zusĂ€tzlicher RAM oder fĂŒr die Einblendung von EMS - Speicher verwendet wird.

Das Segment F enthĂ€lt schließlich die eigentlichen BIOS - Routinen, den Ur - Lader des Systems, sowie das nur noch bei alten Rechnern vorhandene ROM - BASIC.

Die Hardware des PCs ist nicht an ein bestimmtes Speicherlayout gebunden, schon gar nicht an das von IBM, und trotzdem setzte IBM bereits mit dem ersten PC den Maßstab, der bis heute von allen Anbietern eingehalten wird. DAS ist jedoch hauptsĂ€chlich eine Frage der Software, denn es sind das BIOS und das DOS, die sich auf die Lage bestimmter Speicherbereiche (z.B. des Video - RAMs) eingestellt haben. Zementiert wurde dieses Layout zusĂ€tzlich durch jedes Programm, das auf den Aufbau des Speichers aus und arbeiten nicht einwandfrei, wenn diese sich als falsch erweisen.


2. TSR - Programmierung

Seit seiner Entwicklung haftet DOS der Makel an, nicht Multitasking - fĂ€hig zu sein, also jeweils nur ein Programm ausfĂŒhren zu können. Erst jetzt, nach mehr als zehn Jahren DOS - Geschichte, stehen mit Windows und OS/2 zwei Betriebssysteme zur VerfĂŒgung, die diese LĂŒcke fĂŒllen. Einen Hauch von Multitasking haben jedoch seit jeher die sogenannten TSR - Programme (TSR = Terminate and Stay Resident) in die DOS - Welt gebracht. Diese Speicherresidenten Programme schlummern, einmal gestartet, im Hintergrund und warten auf ihre Aktivierung.

Zwar findet auch bei dieser Art von Programmen kein echtes Multitasking statt, werden also nicht mehrere Programme gleichzeitig ausgefĂŒhrt, doch kann der Anwender das im Hintergrund wartende TSR - Programm jederzeit durch die BetĂ€tigung einer bestimmten Tastenkombination, dem sog. "Hotkey", aktivieren. Das TSR - Programm unterbricht dann die AusfĂŒhrung des gerade aktiven Programms, merkt sich den Bildschirminhalt und bietet dem Anwender seine Dienste an. Beendet dieser das TSR - Programm anschließend wieder, restauriert es den Bildschirm des unterbrochenen Programms und setzt desen AusfĂŒhrung fort.

Mit Hilfe von TSR - Programmen kann sich der Anwender per Knopfdruck jederzeit Zugang zu so nĂŒtzlichen Hilfsmitteln wie Taschenrechner, Kalender oder Notizbuch verschaffen. Manche TSR - Programme sind sogar in der Lage, mit den von ihnen unterbrochenen Programm zu interagieren und Daten zu transferieren. Obwohl die unterschiedlichsten Anwendungen als TSR - Programme implementiert werden können, liegt allen TSR - Anwendungen eine einheitliche Funktionsweise und ein einheitlicher Aufbau zu Grunde.

TSR - Programme sind bereits von ihrer Definition her Programme, die die Konzeption von DOS als Singletask - System stÀndig unterlaufen. Denn "Singletask" bedeutet, dass immer nur ein Programm allein auf die Systemressourcen (RAM - Speicher, Bildschirm, Festplatte usw.) zugreift, was eben nicht der Fall ist, wenn neben dem eigentlichen Vordergrund - Programm noch ein TSR - Programm im Hintergrund seine Aufgaben wahrnimmt. Ein TSR - Programm muss es deshalb innerhalb des Systems mit zahlreichen Gegnern aufnehmen, zu denen das BIOS, das DOS, das unterbrochene Programm, aber auch andere TSR - Programme zÀhlen.

Dies zu bewĂ€ltigen, ist keine ganz einfache, dafĂŒr aber eine faszinierende Herausforderung, die jedoch nur in der Assemblersprache realisiert werden kann. Allerdings haftet dieser Sprache der Makel an, fĂŒr die Programmierung von typischen TSR - Anwendungen wie Taschenrechner oder NotizbĂŒchern, die man einfacher und schneller in Hochsprachen wie Pascal und C programmieren kann, nur wenig geeignet zu sein. Aus diesem Grund erstellen wir ein Assemblerprogramm, mit desen Hilfe ein ganz normales Pascal - Programm ohne großen Aufwand in ein TSR - Programm verwandelt werden kann.


Die Aktivierung von TSR - Programmen

Wenn wir an ein TSR - Programm die Forderung stellen, unmittelbar nach BetĂ€tigung seines ganz persönlichen Hotkeys in den Vordergrund zu rĂŒcken, mĂŒssen wir natĂŒrlich eine Art Auslösemechanismus installieren, der mit der Tastatur verbunden ist. Hier bieten sich die Interrupts 09h und 16h an, die beide im Zusammenhang mit der Tastatur aufgerufen werden. Interrupt 16h ist der bekannte BIOS - Tastatur - Interrupt, der Programmen zur Abfrage der Zeichen und des Tastaturstatus dient. Sich in diesen Interrupt einzuklinken und ihn im Hinblick auf die Aktivierung des TSR "umzubauen", fĂŒhrt jedoch nicht zu dem gewĂŒnschten Erfolg. Denn dadurch kann das TSR - Programm nur aktiviert werden, wenn dieser Interrupt durch ein Programm zur Tastaturabfrage aufgerufen wird. Schließlich erhĂ€lt das TSR - Programm erst dann die Möglichkeit, den Inhalt des Tastaturpuffers zu betrachten und sich in den Vordergrund zu rĂŒcken, wenn es darin seinen Hotkey entdeckt.

Besser eignet sich deshalb der Interrupt 09h, der von der Tastatur mit jeder BetĂ€tigung einer Taste ausgelöst wird. Es gilt also diesen Interrupt auf eine eigene Routine umzuleiten, die dann bei jedem Tastenanschlag ĂŒberprĂŒfen kann, ob das TSR - Programm aktiviert werden soll oder nicht. Bevor dies geschieht, sollte die Routine jedoch den Interrupt - Handler aufrufen, der vor der Installation des TSR - Programms fĂŒr den Interrupt 09h zustĂ€ndig war. DafĂŒr gibt es zwei wichtige GrĂŒnde. Der erste hĂ€ngt mit der Aufgabe diese Interrupts zusammen. Er soll dem System anzeigen, dass die Tastatur die Aufmerksamkeit des Systems benötigt, um Informationen ĂŒber die BetĂ€tigung oder das Loslassen einer Taste an das System zu ĂŒbertragen. Konkret heißt das, wenn nicht zunĂ€chst die ursprĂŒngliche Routine aufgerufen wird, wĂ€ren keine Eingaben von der Tastatur mehr möglich.

Der zweite Grund hÀngt mit der Möglichkeit zusammen, dass vor einem TSR - Programm bereits andere TSR - Programme installiert wurden, die den Interrupt 09h auf eine eigene Routine umgeleitet haben. Da sich das zuletzt gestartete TSR - Programm in der Kette der Interrupt - Handler vor diesen Programmen befindet, werden ihrer Interrupt - Routinen nicht mehr aufgerufen, wenn man auf einen Aufruf des alten Interrupt - Handlers verzichtet. Die Folge: Diese TSR - Programme können nicht mehr aktiviert werden.















































Abbildung 2: Kette der TSR - Programme am Beispiel des Interrupts 09h


Aus diesem Grund gilt fĂŒr TSR - Programme, dass beim Aufruf von umgeleiteten Interrupt - Routinen vor oder nach der eigenen Interrupt - Abarbeitung der alte Interrupt - Handler aufgerufen werden sollte. Dieser Aufruf darf dabei jedoch nicht ĂŒber den Maschinensprachebefehl INT erfolgen, da dadurch womöglich doch wieder nur der letzte Interrupt - Handler aufgerufen wĂŒrde, der zusammen mit einem TSR - Programm installiert wurde. Dies hĂ€tte in den meisten FĂ€llen eine unendliche Rekursion und damit verbunden einen StackĂŒberlauf zur Folge, was fast zwangslĂ€ufig zu einem Absturz des Systems fĂŒhrt. Um dem entgegenzuwirken, muss die Adresse des alten Interrupt - Handlers bei der Installation des TSR - Programms in Erfahrung gebracht und in einer Variablen gespeichert werden. Über diese Adresse kann der alte Interrupt - Handler dann mit Hilfe eines FAR - CALL - Befehls aufgerufen werden. Um jedoch den Aufruf dieses Handlers ĂŒber den INT - Befehl zu simulieren, muss zuvor der Inhalt des Flag - Registers mittels PUSHF auf den Stack gebracht werden, wie es automatisch beim INT - Befehl geschieht.

Bevor der alte Interrupt - Handler innerhalb des neuen Interrupt - Handlers aufgerufen wird, wird zunĂ€chst einmal der Inhalt des Ports 60h ausgelesen. Das ist der Port, an den die Tastatur jeweils den Scan - Code der betĂ€tigten Taste anlegt. Auch der spĂ€ter aufgerufene alte Interrupt - Handler wird diesen Port auslesen, was das Programm allerdings nicht beeintrĂ€chtigt, weil der Port immer den gleichen Wert zurĂŒckliefert, bis eine neue Taste betĂ€tigt wurde. Mit dem Inhalt des Tastatur - Ports 60h kann der neue Interrupt - Handler des TSR - Programms feststellen, ob der Anwender einen Teil des Hotkeys betĂ€tigt hat, denn ein Hotkey setzt sich in der Regel aus einer Buchstaben - oder Ziffern - Taste in Verbindung mit einer oder mehreren Umschalttasten ([Shift], [Ctrl], [Alt] etc.) zusammen. Trifft der Interrupt - Handler auf den Code der Buchstaben - oder Zifferntasten, muss noch sichergestellt werden, dass der Anwender auch gleichzeitig die Umschalttasten niedergedrĂŒckt hĂ€lt, die zum Hotkey gehören. Deshalb wird der Inhalt des BIOS - Tastatur - Flags inspiziert, das an der Adresse 17h innerhalb des BIOS - Variablensegments (Segmentadresse 0040h) zu finden ist. Die verschiedenen Umschalttasten werden dabei durch jeweils ein Bit reprĂ€sentiert. Trifft man dort auf die gewĂŒnschte Bit - Maske, versucht der Anwender gerade, das TSR - Programm zu aktivieren. Das TSR - Programm darf sich in diesem Fall aber nicht unter allen UmstĂ€nden aktivieren, denn dem stehen verschiedene Probleme gegenĂŒber, die unter dem Stichwort "DOS - Reentranz" zusammengefaßt werden.


DOS ist nicht reentrant

Da das TSR - Programm ĂŒber die Tastatur jederzeit aktiviert werden kann, ist es möglich, dass es die AusfĂŒhrung einer gerade aufgerufenen DOS - Funktion unterbricht. Dies muss noch nicht zwangslĂ€ufig zu Problemen fĂŒhren, solange das TSR - Programm nach seiner Beendigung ordnungsgemĂ€ĂŸ in die unterbrochene DOS - Funktion zurĂŒckkehrt. Ein Problem entsteht jedoch dann, wenn das TSR - Programm seinerseits DOS - Funktionen aufruft, was praktisch nicht zu vermeiden ist. Hier tritt das Problem der Reentranz auf.

Dieser Begriff steht fĂŒr die FĂ€higkeit eines Systems, seinen Programmcode von mehreren Programmen gleichzeitig aufrufen und ausfĂŒhren zu lassen. Gerade diese Reentranz ist bei DOS nicht gegeben, da es als Singletask - System davon ausgeht, dass die einzelnen DOS - Funktionen nicht gleichzeitig (parallel), sondern eine nach der anderen (seriell) aufgerufen wird.

Um dem Reentranz - Problem aus dem Weg zu gehen, bleibt einem TSR - Programm nur die Möglichkeit, die Aktivierung erst dann zu erlauben, wenn gerade keine DOS - Funktion ausgefĂŒhrt wird. Dabei kommt DOS den Entwicklern solcher Programme entgegen, indem es das sogenannte INDOS - Flag bereitstellt. Es handelt sich dabei um einen ZĂ€hler, der die Verschachtelungstiefe von DOS - Aufrufen zĂ€hlt. EnthĂ€lt er den Wert 0, wird gerade keine DOS - Funktion ausgefĂŒhrt, wĂ€hrend der Wert 1 die aktuelle AusfĂŒhrung einer DOS - Funktion anzeigt. Wenn eine DOS - Funktion bei ihrer AusfĂŒhrung eine andere DOS - Funktion aufruft, kann diese Flag auch grĂ¶ĂŸere Werte enthalten.

Der Inhalt dieses Flags kann direkt aus dem Speicher ausgelesen werden, da sich seine Adresse nach dem Booten des Systems nicht mehr Ă€ndert. Es ist sinnvoll diese Adresse wĂ€hrend der Installation des TSR - Programms mit der DOS - Funktion 34h, die nach ihrem Aufruf die Adresse des INDOS - Flags im Registerpaar ES:BX zurĂŒckliefert, in einer Variablen zu speichern. Die Abfrage dieses Flags wird nun so in den Interrupt - Handler fĂŒr den Interrupt 09h eingegliedert, dass er zwar weiterhin zunĂ€chst die BetĂ€tigung des Hotkeys ĂŒberprĂŒft, in diesem Fall jedoch die Aktivierung des TSR - Programms nur dann erlaubt, wenn das INDOS - Flag den Wert 0 enthĂ€lt.

Ein weiteres Problem bringt die Aktivierung des TSR - Programms von der DOS - OberflĂ€che heraus. Da sich der Befehlsinterpreter des DOS (COMMAND.COM) selbst einiger DOS - Funktionen zur Ausgabe des Prompts und der Entgegennahme von Eingaben durch den Anwender bedient, enthĂ€lt das INDOS - Flag hier fortwĂ€hrend den Wert 1. In diesem speziellen Fall wĂ€re die Unterbrechung zwar relativ sicher, doch mĂŒsste festgestellt werden, ob das INDOS - Flag den Wert 1 enthĂ€lt, weil eine DOS - Funktion von einem transienten Programm oder vom DOS - Befehlsinterpreter aufgerufen wird.

Doch auch fĂŒr diesen Fall gibt es eine Lösung. Sie beruht darauf, dass das DOS in periodischen AbstĂ€nden den Interrupt 28h aufruft, der fĂŒr die kurzzeitige Aktivierung von Hintergrundprozessen verantwortlich ist. Wird dieser Interrupt aufgerufen, kann man grundsĂ€tzlich davon ausgehen, das DOS unbeschĂ€ftigt und es relativ sicher ist, das TSR - Programm zu aktivieren. Dieser Interrupt trĂ€gt deshalb auch den Namen DOS - Idle (dt. idle = unbeschĂ€ftigt).

Dieses Verhalten ausnutzend, wird beim Start des TSR - Programms ein neuer Handler fĂŒr den Interrupt 28h installiert. Er ruft zunĂ€chst den alten Handler fĂŒr diesen Interrupt auf und prĂŒft dann, ob der Anwender den Hotkey betĂ€tigt hat. Trifft dies zu, kann das TSR - Programm aktiviert werden, auch wenn das INDOS - Flag einen Wert ungleich 0 enthĂ€lt.

Eine weitere EinschrĂ€nkung muss hier jedoch insofern gemacht werden, als dass eine Aktivierung des TSR - Programms nur dann erlaubt werden sollte, wenn innerhalb des Systems keine zeitkritischen Aktionen durchgefĂŒhrt werden.


Zeitkritische Aktionen

Hierunter fallen Aktionen, die aus bestimmten GrĂŒnden nicht unterbrochen, also in einer relativ kurzen Zeit beendet werden mĂŒssen. Beim PC zĂ€hlen dazu vor allem die Zugriffe auf Diskette und Festplatte, die auf unterster Ebene ĂŒber den BIOS - Interrupt 13h gesteuert werden. Wird ein Zugriff auf diese GerĂ€te nicht in kĂŒrzester Zeit abgeschlossen, so kann es zu ernsthaften Störungen im Systemablauf kommen. Eine dramatische Situation ergibt sich dann sogar, wenn das TSR - Programm einen Zugriff auf diese GerĂ€te durchfĂŒhrt, wĂ€hrend ein anderer Zugriff (ausgelöst durch das unterbrochene Programm) noch nicht abgeschlossen ist. Dies kann, wenn vielleicht auch nicht zum Systemabsturz, so doch auf jeden Fall zu Datenverlust fĂŒhren.

Vermieden wird dies wiederum durch Installation eines eigenen Interrupt - Handlers fĂŒr den BIOS - Interrupt 13h. Dieser Handler inkrementiert bei seinem Aufruf ein internes Flag, das anzeigt, dass der BIOS - Disk - Interrupt gerade aktiv ist. Danach ruft er den alten Handler fĂŒr diesen Interrupt auf, der den Zugriff auf das Diskettenlaufwerk oder die Festplatte durchfĂŒhrt. Kehrt er dann wieder in den Handler des TSR - Programms zurĂŒck, dekrementiert dieser das zuvor gesetzte Flag und signalisiert dadurch das Ende der AktivitĂ€t des BIOS - Disk - Interrupts.

Um eine Unterbrechung dieses Interrupts zu verhindern, nehmen die anderen Interrupt - Handler innerhalb des TSR - Programms auf dieses Flag insofern RĂŒcksicht, als dass sie das TSR - Programm nur dann aktivieren, wenn aus seinem Inhalt hervorgeht, dass der BIOS - Disk - Interrupt nicht aktiv ist.


Rekursion

Da die BetÀtigung des Hotkeys nach der Aktivierung des TSR - Programms weiterhin möglich ist, muss vermieden werden, dass das TSR - Programm erneut aktiviert wird, ohne zuvor beendet worden zu sein. Diese Rekursion kann man leicht verhindern, indem auch hier ein Flag installiert wird, das bei der Aktivierung des Programms gesetzt und bei seiner Beendigung wieder gelöscht wird. Stellt einer der Interrupt - Handler bei der BetÀtigung des Hotkeys mit Hilfe dieses Flags fest, dass das TSR - Programm bereits aktiv ist, so ignoriert er die BetÀtigung des Hotkeys.

Werden alle genannten Bedingungen erfĂŒllt, so steht der Aktivierung des TSR - Programms nichts mehr im Wege.


Verzögerte Aktivierung

Weil ein TSR - Programm aufgrund der AktivitĂ€ten des DOS oder des BIOS nicht zu jedem Zeitpunkt in den Vordergrund geschaltet wrden kann, installieren die meisten TSR - Programme auch einen Interrupt - Handler fĂŒr den Timer - Interrupt 08h, der eine Verzögerung der Aktivierung möglich macht. Dazu wird bei der Entdeckung des Hotkeys innerhalb des Tastatur - Interrupt - Handlers ein spezielles Flag gesetzt, wenn die Aktivierung des TSR - Programms gerade nicht möglich ist.

Dieses Flag wird nun innerhalb des neuen Timer - Interrupt - Handlers abgefragt, der 18,2 mal in der Sekunde aufgerufen wird, sofern das Vordergrund - Programm ihn nicht auf eine andere Taktfrequenz eingestellt hat. Wird dabei festgestellt, dass das TSR - Programm tatsÀchlich auf seine Aktivierung wartet und dass derzeit weder das DOS noch das BIOS aktiv ist, steht der Aktivierung des TSR - Programms nichts mehr im Wege.

Allerdings sollte die Zeitdauer, die zwischen der BetĂ€tigung des Hotkeys und der Aktivierung des TSR - Programms vergeht, begrenzt werden. Sonst kann es bei langwierigen DOS - Operationen dazu kommen, dass das TSR - Programm erst mehrere Sekunden nach der BetĂ€tigung des Hotkeys aktiviert wird. Fehlt eine zeitliche Begrenzung, weiß der Anwender nie, ob das TSR - Programm den Hotkey nicht erkannt hat oder ob es nur auf eine Möglichkeit wartet, das TSR - Programm zu aktivieren.

Das Flag, das fĂŒr die verzögerte Aktivierung des TSR - Programms gesetzt wird, dient deshalb gleichzeitig als Zeitmesser, indem es mit jedem Aufruf des Timer - Interrupts dekrementiert wird. Nur, solange es dabei einen Wert grĂ¶ĂŸer als 0 aufweist, wird der Versuch zur Aktivierung des TSR - Programms unternommen. Initialisiert der Tastatur - Interrupt - Handler dieses Flag beispielsweise mit 6, muss die Aktivierung innerhalb der nĂ€chsten 6 Aufrufe des Timer - Interrupts erfolgen, was einer Zeitdauer von einer drittel Sekunde entspricht. Wenn nicht, bleibt die BetĂ€tigung des Hotkeys ohne Wirkung.


Kontextwechsel

Die AblĂ€ufe bei der Aktivierung des TSR - Programms bezeichnet man in der Sprache der Informatiker als einen Kontextwechsel. Zum Kontext, oder einfacher gesagt zur Umgebung eines Programms zĂ€hlen dabei alle Informationen, die zum Betrieb des Programms benötigt werden. Dazu zĂ€hlen zum Beispiel der Inhalt der Prozessor - Register, wichtige Informationen des Betriebssystems, aber auch der vom Programm belegte Speicher. Um letzteren muss man sich beim Kontextwechsel in TSR - Programmen jedoch nicht kĂŒmmern, weil ein TSR - Programm bei seiner Installation als resident markiert wird und der von ihm belegte Speicher vom Betriebssystem deshalb nicht mehr an andere Programme vergeben wird.

Die Prozessor - Register, allen voran die Segmentregister, mĂŒssen jedoch mit den Werten geladen werden, die das TSR - Programm bei seiner AusfĂŒhrung erwartet. Dazu sind sie bei der Installation des TSR - Programms in interne Variablen gespeichert worden und können nun mit Hilfe dieser Variablen wieder restauriert wrden. Da der Inhalt dieser, aber auch der Inhalt aller anderen Register bei der AusfĂŒhrung des TSR - Programms verĂ€ndert wird, mĂŒssen sie zuvor jedoch gesichert werden, da sie zum Kontext des unterbrochenen Programms gehören und bei seiner Wiederaufnahme nicht verĂ€ndert worden sein dĂŒrfen.

Gleiches gilt fĂŒr die kontextabhĂ€ngigen Betriebssysteminformationen, wobei fĂŒr DOS hier lediglich der PSP (Program Segment Prefix) des Programms und der DTA (Disk Transfer Area) von Bedeutung ist. Die Adressen beider Strukturen mĂŒssen bei der Installation des TSR - Programms ermittelt, gespeichert und beim Kontextwechsel zum TSR - Programm dann wieder gesetzt wrden. Nicht vergessen darf man hier natĂŒrlich die Adresse des PSP und der DTA des unterbrochenen Programms vor dem Kontextwechsel zum TSR - Programm zu sichern, damit sie nach dessen Beendigung wieder auf ihren ursprĂŒnglichen Wert zurĂŒckgesetzt werden können.

WĂ€hrend die Adresse des DTA mit Hilfe zweier DOS - Funktionen gesetzt (Funktion 1Ah) und ermittelt (Funktion 2Fh) werden kann, existieren entsprechend dokumentierte Funktonen fĂŒr den PSP nicht in allen DOS - Versionen. Zwar gibt es ab der DOS - Version 3.0 die dokumentierte Funktion 62h, mit der die Adresse des aktuellen PSP ermittelt werden kann, doch fehlt weiterhin eine Funktion, mit der diese Adresse gesetzt werden kann. Im Bereich der undokumentierten Funktionen finden sich jedoch die benötigten Funktionen bereits seit der DOS - Version 2.0. Es handelt sich dabei um die Funktion 50h (Adresse des PSP sezten) und um die Funktion 51h (Adresse des PSP ermitteln).

Eine letzte Vorsichtsmaßnahme muss in bezug auf die Aktivierung des Programms ĂŒber den Interrupt 28h getroffen werden. Geht die Aktivierung von diesem Interrupt aus, wird sehr wohl eine aktive DOS - Funktion unterbrochen, deren Stack - Inhalt nicht zerstört werden darf. Aus diesem Grund werden generell die obersten 64 Words vom aktuellen Stack geholt und auf dem Stack des TSR - Programms gesichert. Damit ist der Kontextwechsel zum TSR - Programm vollzogen, und das TSR - Programm kann gestartet werden.

Von diesem Moment an kann das TSR - Programm als ganz normales Programm betrachtet werden, das beliebige DOS - und BIOS - Funktionen aufrufen darf. Von den vielen Gegenspielern innerhalb des Systems ist jetzt nur noch das Vordergrundprogramm ĂŒbrig, mit dem sich das TSR - Programm insofern arrangieren muss, als dass es seinen Bildschirminhalt nicht zerstören bzw. bei seiner Beendigung nicht verĂ€ndert hinterlassen darf.



Sicherung des Bildschirmkontextes

WĂ€hrend die bisher beschriebenen Aufgaben der Assembler - Schnittstelle zufallen, gehört die Sicherung des Bildschirmkontextes zur Aufgabe des Hochsprachen - Programms, das das eigentliche TSR - Programm darstellt. Zum Bildschirmkontext zĂ€hlen der aktuelle Videomodus, die Cursor - Position und der Bildschirminhalt. DarĂŒber hinaus mĂŒssen bei Grafikkarten auch die Inhalte der Farbauswahl - Register und anderer Register der Video - Karte gesichert werden, sofern hier VerĂ€nderungen vorgenommen werden.

Der aktuelle Viedeomodus kann leicht mit Hilfe der Funktion 00h des BIOS - Video - Interrupts 16h abgefragt werden. Stellt sich dabei heraus, dass sich der Bildschirm im Textmodus befindet (diese Modi tragen die Nummern 0, 1, 2, 3 und 7), muss lediglich die erste Textseite aus dem Video - RAM durch das TSR - Programm gesichert werden. Hierzu kann es sich ebenfalls des Video - BIOS bedienen oder direkt auf das Video - RAM zugreifen. Ergibt die Abfrage des Videomodus hingegen, dass ein Grafikmodus aktiv ist, wird die Sicherung des Videomodus schon aufgrund der Tatsache sehr kompliziert, dass das Video - RAM bei EGA - und VGA - Karten in bestimmten Videomodi eine GrĂ¶ĂŸe von bis zu 256 KByte erreichen kann. Hat das TSR - Programm dann ein transientes Programm bei seiner Arbeit unterbrochen, dĂŒrfte es kaum möglich sein, einen Puffer von derartiger GrĂ¶ĂŸe zu allokieren.

Aus diesem Grund verzichten viele TSR - Programme auf ihre Aktivierung innerhalb eines Grafikmodus und lassen sich nur innerhalb der verschiedenen Textmodi starten. Da unter DOS meistens im Textmodus gearbeitet wird, lĂ€sst sich mit diesem Makel in der Regel gut leben. Eine Ausnahme bilden hier jedoch die grafischen BenutzeroberflĂ€chen, allen voran Windows, die ausschließlich im Grafikmodus arbeiten. Da Windows jedoch eigene Mechanismen zur parallelen AusfĂŒhrung von Programmen bzw. zur Einbindung von Taschenrechnern, NotizbĂŒchern etc. anbietet, ist der Einsatz von TSR - Programmen hier ohnehin wenig sinnvoll.


Die Funktionen der Assembler - Schnittstelle

Die Assembler - Schnittstelle bietet ihrem Aufrufer die Möglichkeit, das TSR - Programm bei seinem ersten Aufruf von der DOS - Ebene aus zu installieren und es bei einem erneuten Aufruf wieder zu reinstallieren. DarĂŒber hinaus bietet die Assembler - Schnittstelle ihrem TSR - Programm bei einem Aufruf von der Kommandozeile aus die Möglichkeit, mit einer bereits im Speicher installierten Kopie ihrer selbst in Verbindung zu treten. Dadurch besteht z.B. die Möglichkeit, einen neuen Hotkey einzustellen, ohne das Programm aus dem Speicher zu entfernen und dann wieder installieren zu mĂŒssen. Aber auch andere Parameter lassen sich auf diese Art und Weise einrichten, denn es kann jede beliebige Pascal - Routine in dem bereits installierten TSR - Programm aufgerufen werden.

Um die genannten Mechanismen zu unterstĂŒtzen, bietet die Assembler - Schnittstelle dem Hochsprachenprogramm sieben Routinen an, die in der folgenden Tabelle (Abbildung 3) aufgefĂŒhrt werden.


Name
Aufgabe
TsrInit
Verwandelt das Programm in ein TSR - Programm, installiert die Interrupt - Handler, beendet es und verankert es dabei resident im Speicher.
TsrIsInst
Stellt fest, ob bereits eine Kopie des Programms im Speicher installiert ist.
TsrCanUninst
Stellt fest, ob die bereits installierte Kopie wieder entfernt werden kann.
TsrUnInst
Entfernt eine zuvor installierte Kopie des Programms wieder aus dem Speicher.
TsrSetPtr
HĂ€lt die Adresse der Routine fest, die in der bereits installierten Kopie des Programms aufgerufen werden soll.
TsrCall
Ruft die beim Aufruf von TsrSetPtr angegebene Routine auf.
TsrSetHotkey
Stellt den Hotkey des Programms ein.

Abbildung 3: Die Routinen der Assembler - Schnittstelle


Abfrage des Installations - Status

Von den genannten Routinen sollte das Hochsprachen - Programm zunĂ€chst die Routine TsrIsInst aufrufen, denn mit ihrer Hilfe lĂ€sst sich feststellen, ob bereits eine Kopie des Programms als TSR - Programm im Speicher verankert wurde. Die Routine bedient sich dabei einer Funktion des DOS - Multiplexer - Interrupts 2Fh (MUX). Der Interrupt - Handler fĂŒr den Interrupt 2Fh reagiert jedoch nur auf eine ganz bestimmte Funktion, deren Funktionsnummer beim Aufruf von TsrIsInst festgelegt wird. Wird dieser Interrupt mit einer anderen Funktionsnummer aufgerufen, leitet das TSR - Programm diesen Aufruf einfach an den alten Handler weiter. Der neue MUX - Interrupt - Handler unterstĂŒtzt zwei Unterfunktionen mit den Nummern AAh und BBh. Erstere hilft beim Auffinden einer bereits installierten Kopie.

Wie bei MUX - Funktionen ĂŒblich, vertauscht sie bei ihrem Aufruf dazu einfach die Funktions - und Unterfunktionsnummern im Registerpaar AH/AL. Ist das TSR - Programm nicht installiert, unterbleibt dieser Tausch, da sich keiner der bisherigen MUX - Handler fĂŒr diese Funktion verantwortlich fĂŒhlt und den Inhalt des AX - Registers deshalb unverĂ€ndert zurĂŒckgibt.

Ist das Programm bereits installiert, wird innerhalb von TsrIsInst dann auch gleich die zweite MUX - Funktion aufgerufen, die die Segmentadresse des TSR - Programms im Speicher zurĂŒckliefert. Dieser Wert wird, wie alle anderen Variablen des Assembler - Moduls, im Codesegment des Moduls untergebracht. Dies bietet die GewĂ€hr, dass diese Variablen auch innerhalb der Interrupt - Handler angesprochen werden können, wenn das Datensegment des Programms nicht erreichbar ist.


Einstellung des Hotkeys und Installation

Stellt das Programm mit Hilfe von TsrIsInst fest, dass es noch nicht installiert war, wird in der Regel die Installation folgen. Dabei handelt es sich um einen zweistufigen Prozeß, in dessen Verlauf zunĂ€chst der Hotkey des Programms mit Hilfe von TsrSetHotkey eingestellt wird. Anschließend wird das Programm mit Hilfe von TsrInit als TSR - Programm im Speicher verankert und seine AusfĂŒhrung zunĂ€chst beendet.
Diese TsrSetHotkey - Routine erwartet als Argument die beiden Parameter, die den Hotkey bestimmen: Die Bit - Maske fĂŒr die Steuertasten und den Scan - Code der zugehörigen Buchstaben - oder Zifferntaste. Beide Parameter können mit Hilfe zahlreicher Konstanten konstruiert werden, die sich am Anfang des Pascal - Programms finden.

FĂŒr die Umschalttasten tragen diese Parameter die Namen LSHIFT (linke Schift - Taste), RSHIFT (rechte Shift - Taste), ALT, CTRL etc. Mehrere dieser Konstanten können durch ein binĂ€res ODER miteinander verknĂŒpft werden, wenn mehrere Umschalttasten gleichzeitig betĂ€tigt werden mĂŒssen, um das TSR - Programm zu aktivieren. Das binĂ€re ODER entspricht auf der Anwender - Seite also einem logischen UND.

Die verschiedenen Konstanten fĂŒr die Scan - Codes der einzelnen Tasten beginnen alle mit dem PrĂ€fix SC_, auf den dann der Buchstabe oder die Ziffer bzw. deren Name folgt. (z.B. SC_5, SC_X oder SC_SPACE). Soll das Programm lediglich durch BetĂ€tigung einer oder mehrerer Umschalttasten aktiviert werden können, ohne dass dazu eine Buchstaben - oder Zahlentaste betĂ€tigt werden muss, können Sie sich der Konstante SC_NOKEY bedienen.

Nach der Einstellung der Hotkeys wird das Programm durch den Aufruf von TsrInit in ein TSR - Programm verwandelt. TrsInit erwartet von seinem Aufrufer dabei zwei Parameter: Die Offsetadresse der eigentlichen TSR - Routine und eine Information, die ĂŒber den Speicherbedarf des Programms Auskunft gibt.

Aufgabe von TsrInit ist es, zunĂ€chst die Adressen der Interrupt - Handler 08h, 09h, 13h, 28h und 2Fh zu ermitteln und zu speichern. Danach werden die Daten ermittelt, die zum Kontext des Hochsprachen - Programms gehören. Auch sie werden in Variablen innerhalb des Codesegments gespeichert, damit sie spĂ€ter fĂŒr die Interrupt - Handler und zur Aktivierung des TSR - Programms zugĂ€nglich sind. Im nĂ€chsten Schritt werden die neuen Interrupt - Handler installiert. Als Funktionsnummer fĂŒr den MUX - Interrupt 2Fh wird dabei die Funktionsnummer eingesetzt, die beim vorhergehenden Aufruf von TsrIsInst angegeben wurde.

Bevor das Programm dann ĂŒber die DOS - Funktion 31h als residentes Programm im Speicher verankert werden kann, muss die GrĂ¶ĂŸe des Programms und damit die Anzahl der Paragraphen berechnet werden, die nach der Programmbeendigung, resident im Speicher verbleiben sollen. Die Installation ist damit abgeschlossen, und das Programm wird resident beendet.


Entfernung aus dem Speicher

TSR - Programme arbeiten oft nach der Logik: Beim ersten Aufruf installieren, beim nÀchsten wieder aus dem Speicher entfernen. Wurde nach dem Aufruf von TsrIsInst am Anfang des Programms daher festgestellt, dass sich bereits eine Kopie des Programms resident im Speicher befindet, wird man diese Kopie in der Regel wieder deaktivieren wollen.

Dazu muss zunĂ€chst einmal die Funktion TsrCanUnist aufgerufen werden. Sie stellt fest, ob das Programm ĂŒberhaupt reinstalliert werden kann, denn nicht immer ist dies möglich. Das gilt vor allem, wenn nach der Installation des Programms noch ein anderes TSR - Programm installiert wurde, das die Interrupt - Vektoren des Timers, der Tastatur etc. ebenfalls umleitet. Denn auch dieses Programm wird bei seiner Installation die Adressen der bisherigen Handler ermittelt haben und diese innerhalb seiner eigenen Interrupt - Handler anspringen. Bei den bisherigen Handlern handelt es sich aber um die Handler des zu deinstallierenden TSR - Programms, die damit aus dem Speicher entfernt wĂŒrden. Da es jedoch leider keine Möglichkeit gibt, das andere TSR - Programm von der Entfernung dieser Handler in Kenntnis zu setzen, werden sie weiterhin aufgerufen, was nur eines zur Folge haben kann: den Absturz des Systems.

TsrCanUninst ĂŒberprĂŒft deshalb, ob noch alle umgeleiteten Interrupts direkt auf die Interrup - Handler der bereits installierten Kopie des TSR - Programms verweisen und liefert dementsprchend TRUE oder FALSE zurĂŒck. Nur bei TRUE darf das Programm anschließend TsrUninst aufrufen, um die installierte Kopie wieder aus dem Speicher zu entfernen.

Dabei werden zunĂ€chst wieder die alten Interrupt - Handler fĂŒr die Interrupts 08h, 09h, 13h, 28h und 2Fh installiert. Anschließend wird der Speicher des Programms wieder freigegeben, damit er von DOS wieder an andere Programme verteilt wreden kann, Das Programm hinterlĂ€sst dadurch keinerlei Spuren im Speicher.


Aufruf von Routinen im installierten TSR

SpĂ€testens bei der Reinstallation eines TSR - Programms wird man von der Möglichkeit Gebrauch machen mĂŒssen, Routinen innerhalb der installierten Kopie aufzurufen. Denn auch der Hochsprachen - Teil eines TSR wird oftmals Betriebsmittel (Speicher, Interrupt - Vektoren, Dateien) fĂŒr sich in Anspruch nehmen, die bei seiner Entfernung aus dem Speicher wieder an das Betriebssystem zurĂŒckgegeben werden mĂŒssen.

Da sich die Segmentadresse der installierten Kopie problemlos ĂŒber den MUX - Handler ermitteln lĂ€sst und die Offsetadresse der jeweiligen Routine die gleiche ist, wie in der gerade ausgefĂŒhrten Kopie des Programms, ließe sich leicht ein FAR - Ziger auf die Routine in der installierten Kopie des Programms konstruieren, ĂŒber den die gewĂŒnschte Routine aufgerufen werden kann. Voraussetzung dafĂŒr wĂ€re lediglich, dass die aufgerufene Routine vom Typ FAR ist, aber auch das ließe sich bewerkstelligen.

Die ganze Sache hat jedoch einen großen Hacken, denn durch den direkten Aufruf der Routine findet kein Kontextwechesl zu der installierten Kopie des Programms im Speicher statt. Es bleibe also weiterhin das Datensegment der aktuell ausgefĂŒhrten Kopie aktiv, genau wie deren PSP und DTA. Dadurch bliebe der aufgerufenen Routine aber der Zugriff auf ihre Variablen im Datensegment versperrt, denn sie wĂŒrde auf die Variablen in der gerade aufgerufenen Kopie des Programms zugreifen.

Dashalb muss man sich fĂŒr den Aufruf einer Routine in der bereits installierten Kopie des Programms eines Mittlers bedienen, der vor dem Aufruf der gewĂŒnschten Routine den Kontextwechsel zur installierten Kopie ausfĂŒhrt und auch den anschließenden Kontextwechsel zurĂŒck zum gerade ausgefĂŒhrten Programm ĂŒbernimmt.

Eine solche Routine wĂŒrde als Argument lediglich die Offsetadresse der auszufĂŒhrenden Routine in der installierten Kopie des TSR benötigen. Das funktioniert zwar, ist jedoch nicht besonders komfortabel, weil dabei keine Argumente an die aufzurufende Routine ĂŒbergeben werden können und auch die Entgegennahme eines RĂŒckgabewertes nicht möglich ist.

Um aber auch die Übergabe von Parametern und die Entgegennahme eines Funktionsergebnisses möglich zu machen, wurde fĂŒr den Aufruf von Routinen in der bereits installierten Kopie des TSR - Programms ein anderer Weg gewĂ€hlt, der in den zwei Routinen der Assembler - Schnittstelle involviert sind: TsrSetPtr und TsrCall.

Von diesen beiden Routinen muss zunĂ€chst TsrSetPtr aufgerufen werden, welche die Adresse der aufzurufenden Routine entgegennimmt und sie in einer Variablen der Assembler - Schnittstelle speichert. Anschließend erfolgt der Aufruf der Routine TsrCall, die den Kontextwechsel durchfĂŒhrt und sich der zuvor gepeicherten Adresse bedient, um die gewĂŒnschte Routine aufzurufen.

Das Problem dabei ist nur, das TsrCall natĂŒrlich innerhalb des Hochsprachen - Moduls deklariert und dabei auch die verschiedenen Parameter aufgefĂŒhrt werden mĂŒssen, die ĂŒber TsrCall an die jeweilige Routine ĂŒbergeben werden sollen. Die Anzahl der Parameter und ihr Typ hĂ€ngt von der auszufĂŒhrenden Routine ab und variiert.


Das Hochsprachen - Programm

Turbo Pascal unterstĂŒtzt nur ein Speichermodell, das von seinem Aufbau her der Implementierung von TSR - Programmen entgegenkommt.



























Abbildung 4: Speicheraufbau eines Pascal - Programms unter Turbo Pascal ab Version 4.0


Die Abbildung 4 zeigt, dass hinter dem PSP der Programmcode und die benötigten Routinen aus den verschiedenen Units sowie aus der Run - Time - Library folgen. Daran schließen sich die vordefinierten Konstanten, die globalen Daten sowie das Stacksegment an. WĂ€hrend die GrĂ¶ĂŸe dieser Programmbestandteile bei der Kompilierung festgelegt wird und sich nicht mehr Ă€ndert, gilt dies fĂŒr die GrĂ¶ĂŸe des Heap, der sich an das Stacksegment anschließt, nicht. Werden neue Objekte mit NEW erzeugt, wĂ€chst der Heap, wĂ€hrend mit RELEASE der Heap wieder auf das Ende des Stacksegments zugeht.

Turbo Pascal bietet den großen Vorteil, die maximale GrĂ¶ĂŸe des Heap sowie die StackgrĂ¶ĂŸe einstellen zu können. Es handelt sich dabei um die $M - Direktive, die mit folgenden Parametern aufgerufen werden muss:

{$M StackgrĂ¶ĂŸe, minimale Heap - GrĂ¶ĂŸe, maximale Heap - GrĂ¶ĂŸe}

Alle Angaben beziehen sich auf ein Byte, so dass die Direktive

{$M 2048, 0, 5000}

die Erzeugung eines 2 KByte großen Stacks und eines maximal 5000 Byte großen Heap bei der Kompilierung zur Folge hat. Fehlt eine solche Direktive innerhalb des Programms, ist dem Wachstum des Heap keine Grenze gesetzt, und er kann sich bis zum Ende des Hauptspeichers ausdehnen. Dies hĂ€tte jedoch die katastrophale Folge, dass der gesamte Hauptspeicher fĂŒr das TSR - Programm nach dessen Beendigung reserviert werden mĂŒsste und kein Speicher fĂŒr weitere Programme mehr zur VerfĂŒgung stĂ€nde. Indem dem Programm aber die $M - Direktive vorangestellt wird, lĂ€sst sich die maximale GrĂ¶ĂŸe des Programms im Speicher und damit die Anzahl der Paragraphen, die nach der Beendigung des Programms resident im Speicher verbleiben mĂŒssen, genau berechnen.

Auch hier bietet Turbo Pascal den Vorteil, dass die Anzahl zu reservierender Paragraphen bereits aus dem Pascal - Programm heraus berechnet werden kann, die komplizierte Berechnung innerhalb der Assemblerschnittstelle entfĂ€llt also. FĂŒr diese Zwecke wichtig sind dabei die Anfangsadresse des PSP und das Ende des Heap, da sie den Anfang und das Ende des TSR - Programms im Speicher markieren. Turbo Pascal definiert diese Informationen als ganz normale Variablen, die in Form von Pointern fĂŒr ein Pascal - Programm zugĂ€nglich sind.

Die Abbildung 4 zeigt, dass die Segmentadresse des PSP in der Variablen PrefixSeg zu finden ist, wÀhrend das Ende des Heap bis zur Version 6.0 mit Hilfe der (Pointer - )Variablen FreePtr ermittelt werden kann. Zwar zeigt diese Variable nicht direkt auf das Ende des Heap, doch enthÀlt der Segmentteil dieses Pointers die Endadresse des Heap minus $1000. Unter der Version 6.0 wurde die Verwaltung des Heap etwas verÀndert: Hier ist es der Zeiger HeapEnd, der direkt auf das Ende des Heap zeigt.

Die VerfĂŒgbarkeit dieser Informationen macht sich innerhalb des TSR - Programms die Prodzedur ResPara zunutze, indem sie mit Hilfe der genannten Variablen die Anzahl der Paragraphen berechnet, die nach der Installation des TSR - Programms resident im Speicher verbleiben mĂŒssen. Mit Hilfe konditionaler Kompilierung wird dabei je nach der Turbo - Pascal - Version auf den Zeiger HeapPtr oder HeapEnd zurĂŒckgegriffen.

Bei der Pascal - TSR - Funktion, deren Adresse TsrInit als erster Parameter ĂŒbergeben werden muss, muss es sich um eine Prozedur handeln, die sich innerhalb des Hauptprogramms und nicht innerhalb einer Unit befindet. DarĂŒber hinaus darf sie nicht mit Hilfe der $F+ - Compiler - Direktive in eine FAR - Procedure verwandelt werden, da die Assembler - Schnittstelle davon ausgeht, dass sie es hier mit einer NEAR - Procedure zu tun hat. Aus diesem Grund muss die Adresse diesr Prozedur mit Hilfe der Funktion OFS ermittelt und an die Funktion TsrInit ĂŒbergeben werden, da Turbo Pascal sonst neben der Offset - Adresse der Prozedur auch die Segment - Adresse auf den Stack ablegen wĂŒrde.

FAR mĂŒssen hingegen die Prozeduren und Funktionen sein, die in der installierten Kopie des Programms aufgerufen werden sollen. Das Casting von Funktionszeigern in Turbo Pascal ist nicht erlaubt. Aus diesem Grund liefert TsrSetPtr kein Ergebnis an ihren Aufrufer zurĂŒck, und der Aufruf von TsrSetPtr und TsrCall kann nicht miteinander kombiniert wrden.

Allerdings mĂŒssen zunĂ€chst Code - Zeiger deklariert wrden, die die aufzurufenden Prozeduren bzw. Funktionen und vor allem ihre Argumente beschreiben. Wie der folgende Auszug aus dem Programm - Listing von TSRP.PAS zeigt, tragen diese Zeiger die Namen OAProzT und SHKProzT. OAProzT stellt dabei einen Zeiger auf eine Prozedur dar, die keine Argumente erwartet, wĂ€hrend SHKProzT auf die BedĂŒrfnisse der Prozedur TsrSetHotkey zugeschnitten wurde.

type OAProzT = procedure;
SHKProzT = procedure ( Keymask:word; ScCode:byte );
PPtrT = record
case integer of
1 : ( OAProz : OAProzT );
2 : ( SHKProz : SHKProzT );
end;

const Call : PPtrT = ( OAProz:TsrCall );

Zusammengefaßt werden diese Typen in einem Varianten - Record, der fĂŒr jeden Typen einen Eintrag enthĂ€lt. Sie tragen hier die namen OAProz fĂŒr OAProzT und SHKProz fĂŒr SHKProzT. Um die Funktionen aufrufen zu können, die mit diesen Typen verbunden sind, wird eine globale Variable mit dem Namen Call definiert, deren OAProz - Komponente gleich mit einem Zeiger auf die TsrCall - Prozedur initialisiert wird.

Über diese Variable kann die gewĂŒnschte Prozedur oder Funktion anschließend aufgerufen werden, sofern ihre Offset - Adresse zuvor an TsrSetPtr ĂŒbergeben wurde. Dies zeigen auch die folgenden beiden Programmzeilen, in denen zunĂ€chst TsrSetHotkey beim Aufruf von TsrSetPtr als die auszurufende Routine festgelegt, und TsrCall anschließend mit den Argumenten fĂŒr TsrSetHotkey aufgerufen wird.

TsrSetPtr (ofs (TsrSetHotKey));
Call.SHKProz (Keymask, ScCode);

Dies wird möglich, weil der Compiler durch Verwendung der SHKProz - Komponente von Call davon ausgeht, dass tatsÀchlich eine derartige Prozedur aufgerufen wird. TatsÀchlich wird aber TsrCall aufgerufen.

Nach dem Start des Hochsprachen - Programms TSRP.PAS werden zunÀchst einmal die Parameter aus der Kommandozeile mit Hilfe der Funktion ParamGetHotKey ausgewertet. Sie erkennt als Hotkeys alle Parameter an, die mit dem PrÀfix "/t" beginnen. Dahinter darf der Name einer Umschalttaste (lshift, rshift, alt, ctrl etc.) oder die Nummer einer Taste folgen, die als Scan - Code herangezogen werden soll. Dabei wird eine Zahl im Dezimalformat erwartet.

Zur Auswahl der linken [Shift] Taste, der [Alt] - Taste und der [Leertaste] als Hotkey mĂŒssen also folgende Parameter angegeben werden:

/tlshift /talt /t57

wobei die Reihenfolge der Parameter keine Bedeutung hat.

Als Resultat trĂ€gt ParamGetHotkey den gewĂŒnschten Status der Umschalttasten und den Scan - Code des Hotkeys in die beiden Variablen KeyMask und ScCode, die ihr zu diesem Zweck ĂŒbergeben werden.

Wird bei der Auswertung der Kommandozeile ein Fehler entdeckt, wird die ProgrammausfĂŒhrung mit einer entsprechenden Bildschirmmeldung gestoppt. Andernfalls wird mit Hilfe der Funktion TsrIsInst aus dem Assembler - Modul ĂŒberprĂŒft, ob das Programm bereits installiet war. Dabei wird auch die Funktionsnummer festgelegt, ĂŒber die spĂ€ter der MUX - Handler des Programms erreicht werden kann. Über die Konstante I2F_CODE ist bisher die Funktion C4h eingestellt, doch können Sie durchaus eine andere Funktion wĂ€hlen. Von dieser Möglichkeit sollten Sie auf jeden Fall Gebrauch machen, wenn Sie mehrere TSR - Programme mit Hilfe der Assembler - Schnittstellen entwickeln. Denn sonst besetzen die verschiedenen Programme die gleiche MUX - Funktion und kommen sich dadurch in die Quere.

Doch bei der Auswahl neuer MUX - Funktionsnummern ist Vorsicht geboten, denn zahlreiche Werte werden bereits durch andere Programme verwendet, und Werte kleiner als C0h sollten gar nicht eingesetzt werden.

Zeigt der Aufruf von TsrIsInst, dass das Programm noch nicht installiert war, wird anhand der Variablen KeyMask und ScCode ĂŒberprĂŒft, ob bei der Auswertung der Kommandozeile /t - Parameter entdeckt wurden. Wenn nicht, weisen die beiden Variablen Default - Werte auf, und als Hotkey wird durch Aufruf der Assembler - Routine TsrSetHotkey die Tastenkombination [Alt]+[H] festgelegt. Andernfalls wird der vom Anwender vorgegebene Hotkey ebenfalls ĂŒber TsrSetHotkey eingestellt.

Was bleibt, ist dann nur noch der Aufruf der Assembler - Routine TsrInit, die das Programm in ein TSR - Programm verwandelt. Als TSR - Prozedur wird dabei die Hoschsprachen - Routine TSR angegeben, doch dazu gleich mehr.

Hat der Aufruf von TsrIsInst gezeigt, dass das Programm bereits installiert war, hĂ€ngt das weitere vorgehen vom Anwender ab. Hat er beim Aufruf des Programms einen Hotkey angegeben, wird dieser Hotkey mittels TsrSetHotkey in der bereits installierten Kopie des Programms als neuer Hotkey eingestellt und das Programm anschließend ohne die Reinstallation des TSR - Programms beendet. Wurde jedoch kein neuer Hotkey angegeben, wird durch den Aufruf von TsrCanUninst zunĂ€chst ĂŒberprĂŒft, ob die bereits installierte Kopie des Programms wieder deaktiviert werden kann. Wenn ja, wird anschließend TsrUninst aufgerufen, um das Programm zu deaktivieren.

Zuvor wird in der installierten Kopie des Programms jedoch noch eine Hochsprachen - Routine mit dem Namen EndePrz aufgerufen, die die internen Ressourcen des Programms wieder frei - und eine Bildschirmmeldung ausgibt, aus der die Anzahl der Aktivierungen des TSR - Programms hervorgeht.

Sie bezieht sich dabei auf die globale Variable ATimes, die mit jeder Aktivierung des TSR - Programms inkrementiert wird. Dies geschieht in der TSR - Prozedur des Programms, die den Namen TSR trĂ€gt. Hier wird zunĂ€chst der Tastaturpuffer geleert, um den Hotkey von dort zu entfernen. Anschließend wird der Bildschirm des unterbrochenen Programms gesichert und der Anwender dann durch Ausgabe einer Bildschirmmeldung zur BetĂ€tigung einer beliebigen Taste aufgefordert. Sobald dies geschehen ist, wird wieder der Bildschirm des unterbrochenen Programms zum Vorschein gebracht und die TSR - Prozedur beendet, wodurch auch das unterbrochene Programm wieder zur AusfĂŒhrung kommt.


Das Beispielprogramm

Das Hauptprogramm trÀgt den Namen TSRP.PAS, die dazugehörigen Assembler - Routinen sind im Programm TSRPA.ASM zu finden.


Noch ein paar Tips zum Schluß

Es empfiehlt sich fĂŒr die Entwicklung von TSR - Programmen einige besondere Vorgehensweisen, die mit dem speziellen Charakter dieser Programme zusammenhĂ€ngen. ZunĂ€chst sollte das Programm als ganz normales Programm entwickelt werden, das von der DOS - OberflĂ€che oder aus einer integrierten Umgebung kompiliert und zur AusfĂŒhrung gebracht wird.

Um bei der Umwandlung in ein TSR - Programm möglichst wenige Umstellungen vornehmen zu mĂŒssen, kann man dabei bereits eine Initialisierungsroutine und die eigentliche TSR - Routine entwickeln, die spĂ€ter bei der BetĂ€tigung des Hotkeys aufgerufen werden soll. Im Gegensatz zur TSR - Version lĂ€sst man diese Routinen jedoch innerhalb der Hauptprozedur (bzw. Funktion) des Programms explizit aufrufen, macht ihre Aktivierung also nicht von der BetĂ€tigung des Hotkeys abhĂ€ngig. Auf diese Art und Weise sollte das Programm zunĂ€chst komplett entwickelt und ausgetestet werden. Erst wenn es sich als fehlerfrei erwiesen hat, sollte die Umwandlung in ein TSR - Programm erfolgen, da nach dieser Umwandlung das AufspĂŒren von Fehlern (auch mit Hilfe eines Debuggers) kaum mehr möglich ist.

Die Umwandlung in ein TSR - Programm selbst ist relativ simpel, da dazu lediglich die Assembler - Schnittstelle in das Programm eingebunden und die entsprechenden Funktionen aus dem Assembler - Modul aufgerufen werden.


7588 Worte in "deutsch"  als "hilfreich"  bewertet