home *** CD-ROM | disk | FTP | other *** search
- ;****************************************
- ;* VGASAVE.ASM
- ;*
- ;* Syntax:
- ;* VGASAVE [dateiname] [/Tx] :VGASAVE installieren, angegebenen
- ;* Dateinamen (Default: VGA_BILD.001) beim
- ;* Speichern benutzen, Aktivierung über
- ;* <ALT> + Taste x (default: S)
- ;* VGASAVE - :VGASAVE deinstallieren
- ;* VGASAVE ? :Information anzeigen, ob VGASAVE bereits
- ;* im Speicher installiert ist, falls ja:
- ;* Dateinamen und Hotkey anzeigen
- ;*
- ;****************************************
-
- ;*** Makro zum Lesen von Zeichen aus Parameterzeile
-
- getpar macro
- local mac002 ;Lokale Sprungmarke definieren
-
- mov al,ds:anzpar ;Anzahl Zeichen in Parameterzeile holen
- mov ah,00 ;auf 16 Bit bringen
- cmp si,ax ;Zeiger in Parameterzeile mit Anzahl vgl.
- stc ;Ende signalisieren
- je mac002 ;Ende erreicht
- mov al,parzeil[si] ;noch kein Ende: Zeichen nach al holen
- inc si ;Zeiger in Parameterzeile erhöhen
- clc ;Carry-Flag löschen -> Ende nicht erreicht
- mac002:
- endm ;Ende des Makros
-
- defkey equ 1f00h ;erweiterter Tastaur-Code Default-Hotkey
- defkeyc equ "S" ;Default-Hotkey ist <ALT> + S
- anzpar equ 80h ;PSP Offset 80h: Länge der Parameterzeile
- parzeil equ 82h ;PSP Offset 82h: Parameterzeile
- ; (eigentlich 81h, dort aber Leerzeichen)
- video equ 0a000h ;Segment-Adresse des Video-RAMs
-
- code segment para 'CODE' ;Code-Segment (und Daten- u. Stacksegment)
-
- org 100h ;256 Byte für PSP reservieren
-
- assume cs:code, ds:code, es:code, ss:code
-
- start: jmp iniproc ;Sprung zur Initialisierungsroutine
-
- altint equ this dword ;Far-Adresse des alten Interrupt-Vektors
- altinto dw (?) ;deren Offset-Adresse
- altints dw (?) ;deren Segment-Adresse
- handle dw (?) ;DOS-Datei-Handle
- pag db (?) ;selektiertes RAM-Segment der VGA-Karte
- off dw (?) ;Offset innerhalb RAM-Segment der VGA-Karte
- count dw (?) ;Zähler für Byte-Wiederholungen
- wdhsatz equ this byte ;Datensatz zum Speichern einer Wiederholung
- kennung db (?) ; dessen einleitende Kennung
- dw (?) ; Anzahl der Byte-Wiederholungen
- db (?) ; zu wiederholendes Byte
- lesetab db 2 dup (?) ;FIFO-Puffer für zuletzt eingelesene 2 Bytes
- paltab db 3*256 dup (?) ;Puffer für Auslesen der Paletten-Register
- anz_l dw 256 dup (?) ;Tabelle für Byte-Häufigkeiten -> Low-Word
- anz_h dw 256 dup (?) ;dto. -> High-Word
-
- ;*** neue Interrupt-Routine für Interrupt 09h
- ;*** nach Aufruf des alten Interrupts wird auf Tastendruck von
- ;*** ALT-S getestet und ggf. das aktuelle VGA-Bild komprimiert und
- ;*** gespeichert
-
- neuint proc far ;neue Interrupt-Routine für Interrupt 09h
-
- jmp short skip_id ;Kennung überspringen
-
- ;*** Kennung der Interrupt-Routine
- ;*** Mit Hilfe dieser Kennung kann bei wiederholtem Aufruf von VGASAVE
- ;*** festgestellt werden, ob VGASAVE bereits installiert ist. Ggf. wird
- ;*** VGASAVE dann deinstalliert.
-
- db "VgaSave!"
-
- ;*** zuerst noch alte Interrupt-Routine ausführen
-
- skip_id:pushf ;Interrupt-Aufruf simulieren
- call cs:[altint] ;Sprung in alte Interrupt-Routine
-
- cli ;maskierbare Interrupts sperren
-
- push ax ;alle Register sichern
- push bx
- push cx
- push dx
- push di
- push si
- push bp
- push ds
- push es
-
- ;*** Tastatureingabe testen
-
- mov ah,1 ;Tastatur-Interrupt, Fkt. 1:
- int 16h ;Zeichen in Tastaturpuffer vorhanden?
-
- je quit ;kein Zeichen vorhanden
-
- cmp ax,1f00h ;ALT-S gedrückt ?
- jne quit ;nein
-
- mov ah,0 ;Fkt. 0: Zeichen auslesen
- int 16h ;ALT-S aus Tastaturpuffer entfernen
-
- ;*** auf korrekten Videomodus testen
-
- mov ah,0fh ;Video-Modus überprüfen
- int 10h ;Fkt. 0fh: Video-Informationen liefern
- cmp al,30h ;800x600 Punkte, 256 aus 256K Farben ?
- je ok2 ;ja, in Ordnung
- jmp modeerr ;nein, Modus-Fehler
-
- ;*** Aktion einleiten
-
- ok2: mov dx,9121 ;Tonfolge für Beginn der Aktion
- call sound
- mov dx,6087
- call sound
- mov dx,4560
- call sound
-
- call aktion ;Bild auslesen, packen, abspeichern
-
- mov dx,4560 ;Tonfolge Ende der Aktion
- call sound
- mov dx,6087
- call sound
- mov dx,9121
- call sound
-
- ;*** Interrupt beenden
-
- quit: pop es ;gesicherte Register zurückholen
- pop ds
- pop bp
- pop si
- pop di
- pop dx
- pop cx
- pop bx
- pop ax
-
- iret ;Interrupt beenden
-
- ;*** akustische Fehlermeldungen
-
- openerr:mov dx,20000 ;Fehler beim Öffnen der Datei
- call sound ;tiefen Ton erzeugen
-
- modeerr:mov dx,20000 ;Fehler durch falschen Video-Modus
- call sound ;tiefen Ton erzeugen
- jmp short quit ;Interrupt beenden
-
- neuint endp ;Ende der Interrupt-Routine
-
- ;*** Prozedur für Tonerzeugung
- ;*** Mittels dem Zeitgeber 8253 wird ein periodisches Signal erzeugt.
- ;*** Die Frequenz wird durch den übergebenen Wert im DX-Register
- ;*** bestimmt (Formel: Frequenz [Hz] = 1.193.180 : Wert). Die Tonlänge
- ;*** ist konstant und wird durch eine simple Verzögerungsschleife
- ;*** zwischen Ein- und Ausschalten des Lautsprechers realisiert.
-
- sound proc near
-
- ;*** Tonerzeugung einleiten
-
- mov al,182 ;Wert 182 auf Port 43h:
- out 43h,al ;Zeitgeber aktivieren
- mov ax,dx ;Frequenz-Parameter nach AX bringen
- out 42h,al ;Low-Byte an Zeitgeber senden
- mov al,ah ;High-Byte nach AL
- out 42h,al ;High-Byte an Zeitgeber senden,
- ; Signal wird nun erzeugt
- in al,61h ;Port für Lautsprechersteuerung lesen
- or al,11b ;Signal des Zeitgebers an Membran leiten
- out 61h,al ;Lautsprecher einschalten
-
- ;*** Warteschleife
-
- mov bx,0 ;Verzögerungszähler (low) initialisieren
- mov cx,8 ;dto. (high)
- delay: dec bx ;inneren Zähler bis 0 herunterzählen
- jne delay
- dec cx ;äußeren Zähler bis 0 herunterzählen
- jne delay
-
- ;*** Lautsprecher ausschalten
-
- in al,61h ;Port für Lautsprechersteuerung lesen
- and al,11111100b ;Bit 0 und löschen
- out 61h,al ;Lautsprecher ausschalten
- ret ;Rücksprung ins Hauptprogramm
-
- sound endp ;Ende der Prozedur
-
- ;*** Prozedur zum Auslesen des Video-RAMs, Komprimieren der Daten und
- ;*** anschließendem Abspeichern.
- ;*** Da bei Bildern benachbarte Punkte häufig die gleiche Farbe auf-
- ;*** weisen, arbeitet der eingesetzte Komprimier-Algorithmus trotz
- ;*** seiner Einfachheit recht effektiv: Bei aufeinanderfolgenden
- ;*** gleichen Bytes werden diese als Wiederholung abgespeichert in der
- ;*** Form [Kennung],[Anzahl der Wiederholungen],[Bytewert]. Der
- ;*** Dekomprimieralgorithmus erkennt eine Wiederholung an der Kennung,
- ;*** aus diesem Grunde muß ein im Bild auftretender Byte-Wert, der mit
- ;*** dem Kennungsbyte identisch ist, ebenfalls als Wiederholung kodiert
- ;*** werden. Um diesen Nachteil zu minimieren, wird zu Beginn des Kom-
- ;*** primier-Vorgangs das Bild untersucht und das am seltensten auf-
- ;*** tretende Byte als Kennung benutzt.
-
- aktion proc near
-
- ;*** Datensegment-Register auf Codesegment setzen, da sich Daten im
- ;*** Codesegment befinden
-
- push cs ;Codesegment sichern
- pop ds ;und als Datensegment zurückholen
- assume ds:code ;Assembler mitteilen, daß sich nun das
- ; Datensegment mit Codesegment deckt
-
- ;*** VGA-Bild untersuchen, um am seltensten auftretendes Byte ermitteln
-
- ;*** Häufigkeits-Tabelle initialisieren
-
- mov di,510 ;256 Wörter => Offset 0 - 510
- null: mov anz_l[di],0 ;Low-Word mit 0 initialisieren
- mov anz_h[di],0 ;dto. High-Word
- sub di,2 ;Zeiger auf nächstes Wort
- jns null ;Null noch nicht unterschritten => weiter
-
- ;*** VGA-RAM durchsuchen und Häufigkeiten ermitteln
-
- ;*** Initialisierungen
-
- mov pag,0 ;Wert für RAM-Segment der VGA-Karte
- mov si,0 ;Offset innerhalb des VGA-RAM-Segments
- mov ax,video ;Adresse des VGA-RAM-Segments
- mov es,ax ;ins ES-Register
-
- ;*** VGA-RAM-Segment selektieren
-
- s1: mov dx,3cdh ;3cdh: GDC-Segment-Select-Register
- in al,dx ;SSR-Register auslesen
- and al,11000111b ;Bits 3-5 löschen (Read-Segment-Pointer)
- mov bl,pag ;Wert für VGA-RAM-Segment
- mov cl,3 ;Anzahl der Links-Shifts
- shl bl,cl ;Wert an die richtige Bit-Position schieben
- or al,bl ;Bits 3-5 auf Segment-Nummer setzen
- out dx,al ;zurückschreiben
-
- ;*** VGA-RAM-Segment auslesen und Bytes zählen
-
- w2: mov al,es:[si] ;aktuelles Byte auslesen
- mov ah,0 ;auf 16 Bit bringen
- shl ax,1 ;Multiplikation mit 2, da Wort-Zugriff
- mov di,ax ;Ergebnis als Index in Tabelle nach DI
- inc anz_l[di] ;Eintrag in Tabelle erhöhen
- jnz w1 ;kein Überlauf, ok
- inc anz_h[di] ;sonst noch Übertrag berücksichtigen
- w1: inc si ;Offset in VGA-RAM-Segment erhöhen
- jnz w2 ;noch nicht am Ende, dann weiter
- inc pag ;sonst Segment-Nummer erhöhen
- cmp pag,8 ;mit Endwert vergleichen
- jb s1 ;noch kleiner, dann weiter
-
- ;*** Untersuchung des VGA-RAMs abgeschlossen, kleinsten Wert suchen
- ;*** AX/BX enthalten bisher kleinsten Wert, CX/DX enthalten laufende
- ;*** Tabellen-Werte für Vergleich mit AX/BX
-
- ;*** Initialisierungen
-
- mov ax,anz_l[0] ;AX mit erstem Tabellenwert (low) besetzen
- mov bx,anz_h[0] ;dto. BX (high)
- mov di,0 ;Index für bisher kleinsten Wert
- mov si,2 ;laufender Index
-
- ;*** Vergleich von laufendem Element mit AX/BX
-
- vergl: mov cx,anz_l[si] ;laufendes Low-Word nach CX
- mov dx,anz_h[si] ;laufendes High-Word nach DX
- cmp ax,cx ;32 Bit-Vergleich AX/BX <-> CX/DX
- sbb bx,dx
- jc kleiner ;AX/BX immer noch kleiner als CX/DX
-
- ;*** neuen kleinsten Wert gefunden
-
- mov ax,cx ;laufendes Low-Word nach AX
- mov bx,dx ;laufendes High-Word nach BX
- mov di,si ;laufenden Index nach SI
-
- ;*** Schleifenende
-
- kleiner:add si,2 ;laufenden Index erhöhen
- cmp si,512 ;mit Ende vergleichen
- jne vergl ;noch nicht am Ende, dann weiter suchen
-
- ;*** kleinster Wert ist ermittelt
-
- mov ax,di ;Index für kleinsten Wert nach AX
- shr ax,1 ;entsprechendes Byte = Index / 2
- mov kennung,al ;als Kennung ablegen
-
- ;*** Datei öffnen
-
- mov ah,3ch ;DOS-Fkt. 3ch: Datei erstellen
- mov cx,0 ;normales Datei-Attribut
- mov dx,offset datname;Adresse des Dateinamens
- int 21h ;Öffnen der Datei
- jnc ok1 ;kein Fehler aufgetreten, dann weiter
- jmp openerr ;sonst Fehlermeldung
-
- ok1: mov handle,ax ;DOS-Datei-Handle merken
-
- ;*** Paletten-Register speichern
-
- ;*** Extrasegment-Register auf Datensegment setzen, da sich Puffer
- ;*** für Palettendaten im Datensegment befindet
-
- push ds ;Datensegment sichern
- pop es ;und als Extrasegment zurückholen
-
- mov ah,10h ;Fkt. 10h: Paletten-Register bearbeiten
- mov al,17h ;Sub-Fkt. 17h: Palettenregister-Block lesen
- mov dx,offset paltab;ES:DX = Zeiger auf Datenpuffer
- mov bx,0 ;bei Paletten-Register 0 beginnen
- mov cx,256 ;(alle) 256 Register auslesen
- int 10h ;ausführen
-
- mov ah,40h ;DOS-Fkt. 40h: Datei beschreiben
- mov bx,handle ;Handle der Datei setzen
- mov cx,3*256 ;Anzahl Bytes (1 Register = 3 Bytes [RGB])
- mov dx,offset paltab;Adresse des Datenpuffers
- int 21h ;Speichern ausführen
-
- ;*** Color-Page-Informationen speichern
-
- mov ah,10h ;Fkt. 10h: Paletten-Register bearbeiten
- mov al,1ah ;Sub-Fkt. 1ah: Color-Page-Status liefern
- int 10h ;ausführen
- mov paltab[0],bl ;aktuellen Paging-Mode sichern
- mov paltab[1],bh ;aktuelle Color-Page sichern
-
- mov ah,40h ;DOS-Fkt. 40h: Datei beschreiben
- mov bx,handle ;Handle der Datei setzen
- mov cx,2 ;Anzahl Bytes
- mov dx,offset paltab;Adresse des Datenpuffers
- int 21h ;Speichern ausführen
-
- ;*** bei diesem Bild verwendete Wiederholungs-Kennung speichern
-
- mov ah,40h ;DOS-Fkt. 40h: Datei beschreiben
- mov bx,handle ;Handle der Datei setzen
- mov cx,1 ;Anzahl Bytes
- mov dx,offset kennung;Adresse des Datenpuffers
- int 21h ;Speichern ausführen
-
- ;*** Video-RAM auslesen, packen, speichern
-
- ;*** Initialisierungen
-
- mov pag,0 ;Wert für VGA-RAM-Segment
- mov off,0 ;Offset innerhalb VGA-RAM-Segment
- mov count,0 ;Zähler für Byte-Wiederholungen
- mov si,0 ;Zeiger für FIFO-Lesepuffer
- mov ax,video ;Extrasegment auf VGA-RAM-Segment
- mov es,ax
-
- ;*** aktuelles VGA-RAM-Segment selektieren
-
- seite: mov dx,3cdh ;3cdh: GDC-Segment-Select-Register
- in al,dx ;SSR-Register auslesen
- and al,11000111b ;Bits 3-5 löschen (Read-Segment-Pointer)
- mov bl,pag ;Wert für VGA-RAM-Segment
- mov cl,3 ;Anzahl der Links-Shifts
- shl bl,cl ;Wert an die richtige Bit-Position schieben
- or al,bl ;Bits 3-5 auf Segment-Nummer setzen
- out dx,al ;zurückschreiben
-
- ;*** aktuelles Byte auslesen
-
- readram:mov di,off ;Offset in aktuelles VGA-RAM-Segment
- mov al,es:[di] ;Byte aus Video-Ram auslesen
- mov lesetab[si],al ;FIFO-Puffer füllen
-
- ;*** Sonderfall Startzustand behandeln
-
- cmp si,0 ;Zeiger in FIFO-Puffer = 0 ?
- je plus ;ja -> Startzustand, erstes Byte gelesen
-
- ;*** auf Byte-Wiederholung testen
-
- cmp al,lesetab[0] ;Vergleich mit erstem Byte aus FIFO-Puffer
- je plus ;Gleichheit: Wiederholungen zählen
-
- ;*** zum Vorgänger unterschiedliches Byte
-
- cmp count,4 ;Wiederholungs-Zähler prüfen
- jnb save2 ;bei mehr als 3 Wiederholungen komprimieren
-
- ;*** Sonderfall: gelesenes Byte = Kennungsbyte
-
- mov al,kennung ;Kennungsbyte holen
- cmp al,lesetab[0] ;mit zu speicherndem Zeichen vergleichen
- je save2 ;bei Gleichheit als Wiederholung speichern
-
- ;*** Speichern von 1-3 Zeichen
-
- mov di,count ;Wiederholungszähler nach DI
- dec di ;um 1 vermindern, da Schleifenende bei -1
-
- ;*** Speichern im Normalfall (keine Wiederholung) 1 - 3 mal
-
- save1: mov ah,40h ;DOS-Fkt. 40h: Datei beschreiben
- mov bx,handle ;Handle der Datei setzen
- mov cx,1 ;Anzahl der Zeichen = 1 (aber DI-Schleife)
- mov dx,offset lesetab;Adresse des Datenbereichs
- int 21h ;Speichern ausführen
- dec di ;Zähler vermindern
- cmp di,0ffffh ;auf Ende testen
- jne save1 ;falls Ende nicht erreicht: weitermachen
-
- ;*** FIFO-Stack shiften
-
- rueck: mov al,lesetab[1] ;2. Byte holen
- mov lesetab[0],al ;an 1. Stelle schreiben
- mov si,1 ;Zeiger auf 2. Byte setzen
- mov count,1 ;Wiederholungszähler initialisieren
- jmp short plus2 ;Lesezeiger auf nächstes Zeichen
-
- ;*** Wiederholungen zählen
-
- plus: mov si,1 ;FIFO-Zeiger auf 2. Byte
- inc count ;Wiederholungszähler erhöhen
- cmp count,0ffffh ;mit Maximalwert vergleichen
- jne plus2 ;kein Überlauf, ok
- call savewdh ;sonst Zwischenspeichern
- mov count,0 ;Wiederholungszähler initialisieren
- mov si,0 ;FIFO-Zeiger auf 1. Byte (Startzustand)
-
- ;*** Lesezeiger auf nächstes Byte in VGA-RAM
-
- plus2: inc off ;Offset in Video-RAM-Segment erhöhen
- jnz readram ;Segment-Ende nicht erreicht, weiterlesen
-
- ;*** Wert für nächstes VGA-RAM-Segment setzen
-
- inc pag ;VGA-RAM-Segment-Zähler erhöhen
- cmp pag,8 ;mit Endwert (+1) vergleichen
- jnb savrest ;Ende erreicht, Rest speichern
- jmp seite ;Ende nicht erreicht, Segment selektieren
-
- ;*** Speichern einer Wiederholung, Komprimieren
-
- save2: call savewdh ;Wiederholung speichern
- jmp short rueck ;FIFO-Stack shiften, weiter einlesen
-
- ;*** bei Erreichen RAM-Endes noch nicht verarbeiteten Rest abspeichern
-
- ;*** auf Sonderfall prüfen: gelesenes Byte = Kennungsbyte
-
- savrest:mov al,lesetab[0] ;letztes Zeichen holen
- cmp al,kennung ;und mit Kennungs-Byte vergleichen
- je save4 ;Übereinstimmung: als Wiederholung speichern
-
- ;*** bei mehr als 3 Wiederholungen als Wiederholung speichern
-
- cmp count,4 ;Wiederholungszähler mit 4 vergleichen
- jnb save4 ;größer: als Wiederholung speichern
-
- ;*** sonst als einzelne Bytes speichern
-
- mov di,count ;Anzahl der Bytes nach DI
- jmp short decdi ;Einsprung in Schleife
-
- ;*** Schleife für Speichern von einzelnen Rest-Bytes
-
- save3: mov ah,40h ;DOS-Fkt. 40h: Datei beschreiben
- mov bx,handle ;Handle der Datei setzen
- mov cx,1 ;Anzahl der Zeichen
- mov dx,offset lesetab;Adresse des Datenpuffers
- int 21h ;Speichern ausführen
- decdi: dec di ;Anzahl vermindern
- jns save3 ;Ende noch nicht erreicht, Schleife
- jmp short close ;sonst Sprung zum Dateischließen
-
- ;*** Rest als Wiederholung speichern
-
- save4: call savewdh ;Wiederholung speichern
-
- ;*** Datei schließen
-
- close: mov ah,3eh ;DOS-Fkt. 3eh: Datei schließen
- mov bx,handle ;Handle der Datei setzen
- int 21h ;Schließen ausführen
-
- ret ;Rücksprung zum Hauptprogramm
-
- aktion endp ;Ende der Prozedur
-
- ;*** Prozedur zum Speichern einer Wiederholung
-
- savewdh proc near
-
- mov ax,count ;Anzahl der Wiederholungen nach AX
- mov wdhsatz[1],al ;Low-Byte setzen
- mov wdhsatz[2],ah ;High-Byte setzen
- mov al,lesetab[0] ;zu wiederholendes Byte nach AL
- mov wdhsatz[3],al ;setzen
- mov ah,40h ;DOS-Fkt. 40h: Datei beschreiben
- mov bx,handle ;Handle der Datei setzen
- mov cx,4 ;Anzahl der Zeichen
- mov dx,offset wdhsatz;Adresse des Datenpuffers
- int 21h ;Speichern durchführen
-
- ret ;zurück zum Hauptprogramm
-
- savewdh endp ;Ende der Prozedur
-
- datname db 80 dup (?) ;Bereich für Dateinamen
-
- defname db "vga_bild.bin" ;Default-Dateiname
- defnam0 equ this byte ;End-Adresse (+1) des Default-Dateinamens
-
- residen equ this byte ;bis hier bleibt's resident
-
- inst_m db 13,10,13,10 ;Text für Installationsmeldung
- db "VGASAVE wurde installiert !",13,10
- db 13,10
- db "RAM-residentes Tool, um VGA-Bild (800x600 Punkte,",13,10
- db "256 aus 256K Farben) zu komprimieren und auf",13,10
- db "Diskette/Festplatte abzuspeichern.",13,10
- db 13,10
- db "Aufruf durch < ALT-S >.",13,10
- db "Eine Tonfolge signalisiert daraufhin das Starten des",13,10
- db "Prozesses, nach Beendigung erklingt eine weitere",13,10
- db "Tonfolge.",13,10
- db "Bei falschem Video-Modus erklingt 1 tiefer Ton, bei",13,10
- db "Fehlern beim Öffnen der Datei erklingen 2 tiefe Töne.",13,10
- db 13,10
- db "Anzeige eines gespeicherten Bildes mit",13,10,13,10
- db " VGALOAD [Pfad] Dateiname [/A] [/E] [/Wnn]",13,10
- db 13,10,"$"
-
- meldaus db 13,10,13,10 ;Text für Deinstallationsmeldung
- db "VGASAVE wurde deinstalliert !",13,10,13,10,"$"
-
- ;*** Interrupt-Initialisierungs-Routine
- ;*** Sichert den bisherigen Interrupt-Vektor des Interrupt 09h, setzt
- ;*** den Vektor auf die eigene Interrupt-Routine und installiert es
- ;*** resident im Speicher, oder, falls VGASAVE bereits installiert
- ;*** war, entfernt sie VGASAVE wieder aus dem Speicher.
-
- iniproc proc near
-
- ;*** Feststellen, ob VGASAVE bereits installiert ist
-
- mov ah,35h ;DOS-Fkt. 35h: Interrupt-Vektor auslesen
- mov al,09h ;Interrupt-Nummer 09h: Tastatur-Interrupt
- int 21h ;Vektor nach ES:BX holen
- cmp word ptr es:[bx+2],"gV";auf Identifikation testen
- jne intini ;Ungleichheit => Installation
- cmp word ptr es:[bx+4],"Sa"
- jne intini
- cmp word ptr es:[bx+6],"va"
- jne intini
- cmp word ptr es:[bx+8],"!e"
- jne intini
-
- ;*** Deinstallation
-
- ;*** ehemaligen Interrupt-Vektor wiederherstellen
-
- mov ah,25h ;DOS-Fkt. 25h: Interrupt-Vektor setzen
- mov al,09h ;Interrupt-Nummer 09h: Tastatur-Interrupt
- mov dx,es:altints ;Segment-Adresse holen
- mov ds,dx ;und nach DS bringen
- mov dx,es:altinto ;Offset-Adresse nach DX bringen
- int 21h ;Vektor setzen/wiederherstellen
-
- ;*** zu VGASAVE gehörenden Environment-Block freigeben
-
- push es ;Segment-Adresse von VGASAVE merken
- mov ah,49h ;DOS-Fkt. 49h: RAM freigeben
- mov es,es:[2ch] ;PSP Offset 2ch: Segment-Adresse Env.-B.
- int 21h ;Speicher freigeben
- pop es ;ES wiederherstellen
-
- ;*** von VGASAVE belegten Speicher freigeben
-
- mov ah,49h ;DOS-Fkt. 49h: RAM freigeben
- int 21h ;ausführen (ES = Segment-Adresse VGASAVE)
-
- ;*** Meldung ausgeben
-
- push cs ;Datensegment := Codesegment, da sich
- pop ds ;Daten im Codesegment befinden
-
- mov ah,09h ;DOS-Fkt. 09h: Zeichenkette ausgeben
- mov dx,offset meldaus;Adresse des Meldungstextes
- int 21h ;Ausgabe
-
- ;*** Programm beenden
-
- mov ah,4ch ;DOS-Fkt. 4ch: Programm m. Ende-Code beenden
- mov al,0 ;Ende-Code 0: Kein Fehler
- int 21h ;Programm beenden
-
- ;*** Installations-Routine für VGASAVE
-
- ;*** bisherigen Interrupt-Vektor merken
-
- intini: mov altints,es ;Segment-Adresse sichern
- mov altinto,bx ;Offset-Adresse sichern
-
- ;*** Dateinamen aus Parameterzeile holen
-
- push ds ;ES auf DS setzen,
- pop es ;ES wird beim Kopieren benutzt
- mov di,offset datname;Zeiger in Zielbereich initialisieren
-
- mov si,parzeil ;Quellzeiger auf Parameterzeile setzen
- mov cl,ds:anzpar ;Anzahl Zeichen in Parameterzeile holen
- mov ch,0 ;auf 16 Bit bringen
- cmp cx,0 ;Anzahl mit 0 vergleichen
- je copy0 ;Datei-Name wurde nicht angegeben => Default
-
- dec cl ;Anzahl wegen Leerzeichen um 1 vermindern
- jmp short copy ;zum Kopieren
-
- copy0: mov si,offset defname;Quellzeiger auf Default-Dateinamen setzen
- mov cx,defnam0 - defname;Anzahl Zeichen ermitteln
-
- copy: cld ;Directionflag löschen => vorwärts kopieren
- rep movsb ;Quellbereich nach Zielbereich kopieren
- mov datname[di],0 ;Endekennzeichen (Nullbyte) setzen
-
- ;*** eigenen Interrupt installieren
-
- mov ah,25h ;DOS-Fkt. 25h: Interrupt-Vektor setzen
- mov al,09h ;Interrupt 09h: Tastatur-Interrupt
- mov dx,offset neuint;Offset der eigenen Interrupt-Routine
- int 21h ;Interrupt-Vektor auf DS:DX setzen
-
- ;*** Meldung ausgeben
-
- mov ah,09h ;DOS-Fkt. 09h: Zeichenkette ausgeben
- mov dx,offset inst_m;Adresse des Textes
- int 21h ;Ausgabe
-
- ;*** nicht benötigten Speicher freigeben und Programm resident beenden
-
- mov ah,31h ;DOS-Fkt. 31h: Programm resident beenden
- mov al,0 ;Ende-Code 0: kein Fehler
- mov dx,offset residen;Grenze, bis zu der's resident bleibt
- add dx,15 ;auf nächsten Paragraphen aufrunden
- mov cl,4 ;4 mal Rechts-Shiften => durch 16 teilen
- shr dx,cl ;Segment-Adresse errechnen
- int 21h ;Programm resident beenden
-
- iniproc endp ;Ende der Prozedur
-
- code ends ;Ende des Code-Segments
- end start ;Ende des Programmtextes
-