|
QuickBasic Tutorials
Was sind eigentlich Interrupte?
Interrupte, genauer gesagt BIOS- und API-Routinen-Aufrufe, ermöglichen auch
unter QuickBasic so ziemlich alles wofür man sonst C++ oder Turbopascal bräuchte.
Diesen Bereich habe ich als Fragen-Antwort-Komplex aufgebaut. Es sind genau
die Fragen die bisher an mich gerichtet wurden:
Was sind eigentlich Interrupte?
Wozu brauche ich eigentlich Interrupte?
Was ist nötig um Interrupte aufzurufen?
Kann man auch in QBasic Interrupte aufrufen?
Wie rufe ich denn nun einen Interrupt auf?
Was für Register gibt es und wofür ist welches gut?
Was für Interrupte bzw. Funktionen gibt's denn nun alles?
Frage: |
Was sind eigentlich Interrupte? |
Antwort: |
Am Anfang gleich die größte Verwirrung. Der Begriff
"Interrupt" ist nämlich eigentlich falsch gewählt an
dieser Stelle. Vielmehr geht es um Routinen und Unterprogramme die
schon vom Betriebssystem bereitgestellt werden. Diese Routinen gibt
es sowohl im BIOS als auch im API (Aplication Program Interface) und
das schon seit der ersten DOS Version. Der große Vorteil dieser
Routinen ist, daß sie in jedem DOS basierenden Rechner (also auch
in Windows 9x / ME / XP und weiß der Geier) vorhanden und vor allem
kompatibel sind. |
nach oben
Frage: |
Wozu brauche ich eigentlich Interrupte? |
Antwort: |
Es gibt so manche Sache die sich nicht direkt mit
QBasic bzw. QuickBasic lösen läßt. Das sind zum Beispiel
Mausfunktionen, das Schreiben und Lesen von Datenträgern auf
Sektorbasis, Einstellen von Videomodi's, das Arbeiten mit CD-ROM und
vieles mehr. Man könnte sich statt der Interrupte natürlich auch
entsprechende Librarys downloaden und einbinden, aber der Gebrauch von
Interrupten hat einige Vorteile:
Kompatibilität - der Einsatz von Interrupten garantiert gleiche
Funktionen bei unterschiedlichen Betriebssystemen.
Flexibilität - d.h. höhere Geschwindigkeit der Programme.
Sicherheit des Quellcodes - das Programm stürzt nicht ab weil in
irgend einer Library ein Bug sitzt.
Entwerfen eigener angepaßter Library's.
Bessere Ausnutzung von Speicherplatz, da nur das im Quellcode steht
was auch reingehört.
UND - wir wollen ja programmieren - nicht zusammenkleistern. |
nach oben
Frage: |
Was ist nötig um Interrupte
aufzurufen? |
Antwort: |
Alles was dazu nötig ist, ist die Einbindung der
Standardbibliothek von QuickBasic (QB.QLB). Das geht fast von allein
indem man die QuickBasic-EXE mit der Option /L aufruft. (Voraussetzung
ist natürlich, daß die Datei im selben Verzeichnis wie die QuickBasic-EXE ist, oder daß der Suchpfad richtig gesetzt wurde.) Die
Zeile hat dann z.B. diesen Syntax C:\QB\QB.EXE /L C:\QB\QB.QLB
Des weiteren muß in QuickBasic (also im Programm) die
Bibliotheksdatei eingebunden werden. Dies geschieht mit der Zeile: REM
$INCLUDE:'QB.BI' Diese Bibliotheksdatei enthält alle
Type-Definitionen die die neuen Befehle benötigen.
Ist alles erledigt hat man 5 neue Befehle:
CALL INTERRUPT - ermöglicht den Aufruf von Interrupten
CALL INTERRUPTX - wie oben, jedoch mit Übergabe der Segmentregister
CALL ABSOLUTE - Start von Maschinenprogrammen
CALL INT86OLD - Kompatibilitätswahrung (wie INTERRUPT)
CALL INTX86OLD - Kompatibilitätswahrung (wie INTERRUPTX)
Ich habe festgestellt, daß man eigentlich nur einen einzigen
dieser Befehle tatsächlich braucht: CALL INTERRUPT. Da dieser aber
(eigentlich) die Übergabe der sogenannten Segmentregister nicht unterstützt,
habe ich die Datei QB.BI kurzerhand etwas umgeschrieben. So brauche
ich nur einen einzigen Befehl der alles kann. Die
"neue" Include Datei trägt bei mir den Namen: INTERUPT.BI
und befindet sich (natürlich) im INCLUDE Verzeichnis - damit sie QuickBasic
auch findet. Da ich diese Datei zum Teil auch in meinen Programmbeispielen
verwende, findest du sie dort immer mal wieder. Wo
das der Fall ist, mache ich aber darauf aufmerksam.
Und so sieht die Datei aus:
REM ***** Anfang Datei: INTERUPT.BI *****
TYPE RegType
ax AS INTEGER
bx AS INTEGER
cx AS INTEGER
dx AS INTEGER
bp AS INTEGER
si AS INTEGER
di AS INTEGER
flags AS INTEGER
ds AS INTEGER
es AS INTEGER
END TYPE
DECLARE SUB INTERRUPT (intnum AS INTEGER, inreg AS RegType, outreg AS
RegType)
DIM SHARED Reg AS RegType
REM ***** Ende Datei ***** |
nach oben
Frage: |
Kann man auch in QBasic Interrupte aufrufen? |
Antwort: |
Aus „Altertumsgründen“ gibt es in Qbasic die Funktionen zum
Aufrufen von Interrupten nicht. Das Ausführen von
Assemblerprogrammen, also Maschinenunterprogrammen, über CALL
ABSOLUTE ist jedoch möglich. Dadurch und durch ein kleines Hilfsprogramm
wird es möglich Interrupte auch unter Qbasic zu nutzen.
Download |
nach oben
Frage:
|
Wie rufe ich denn nun einen Interrupt auf? |
Antwort:
|
Als Beispiel betrachten wir
eine der Mausfunktionen. Die nachfolgende Beschreibung benötigen wir
zu jeder Funktion die wir aufrufen wollen.
Funktion: |
Interrupt 33h - Funktion 01h des DOS-API |
Beschreibung: |
Maus-Cursor auf dem Bildschirm anzeigen. Nach dem Aufruf dieser
Funktion wird der Maus-Cursor auf dem Bildschirm sichtbar und folgt
fortan den Bewegungen der Maus über den Bildschirm. |
Eingabe: |
AX = 0001h |
Ausgabe: |
keine |
Mit dem Aufruf dieser Funktion
ist die Inkrementierung (Erhöhung) eines internen Zählers verbunden,
der darüber entscheidet, ob der Maus-Cursor auf dem Bildschirm
dargestellt wird. Enthält dieser Zähler den Wert 0, wird der
Maus-Cursor auf dem Bildschirm dargestellt, während der Wert -1 seine
Ausblendung zur Folge hat. Beim Aufruf der Funktion 00h (Reset) wird
dieser Zähler zunächst auf -1 gesetzt, um dann durch den ersten
Aufruf dieser Funktion den Wert 0 anzunehmen und wieder auf dem
Bildschirm zu erscheinen. Der Maustreiber verfolgt die Mausbewegung
auch, wenn der Maus-Cursor nicht auf dem Bildschirm dargestellt wird,
so daß der Maus-Cursor nach dem Aufruf dieser Funktion nicht
unbedingt wieder an der Stelle erscheinen muß, an der er sich bei
seiner Ausblendung befand.
Hinweis: Unter MS-DOS muß ein Maustreiber installiert sein.
Und nun ein Programmbeispiel zu
dem Ganzen:
REM ***** Beispielprogramm: Interruptaufruf *****
REM $INCLUDE:'INTERUPT.BI'
CLS
PRINT "Bewege die Maus"
Reg.ax = &h1
CALL INTERRUPT(&h33, Reg, Reg)
WHILE INKEY$ = "": WEND
REM ***** Programmende *****
Was haben wir gerade gemacht?
Zeile 1: Wir binden die INCLUDE-Datei ein. (kann auch QB.BI sein)
Zeile 2: Bildschirm löschen
Zeile 3: Bildschirmhinweis
Zeile 4: Laden des Registers AX mit 01h (Funktionsnummer s.o.)
Zeile 5: Aufruf des Interrupts (33h ist die Interruptnummer)
Zeile 6: Auf eine Taste warten
Und das war's schon - wir haben unseren ersten Interrupt aufgerufen.
Das Prinzip ist immer gleich. Die entsprechenden Register werden geladen
und der entsprechende Interrupt wird aufgerufen. Ist doch eigentlich
ganz easy - und dafür 'ne ganze Library runterladen?
|
nach oben
Frage: |
Was für Register gibt es und wofür
ist welches gut? |
Antwort: |
Für den Aufruf von DOS- und BIOS-Funktionen sind vor
allem die allgemeinen Register von Bedeutung, denn mit ihrer Hilfe
werden der jeweiligen Funktion die Parameter übergeben, die sie zu
ihrer Ausführung benötigt. Hauptsächlich diese Register sind es
auch, die durch arithmetische Operationen (Addition, Subtraktion etc.)
beeinflußt werden, die auf der Prozessorebene den Mittelpunkt aller
Softwareaktivitäten darstellen. Eine Sonderstellung innerhalb des
Registersatzes kommt dabei den Registern AX, BX, CX und DX zu, weil
sie jeweils in zwei 8-Bit-Register unterteilt werden können. Damit
besteht jedes dieser Register praktisch aus drei verschiedenen
Registern: einem 16 Bit großen und zwei 8 Bits kleinen. Diese
"kleinen" Register werden jeweils mit H (high) und mit L
(low) bezeichnet, wodurch sich z.B. das 16 Bits umfassende AX-Register
in die 8- Bit-Register AH und AL aufspaltet. Die Anordnung des H- und
des L-Registers ist so gewählt, daß das L-Register die
niederwertigen 8 Bits (Bits 0 bis 7) und das H-Register die höherwertigen
8 Bits (Bits 8 bis 15) des X-Registers belegt. Das AH-Register setzt
sich damit aus den Bits 8 bis 15 und das AL-Register aus den Bits 0
bis 7 des AX-Registers zusammen.
Das Flag-Register dient zunächst einmal zur Kommunikation zwischen
aufeinanderfolgenden Maschinensprache-Befehlen, indem es den Status
arithmetischer und logischer Operationen speichert. So kann ein
Programm nach der Addition zweier 16-Bit-Register anhand des
Carry-Flags z.B. feststellen, ob das Resultat größer als 65535 war
und deshalb nicht mehr als 16-Bit-Zahl dargestellt werden konnte. Ähnliche
Aufgaben übernehmen auch das Sign-, das Zero- und das Overflow-Bit,
mit deren Hilfe sich nach dem Vergleich zweier Register feststellen läßt,
ob der Wert des ersten Registers größer, kleiner oder gleich dem des
zweiten war.
Für die Systemprogrammierung auf Hochsprachen-Ebene ist lediglich das
Carry-Flag und in ganz wenigen Ausnahmen auch das Zero-Flag von
Bedeutung, denn mit Hilfe dieser Flags zeigen die meisten DOS- und
BIOS-Funktionen ihrem Aufrufer an, ob während ihrer Ausführung ein
Fehler aufgetreten ist, weil beispielsweise nicht genügend Speicher
zur Verfügung stand, ein unbekannter Dateiname angegeben wurde oder
was auch immer.
Das Flag-Register:
Bit 0 - CF = Carry Flag
Bit 2 - PF = Parity Flag
Bit 4 - AF = Auxiliary Flag
Bit 6 - ZF = Zero Flag
Bit 7 - SF = Sign Flag
Bit 8 - TF = Trap Flag
Bit 9 - IF = Interrupt Flag
Bit 10 - DF = Direction Flag
Bit 11 - OF = Overflow Flag
Bleiben nur noch die Segment-Register. (CS, DS, SS und ES) diese
finden immer dann Verwendung, wenn einer Routine eine Speicheradresse
mitgeteilt werden muß, oder das rufende Programm eine Adresse zurückgeliefert
bekommt. Allgemein ausgedrückt markieren die Segment-Register immer
ein Datensegment und dessen Offset im Speicher des Computers. |
nach oben
Frage: |
Was für Interrupte bzw. Funktionen gibt's denn
nun alles? |
Antwort: |
Im Internet gibt es mehrere, mehr oder weniger komplette,
Interruptlisten. Diese sind allerdings meist so umfangreich, daß es
sehr schwer fällt die nötigen Informationen herauszulesen. Ich habe
daher zu den Tutorials, die sich mit Interrupten beschäftigen, oder
sich solcher bedienen, eine Liste der meisten Interrupte bzw.
Funktionen zusammengestellt die zu dem jeweiligen Gebiet gehören. |
nach oben
|
|