Viren im System?

Seit einiger Zeit (spätestens seit der CeBIT ’88) geistert es nur so von allen möglichen Schlagworten um den Virus. Jeder sucht Schutz für seine Programme und Daten. VIRUS EX hilft - auf einfache Weise. Zuerst einmal eine kurze Einführung. Was versteht man unter Viren? Viren sind in der Regel kleine Programme - damit sie nicht auffallen -, die sich von Diskette zu Diskette oder von Programm zu Programm weiterkopieren.

Das Prinzip ist immer ähnlich. Startet man ein infiziertes Programm, so gelangt der Virus in den Speicher und kann von nun an sein Unwesen treiben. Dieses Unwesen besteht vorerst darin, sich an andere (Wirts-) Programme anzuhängen, bis er sich ausreichend verbreitet hat. Dann aber kann er so richtig loslegen. Die möglichen Auswirkungen reichen von einem netten Gruß zu Weihnachten bis hin zur Formatierung von Disketten. Wann die Viren ihre vielfältige Funktion ausüben, kann man kaum Vorhersagen. Es kann zum Beispiel an einem bestimmten Datum oder auf eine bestimmte Aktion hin geschehen. Die Viren auf den Disketten (sie befinden sich meist im Bootsektor) verbreiten sich ähnlich. Neben diesen beiden Typen von Programmen sind selbstverständlich auch gekoppelte Programme (Bootsektor und Programm oder Track 81 auf der Diskette o.ä.) möglich. Da die Viren aber zu vielfältig sein können, soll hier nicht weiter darauf eingegangen werden.

Wie schützt man sich nun? Ein Schutz als solcher ist schlecht möglich, besser ist die Vorbeugung. Disketten lassen sich relativ einfach untersuchen. Den Bootsektor (Track 0, Sektor 1 auf Seite 0 der Diskette) läßt man sich mit einem Diskettenmonitor anzeigen und betrachtet ihn näher. Erster Hinweis ist eine $60 (hexadezimal) gleich an erster Stelle. Zweiter Hinweis ist die Prüfsumme des Bootsektors. Sie muß $1234 ergeben, sonst ist der Bootsektor auf keinen Fall ausführbar, und der Virus - sofern vorhanden - hat auch keine Chance, sich auszubreiten. Letzter Hinweis ist der Vergleich mit bekannten Viren, beispielsweise ist ein Virus, der die Zeichenfolge BPL enthält, bekannt ... und leider sehr verbreitet. Er soll zwar unschädlich sein, aber man entfernt ihn besser. Dazu müssen die Bytes 34 bis 511 auf 0 gesetzt werden. Die geschilderten Tätigkeiten sind aber auch keine Vorbeugung, sondern eher eine Nachbehandlung.

Viren in Programmen sind schwer zu erkennen. Sicheres Merkmal ist jedoch die Länge eines Programmes. Ist ein Programm plötzlich länger, so ist ein Virus sehr wahrscheinlich! (Nur Programmentwickler müssen aufpassen, denn bei Ihnen kann eine Veränderung an einem Programm auch eine Veränderung der Programmlänge bedeuten.) Da man kaum alle Programmlängen kennen kann, ist es vorteilhaft, die Programmnamen mit Pfad und Länge abzuspeichern und von Zeit zu Zeit zu überprüfen. Und genau das macht VIRUS EX!

Zuvor aber noch ein Wort zu grundsätzlichen Vorbeugungsmaßnahmen, die man treffen kann. Eine schreibgeschützte Diskette kann auch schwerlich von einem Virus befallen werden, also möglichst Schreibschutz aktivieren. Sicherheitskopien können sowieso nicht schaden, also besser mit Kopien arbeiten. Wer über Programmierkenntnisse verfügt, kann von seinen Disketten die ersten 18 logischen Sektoren in einer Datei abspeichern und sie notfalls wieder auf die Diskette schreiben. Damit hat man für den Notfall noch die FAT und das Directory sowie sonstige Informationen der Diskette. Hat man einen Virus entdeckt, so sollte man ihn (notfalls durch Löschen des betreffenden Programmes) entfernen. Aber vorher auf jeden Fall den Rechner einmal abschalten (Reset allein hilft nicht immer!)! Mehr soll hier nicht berichtet werden, nur noch ein kleiner Hinweis: Betrachten Sie Viren bitte nicht als Scherz! Viren sind eine echte Gefahr! Und besonders Harddisk-Benutzer sollten vorsichtig sein!

Bevor es etwas programmtechnisch wird, die Hinweise zur Benutzung von VIRUS EX. VIRUS EX ist ein Accessory. Kopieren Sie es auf das Bootlaufwerk (Diskette oder Partition C). Diskettenbenutzer sollten sich vor allem eine virenfreie Bootdiskette verschaffen. Möchten Sie die Programmdaten in eine Datei aufnehmen, muß das gewünschte Laufwerk eingestellt und “aufnehmen” angeklickt werden. Es erscheint ein File-Selector. Dort wird die Datei eingetragen, unter deren Namen die Datei angelegt werden soll. Sie sollte sich auf jeden Fall an einem Ort befinden, wo sie von Viren nicht angetastet werden kann. Möchte man eine Diskette oder Partition überprüfen, so stellt man ebenso erst das Laufwerk ein und wählt dann “überprüfen”, worauf wieder ein File-Selector erscheint. Dort wählt man nun die zur Diskette oder Partition passende Datei aus. Fehlt mittlerweile ein Programm, gibt es während der Untersuchung eine entsprechende Meldung, hat sich die Programmlänge geändert, erscheint eine Alertbox, bei der man wählen kann, ob das Programm erhalten bleiben oder gelöscht werden soll. Neu hinzugekommene Programme werden nicht geprüft. Sind neue Programme hinzugekommen, prüft man erst die alten und nimmt dann die neuen Daten auf.

Aufgenommen werden alle Programme, die auf ACC, PRG, TOS oder TTP enden. Accessories mitaufzunehmen, scheint nicht sinnvoll zu sein, aber es gibt einige wenige Programme, die sich durch einfache Umbenennung von PRG in ACC und umgekehrt auch als Programm nutzen lassen.

Wenden wir uns jetzt dem Programm VIRUS EX selbst zu. Es wurde in Modula 2 (Megamax) geschrieben. Bevor das Listing eingegeben wird, muß eine Resourcedatei mit einem Resource-Construction-Programm angelegt werden. Eine Dialogbox und vier Strings für Alertboxen sind analog zu den auf den Bildern zu sehenden Mustern zu erstellen. Die Erklärungen zum Listing kann man dem Listing selbst entnehmen.

Ist das Listing eingetippt und das Resourcefile angelegt, werden die drei Quelldateien (DEFINITION- und IMPLEMENTATION-Modul für das Resourcefile und Programm-Modul) übersetzt. Fertig!

Wer Megamax Modula 2 nicht sein eigen nennen kann, muß eine Übersetzung in eine andere Programmiersprache vornehmen. Fast alle Strukturen lassen sich leicht nachbilden. Aber trotzdem ein paar Hinweise zu DirQuery. DirQuery (in Prozedur WritePrgFileSub) ruft die übergebene Routine (hier WriteProgramName) solange mit einer bestimmten Maske (hier LokalName) auf, bis keine passenden Files mehr zu finden sind. Bei vielen anderen Programmiersprachen (oder besser Entwicklungspaketen) muß eine entsprechende Routine erst aufgebaut werden. Dazu benutzt man Fsetdta (Gemdos 26), um die Diskettentransferadresse zu setzen. Fsfirst (Gemdos 78), um die erste Datei zu suchen, und Fsnext (Gemdos 79), um nachfolgende Dateien zu ermitteln.

Schließlich ist ein zweites Listing - in GFA-BASIC - aufgeführt, welches lediglich eine Aufgabe hat. Das Programm soll eine Datei, die von VIRUS EX geschrieben wurde, auswerten. Die Programmdaten werden nacheinander auf dem Bildschirm ausgegeben.

    IMPLEMENTATION MODULE Virus_ex; 
    (*$N+,M-*)
    END Virus_ex.

Listing 1

    DEFINITION MODULE Virus_ex;

    EXPORT
        Userdial, Dec, Cdrive, Inc, Instal, Check, 
        Abbruch, Virus, Missprg, Baddrive, Diskerr;

    CONST
        Userdial    = 0; (* Formular/Dialog          *)
        Dec         = 3; (* BOXTEXT in Baum USERDIAL *)
        Cdrive      = 4; (* BOXTEXT in Baum USERDIAL *)
        Inc         = 5; (* BOXTEXT in Baum USERDIAL *)
        Instal      = 6; (* BUTTON in Baum USERDIAL  *)
        Check       = 7; (* BUTTON in Baum USERDIAL  *)
        Abbruch     = 8; (* BUTTON in Baum USERDIAL  *)
        Virus       = 0; (* Meldung-String Index     *)
        Missprg     = 1; (* Meldung-String Index     *)
        Baddrive    = 2; (* Meldung-String Index     *)
        Diskerr     = 3; (* Meldung-String Index     *)

    END Virus_ex.

Listing 2

(**************************************************) 
(* VIRUS EX-Ein Programm zur Überprüfung der Länge*) 
(*          von Programmen - V. 1.00              *)
(* ===============================================*)
(* Sollte sich ein (beliebiger) Virus an ein      *)
(* Programm anhängen, so kann dies von VIRUS EX   *) 
(* entdeckt werden. Es werden alle Programme mit  *) 
(* den Endungen ACC, PRG, TOS und TTP überprüft.  *)
(* ===============================================*)
(* Megamax Modula 2 ,Appl. Syst. /// Heidelberg.  *) 
(* ===============================================*)
(* Autor: Dietmar Rabich, Dövelingsweg 2,         *)
(* D-4408 Dülmen / 20. Juni 1988                  *)
(**************************************************) 

MODULE VirusEx; (*$R-,M-,Q+,N-,V-,P-,S-*)

(* Importe *)
                IMPORT Virus_ex; (* Resource-File *) 
FROM Files      IMPORT Create,Open,Close,Access,File,State,ResetState, ReplaceMode;
FROM Binary     IMPORT FileSize,ReadBytes,WriteBytes;
FROM Strings    IMPORT Append,Assign,String,Pos,Empty,StrEqual,Length;
FROM Directory  IMPORT FileAttr,FileAttrSet,DirEntry,Drive,DriveSet, 
    DriveStr,DirQuery,StrToDrive,DrivesOnline,Delete, 
    SplitPath,SplitName,DriveToStr,DefaultDrive;
FROM Convert    IMPORT ConvInt;
FROM SYSTEM     IMPORT ADR;
FROM GrafBase   IMPORT Rect,Rectangle,TransRect;
FROM GEMEnv     IMPORT InitGem,RC,DeviceHandle,GemError,SetCurrGemHandle; 
FROM GEMGlobals IMPORT PtrObjTree,PtrMaxStr,Root,OStateSet,MaxDepth,ObjState 
FROM AESEvents  IMPORT MessageEvent,MessageBuffer,ccOpen,TimerEvent;
FROM AESForms   IMPORT FormAlert,FormDial,FormDialMode,FormCenter,FormDo;
FROM AESGraphics IMPORT GrafMouse,MouseForm;
FROM AESMenus   IMPORT RegisterAcc;
FROM AESMisc    IMPORT SelectFile;
FROM AESObjects IMPORT ChangeObjState,DrawObject,ObjectOffset;
FROM AESResources IMPORT LoadResource,ResourceAddr,ResourcePart;
FROM AESWindows IMPORT UpdateWindow;
FROM ObjHandler IMPORT ObjectState,ObjectSpace,SetCurrObjTree,AssignTextStrings,SetPtrChoice;

(* Konstanten *)
CONST
    MaximalDrive=15; (* höchstens 16 Laufwerke! *)
    Leer        ='            ';
    NoResource  ='[0][VIRUS EX verzweifelt.|Resourcefile fehlt!][Wo ist es denn?]'; 
    Nolnstal    ='[0][VIRUS EXverzweifelt.|Installation unmöglich!][Schade.]';

(* Typen *)
TYPE ProgramID = RECORD
                    Path : ARRAY [0..63] OF CHAR;   (* Pfad des Programms *)
                    Name : ARRAY [0..11] OF CHAR;   (* Name des Programms *)
                    Numb : LONGCARD                 (* Filegröße *)
                 END;
    RWProc = PROCEDURE(ARRAY OFCHAR,CARDINAL, VAR INTEGER);

(* Variablen *)
VAR DriveCount,PositionVirF,PositionMiss,Position,
    VoidC           :CARDINAL;
    UserBox         :PtrObjTree;
    VirusFoundAlert,MissingProgAlert,BadDriveAlert,
    DiskErrorAlert  :PtrMaxStr; 
    dev             :DeviceHandle;
    InstalPath,InstalName,CheckPath,CheckName,
    AccName         :String;
    VirFile         :File;
    PrgID           :ProgramID;
    Message         :MessageBuffer;

(* Initialisierung des Programms *)
PROCEDURE InitVirusEx () : BOOLEAN;

VAR success,AccOK;BOOLEAN;

BEGIN
    InitGem(RC,dev,success);        (* Initialisierung*)
    IF ~success THEN 
        RETURN FALSE 
    END;
    LoadResource('VIRUS_EX.RSC');   (* RSC-File laden*) 
    IF GemError() THEN 
        FormAlert(1,NoResource,VoidC);
        RETURN FALSE
    END;
    UserBox :=ResourceAddr(treeRsrc,Userdial);          (* RSC-File auswerten*)
    VirusFoundAlert :=ResourceAddr(textstring,Virus); 
    MissingProgAlert:=ResourceAddr(textstring,Missprg);
    BadDriveAlert   :=ResourceAddr(textstring,Baddrive);
    DiskErrorAlert  :=ResourceAddr(textstring,Diskerr); 
    DriveCount      :=0; (* Zähler auf 0 *)
    PositionMiss    :=Pos('%prg',MissingProgAlert^,0);  (* Position für     *) 
    PositionVirF    :=Pos('%prg',VirusFoundAlert^,0);   (* variablen Namen  *) 
    Position        :=Pos('%nnn',DiskErrorAlert^,0);
    AccName         :='  Virus Ex';                     (* Accessory        *)
    RegisterAcc(ADR(AccName),VoidC,AccOK);
    IF ~AccOK THEN 
        RETURN FALSE 
    END;
    InstalName:='';                                     (* Texte für        *)
    InstalPath:=DriveToStr(DefaultDrive());             (* File-Selectoren  *) 
    Append('\*.VIR',InstalPath,success);
    CheckName :='';
    CheckPath :=InstalPath;
    RETURN TRUE                                         (* Alles OK!        *)
END InitVirusEx;

(* Ausgabe TOS-Fehlermeldung *)
PROCEDURE DiskError (errCode:INTEGER);

VAR ErrNumber:String;
    i        :CARDINAL;

BEGIN
    IF errCode#0 THEN       (* Fehler aufgetreten *)
        ConvInt(errCode,4,ErrNumber); (* Zahl->String*)
        FOR i:=Position TO Position+3 DO (* Zahl in Alertstring *) 
            DiskErrorAlert^[i]:=ErrNumber[i-Position]
        END;
        FormAlert(1,DiskErrorAlert^,VoidC)  (* Ausgabe Alertbox *)
    END
END DiskError;

(* Ausgabe, wenn Programm fehlt *)

PROCEDURE MissProgError (errName:ARRAY OF CHAR);

VAR i           :CARDINAL;
    LokalName   :String; 
    success     :BOOLEAN;

BEGIN
    Assign(errName,LokalName,success);
    Append(Leer,LokalName,success);
    FOR i:=PositionMiss TO PositionMiss+11 DO 
        MissingProgAlert^[i]:=LokalName[i-PositionMiss]     (* Name einsetzen *)
    END;
    FormAlert(1,MissingProgAlert^,VoidC)    (* Ausgabe Alertbox *)
END MissProgError;

(* Ausgabe, wenn Filegrößen unterschiedlich (Merkmal für Virus) *) 
PROCEDURE VirusError (errName:ARRAY OF CHAR) : BOOLEAN;

VAR i           :CARDINAL;
    LokalName   :String; 
    success     :BOOLEAN;

BEGIN
    Assign(errName,LokalName,success);
    Append(Leer,LokalName,success);
    FOR i:=PositionVirF TO PositionVirF+11 DO 
        VirusFoundAlert^[i]:=LokalName[i-PositionVirF] (* Name einsetzen *)
    END;
    FormAlert(1,VirusFoundAlert^,VoidC);    (* Ausgabe Alertbox *)
    RETURN VoidC=2      (* TRUE=Programm löschen *)
END VirusError;

                (* Fehlerstatus ermitteln *) 
PROCEDURE errState (f:File;VAR IOResult:INTEGER) : BOOLEAN;

BEGIN 
    IOResult:=State(f);
    IF IOResult<0 THEN  (* Fehler aufgetreten? *) 
        ResetState(f);  (* Status zurücksetzen *)
        RETURN TRUE 
    END;
    RETURN FALSE 
END errState;

(* Feststellen, ob Laufwerk N (A=0,B=1,...) angemeldet ist *)
PROCEDURE DriveOnline (N:CARDINAL) : BOOLEAN;

VAR DRV         :Drive;
    DriveString :DriveStr;
    DRVSet      :DriveSet;

BEGIN
    DriveString     :='A:';
    DriveString[0]  :=CHR(ORD('A')+N);
    DRV             :=StrToDrive(DriveString);
    DRVSet          :=DrivesOnline();   (* Angemeldete Laufwerke ermitteln *)
    RETURN DRV IN DRVSet                (* TRUE=Laufwerk angemeldet *)
END DriveOnline;

FORWARD WritePrgFileSub (name : ARRAY OF CHAR;VAR IOresult:INTEGER);

(* Programmdaten in File schreiben oder Unterverzeichnis untersuchen *)
PROCEDURE WriteProgramName (path:ARRAY OF CHAR;entry:DirEntry) : BOOLEAN;

VAR LokalName,NAME,EXTENSION:String;
    Acc,Prg,Tos,Ttp         :ARRAY [0..3] OF CHAR
    result                  :INTEGER;
    success                 :BOOLEAN;

BEGIN
    Assign(path,LokalName,success);
    IF subdirAttr IN entry.attr THEN (* falls Subdirectory *)
        IF entry.name[0]#'.' THEN 
            Append(entry.name,LokalName,success); 
            WritePrgFileSub(LokalName,result); (* Subdirectory untersuchen *)
        END
    ELSE (* falls normale Datei *)
        SplitName(entry.name,NAME,EXTENSION);
        Acc:='ACC';
        Prg:='PRG';
        Tos:='TOS';
        Ttp:='TTP';
        IF StrEqual(EXTENSION,Acc) OR StrEqual (EXTENSION,Prg) OR 
           StrEqual(EXTENSION,Tos) OR StrEqual (EXTENSION,Ttp) THEN 
           Assign(path,PrgID.Path,success);
            Assign(entry.name,PrgID.Name,success);
            PrgID.Numb:=entry.size;
            WriteBytes(VirFile,ADR(PrgID),SIZE(PrgID)) (* speichern wenn Extension OK *)
        END
    END;
    RETURN TRUE 
END WriteProgramName;

(* untersucht alle Files mit Pfadname *)
PROCEDURE WritePrgFileSub (name:ARRAY OF CHAR;VAR IOresult:INTEGER);

VAR LokalName:String; 
    success  :BOOLEAN;

BEGIN
    Assign(name,LokalName,success);
    Append('\*.*',LokalName,success);
    DirQuery(LokalName,FileAttrSet{subdirAttr),WriteProgramName,IOresult)
END WritePrgFileSub;

(* erstellt File mit Programmdaten *)
PROCEDURE WritePrgFile (name:ARRAY OF CHAR;N:CARDINAL;VAR IOresult:INTEGER);

VAR DRV         :Drive;
    DriveString :DriveStr;
    SearchName  :String; 
    success     :BOOLEAN;

BEGIN
    Create(VirFile,name,writeOnly,replaceOld); 
    DriveString :='A:';
    DriveString[0]:=CHR(ORD('A')+N);
    WritePrgFileSub(DriveString,IOresult);
    Close(VirFile)
END WritePrgFile;

(* Programmfile auswerten *)
PROCEDURE ReadPrgFile (name:ARRAY OF CHAR;N:CARDINAL;VAR IOresult:INTEGER);

VAR Cnt     :LONGCARD;
    PrgFile :File;
    IOres   :INTEGER;
    PrgName :String; 
    success :BOOLEAN;

BEGIN
    Open(VirFile,name,readonly);        (* Datei mit Prog.daten *)
    IF errState(VirFile,IOresult) THEN 
        Close(VirFile)
    ELSE
        LOOP
            ReadBytes(VirFile,ADR(PrgID),SIZE(PrgID),Cnt);  (* Daten lesen *)
            IF Cnt=0L THEN 
                EXIT 
            END;
            Assign(PrgID.Path,PrgName,success);
            Append(PrgID.Name,PrgName,success);
            PrgName[0]:=CHR(ORD('A')+N);
            Open(PrgFile,PrgName,readonly);             (* Daten auswerten *)
            IF errState(PrgFile,IOres) THEN 
                Close(PrgFile);
                IF IOres=-33 THEN   (* Programm fehlt *) 
                    MissProgError(PrgID.Name)
                ELSE 
                    DiskError(IOres)
                END
            ELSE
                IF FileSize(PrgFile)#PrgID.Numb THEN (* Filegrößen unterschiedlich, Virus? *)
                    IF VirusError(PrgID.Name) THEN 
                        Delete(PrgName,IOres);       (* Programm löschen *)
                        DiskError(IOres)
                    END
                END;
                Close(PrgFile)
            END
        END;
        Close(VirFile)
    END
END ReadPrgFile;

(* vergleicht Programmdaten mit abgespeicherten Werten bzw. *)
(* steuert Abspeicherung der Programmdaten von Laufwerk Number in Datei P *)
PROCEDURE Do (ReadWriteProcedure:RWProc;
    VAR Path,Name:ARRAY OF CHAR; Number:CARDINAL);

VAR result          :INTEGER;
    P,VoidStr       :String;
    OKButn,success  :BOOLEAN;

BEGIN
    IF DriveOnline(Number) THEN         (* Laufwerk angemeldet *)
        SelectFile(Path,Name,OKButn);   (* File-Selector *)
        IF OKButn AND ~Empty(Name) THEN 
            GrafMouse(bee,NIL);         (* Biene darstellen *)
            SplitPath(Path,P,VoidStr);  (* Namen zusammensuchen *)
            Append(Name,P,success);
            ReadWriteProcedure(P,Number,result); (* Datei schreiben bzw. auswerten *)
            GrafMouse(arrow,NIL);       (* wieder Mauspfeil *)
            DiskError(result)
        END
    ELSE
        FormAlert(1,BadDriveAlert^,VoidC)
    END 
END Do;

        (* Dialog mit dem User durchführen *)
PROCEDURE DoDialog;

VAR but     :CARDINAL; 
    state   :OStateSet; 
    space   :Rectangle;

BEGIN 
    UpdateWindow(TRUE);
    GrafMouse(arrow,NIL);   (* Mauszeiger als Pfeil *)
    LOOP
        space:=FormCenter(UserBox);
        FormDial(reserveForm,Rect(0,0,5,5),space); 
        FormDial(growForm,Rect(0,0,5,5),space);
        DrawObject(UserBox,Root,MaxDepth,space); (* Dialogbox ausgeben *)
        LOOP
            FormDo(UserBox,Root,but);            (* Dialog durchführen *) 
            state:=ObjectState(but);
            EXCL(state,selectObj);
            ChangeObjState(UserBox,but, (* selectObj zurück *)
                           TransRect(ObjectSpace(but),ObjectOffset(UserBox,but)), state,TRUE);
            CASE but OF 
                Dec : IF DriveCount=0 THEN (* "<<" angeklickt *)
                        DriveCount:=MaximalDrive 
                      ELSE 
                        DEC(DriveCount)
                      END
                Inc : IF DriveCount=MaximalDrive THEN (* ">>" angeklickt *)
                        DriveCount:=0 
                      ELSE 
                        INC(DriveCount)
                      END
            END;
            IF (but=Dec) OR (but=Inc) THEN 
                SetCurrObjTree(UserBox,FALSE); 
                AssignTextStrings(Cdrive,setOnly,CHR(ORD('A')+DriveCount),noChange,'', noChange,'');
                DrawObject(UserBox,Cdrive,MaxDepth,FormCenter(UserBox)) (* Laufwerk neu *)
            ELSE
                EXIT
            END
        END;
        FormDial(freeForm,Rect(0,0,5,5),space);
        FormDial(shrinkForm,Rect(0,0,5,5),space);
        CASE but OF 
            Instal : Do(WritePrgFile,InstalPath,InstalName,DriveCount)|
                (* "aufnehmen"-Button / = DoDriveInstal *) 
            Check  : Do(ReadPrgFile, CheckPath, CheckName, DriveCount)|
                (* "überprüfen"-Button / = DoDriveCheck *) 
            Abbruch: EXIT (* "Abbruch"-Button *)
        END
    END;
    UpdateWindow(FALSE)
END DoDialog;

BEGIN
    IF InitVirusEx() THEN 
        REPEAT (* Endlosschleife *)
            MessageEvent(Message);
            IF Message.msgType=accOpen THEN 
                DoDialog (* unser Accessory wurde ausgewählt! *)
            END 
        UNTIL FALSE 
    ELSE
        FormAlert(1,NoInstal,VoidC);
        REPEAT                  (* auch 'ne Endlosschleife, damit VIRUS_EX nicht *) 
            TimerEvent(10000L)  (* abstürzt, wenn mal das Resourcefile fehlt.*)
        UNTIL FALSE 
    END 
END VirusEx.
(* Ende *)

VIRUS EX

' GfA-Basic-Programm zur Anzeige der Programm-
' namen, die mit VIRUS EX abgespeichert wurden.
' (c) D. Rabich, Dülmen
' 20. Juni 1988
CLS
path$="\*.VIR" 
name$=""
DO
    FILESELECT path$,name$,ret$ ! File-Selector zur Auswahl
    EXIT IF ret$="" page_count=0
    i=LEN(ret$) ! Pfad für nächsten Aufruf retten 
    REPEAT
        IF MID$(ret$,i,1)="\" 
            path$=LEFT$(ret$, i)
        ENDIF 
        DEC i
    UNTIL MID$(ret$,i+1,1)="\" OR i<l1
    CLS
    OPEN "I",#1,ret$ ! Datei öffnen
    WHILE NOT (EOF(#1))
        p$=INPUT$(64,#1) ! Pfad lesen
        pos_end=INSTR(p$,CHR$(0))
        IF pos_end>0 THEN
            p$=LEFT$(p$,pos_end-1)
        ENDIF
        n$=INPUT$(12,#1) ! Name lesen
        pos_end=INSTR(n$,CHR$(0))
        IF pos_end>0 THEN
            n$=LEFT$(n$,pos_end-1)
        ENDIF
        l=CVL(INPUT$(4,#1)) ! Programmlänge lesen
        PRINT LEFT$(p$+n$+SPACE$(70),70);l ! Ausgabe 
        INC page_count
        IF page_count=23 THEN ! ggf. auf Tastendruck warten
            PRINT "- mehr -"
            REPEAT
                antw$=INKEY$
            UNTIL antw$<>"" 
            page_count=0 
        ENDIF 
    WEND
    CLOSE #1
    PRINT "- Ende —"            ! auf Tastendruck warten
    REPEAT
        antw$=INKEY$
    UNTIL antw$<>""
LOOP
END                                         ! Ende !

GFA-BASIC-Programm zur Anzeige der Programmnamen


Dietmar Rabich
Aus: ST-Computer 04 / 1989, Seite 81

Links

Copyright-Bestimmungen: siehe Über diese Seite