Systemsteuerung mittels QBASIC


Mittlerweile sind wir in der Lage, mittels Zusammenfügen einiger Bausteine, die wir gelernt haben, doch einiges zu bewerkstelligen. In diesem Kapitel wollen wir das anhand ein paar Systemsteuerungsaufgaben für Windows XP (!) mal ankosten. Die Bausteine, die wir benutzen werden, sind:

Von diesen vier Bausteinen fehlt uns nur noch der letzte:

Der SHELL-Befehl

Dieser ist ganz einfach. Mittels SHELL "Befehl" können Sie ein beliebiges DOS-Kommando abschicken. Also z.B. SHELL "copy A:\*.* C:\temp" würde aus QBASIC heraus alle Dateien des Diskettenlaufwerks nach C:\temp kopieren. Sogar das Ausführen von Batch-Dateien klappt so: QBASIC "back.bat" führt das Batchskript back.bat aus. Und jetzt machen Sie mal was ganz Lustiges: Starten Sie mal folgendes Programm:

SHELL "qbasic"

Was passiert? Scheinbar nichts. Ausser, dass der Eingangsbildschirm, bei dem man die ESC-Taste drücken muss, wieder erscheint. Und dann das Programm verschwunden ist. Das ist auch kein Wunder - wir haben aus dem alten QBASIC heraus ein neues QBASIC gestartet! Beenden wir es über Datei->Beenden, dann kommt zuerst der DOS- Bildschirm wieder mit der Aufforderung, eine Taste zu drücken. Und dann kommt wieder unser alter QBASIC-Schirm mit Programm.

Aufgabe 1: Windowsverzeichnis ermitteln

Nehmen wir an, wir wollen ein Programm schreiben, das ein anderes Programm so installiert, dass es als DOS-Befehl aus jedem Verzeichnis aufgerufen werden kann. Das zu installierende Programm liege als Binary vor, also als Befehl der Form "myprog.exe".

In jedem Windowssystem gibt es ein Verzeichnis, das von vornherein im Pfad der Kommandozeile steht und somit nach Befehlen durchsucht wird, wenn man auf der Kommandozeile einen Namen eingibt: Das Windowsverzeichnis selbst. Nichts einfacher also, als unser myprog.exe ins Windowsverzeichnis zu kopieren (wenn das auch nicht feine englische Art eines Installationsprogramms ist - aber es funktioniert.)

Unser Installationsprogramm soll auf jeder Windowsversion bis zur neuesten laufen. Nun sind die Windowsverzeichnisse aber alles andere als einheitlich. Schon deshalb, weil das Systemlaufwerk nicht immer C: sein muss. Was tun? Wie finden wir heraus, wo das Windows-Verzeichnis ist? Das klingt jetzt schon ganz schön kompliziert.

Ist aber nicht so schwer. Als erstes müssen wir wissen, dass es ein Windows/DOS-Kommando namens SET gibt. Öffnen Sie mal eine Konsole und geben Sie SET+enter ein. Wenn ich das hier auf meiner Maschine eingebe, dann kommt folgendes:

COMSPEC=C:\WINNT\SYSTEM32\COMMAND.COM
COMPUTERNAME=SCHATZ
EDPATH=C:\progra~1\WATCOM\EDDAT
HOMEDRIVE=C:
HOMEPATH=\
INCLUDE=C:\progra~1\WATCOM\H;C:\progra~1\WATCOM\H\NT
LOGONSERVER=\\SCHATZ
MXBIN=D:\Programme\FireDaemon
MXHOME=D:\Programme\FireDaemon
NTRESKIT=D:\Programme\reskit1
NUMBER_OF_PROCESSORS=1
OS=Windows_NT
OS2LIBPATH=C:\WINNT\system32\os2\dll;
PATH=C:\winnt;C:\winnt\system32;C:\PROGRA~1\dosprog\tc\bin;C:\progra~1\dosprog\d
os6
PATHEXT=.COM;.EXE;.BAT;.CMD
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_IDENTIFIER=x86 Family 6 Model 7 Stepping 3, GenuineIntel
PROCESSOR_LEVEL=6
PROCESSOR_REVISION=0703
PROMPT=$P$G
SYSTEMDRIVE=C:
SYSTEMROOT=C:\WINNT
TEMP=C:\TEMP
TMP=C:\TEMP
USERDOMAIN=SCHATZ
USERNAME=schatz
USERPROFILE=C:\WINNT\Profiles\schatz
WATCOM=C:\progra~1\WATCOM
WWINHELP=F:\BINW

Damit wissen Sie schon ziemlich viel über mich und meinen PC - sogar meinen Nachnamen. Sie wissen zumindest, dass ich auf einer ollen NT-Maschine mit einer ziemlich schlaffen CPU arbeite (PROCESSOR_IDENTIFIER). Was sehen wir hier? Wir sehen die voreingestellten Systemvariablen. Genau. Das sind Betriebssystem- variablen, die man abfragen und auch neu setzen kann. Die meisten davon sind Strings. Und eine davon enthält das Windows-Verzeichnis: SYSTEMROOT. Bingo.

Die nächste Aufgabe ist es, den Wert für SYSTEMROOT in unser Programm zu bekommen. Nun, wir haben im Kapitel Feine DOS-Fähigkeiten im Abschnitt "Umleitungen und Pipes" gelernt, dass man die Ausgabe eines DOS-Befehls in eine Datei umleiten kann. Geben wir also in unserem QBASIC-Verzeichnis "SET > set.txt" an, so leiten wir die Liste, was wir gerade noch auf dem Bildschirm gesehen haben, in die Datei set.txt um.

So, die nächste Aufgabe besteht nun darin, den Wert einer bestimmten Systemvariablen aus set.txt auszulesen. Das ist die Sache mit dem Dateien lesen. Hier muss man ein bisschen clever vorgehen, nämlich das Übungsergebnis aus dem vorigen Kapitel benutzen, bei dem es darum ging, eine search-Routine für Textdateien zu schreiben. Die die Textdatei nach einem bestimmten Schlüsselwort durchkämmt. Genau so etwas brauchen wir jetzt. Wenn Sie also die Übung noch nicht gemacht haben, dann schreiben Sie jetzt Ihre Routine "searchtextfile"! Ergebnis der Routine soll ein String mit der Zeile sein, in der das Schlüsselwort zum ersten Mal vorkommt. Kommt es in der Datei nicht vor, soll der String leer sein. Die Suche soll Gross- und Kleinschreibung nicht beachten.

Meine Lösung dafür sieht so aus:

'---------------------------------------------------------
'Lookstring:
'Routine fuer das Suchen eines Strings in einer Textdatei
'---------------------------------------------------------

'Sucht in #1
'#1 muss geoeffnet sein
'Suchstring: such$
'Rueckgabewert 1: rueck$
'Rueckgabewert 2: suchpos
'Enthaelt die Zeile mit dem Suchstring

'by C. Schatz 2003, Programmiertutorial

GOTO main



lookstring:

found = 0
WHILE (NOT EOF(1) AND found = 0)
  LINE INPUT #1, a$
  suchpos = INSTR(LCASE$(a$), LCASE$(such$))
  IF (suchpos > 0) THEN found = 1
WEND
IF (found = 0) THEN rueck$ = "": suchpos = 0 ELSE rueck$ = a$
RETURN

'Test
'---------
main:
SHELL "set > set.txt"
OPEN "set.txt" FOR INPUT AS #1
such$ = "systemroot"
GOSUB lookstring
CLOSE #1
PRINT rueck$
PRINT suchpos

Schauen wir uns diese Lösung einmal an. Was fällt Ihnen auf?

So. Das Hauptprogramm zeigt schon, wie wir nun ganz elegant an die Systemvariablen rankommt, auch z.B. an das temporäre Verzeichnis des Rechners. Wir müssen nun nur noch aus der richtigen Zeile des Variablenwert extrahieren. Das ist ziemlich einfach. Wir ermitteln mit INSTR() die Position des Gleichheitszeichens und nehmen dann den String ab einem Zeichen hinter dieser Position:

winpath$=MID$(rueck$,INSTR(rueck$,"=")+1,len(rueck$))

Die Zeile ist allerdings ein bisschen unübersichtlich. "Sprechender" wäre es, sie in mehrere Zeilen aufzuteilen:

posstart=INSTR(rueck$,"=")+1
IF (posstart=1) THEN STOP 'Hups! Kein Gleichheitszeichen!
posend=LEN(rueck$)
winpath$=MID$(rueck$,posstart,posend)

Das ganze Programm: Kopieren eines Files ins Windowsverzeichnis

Der Rest ist nun einfach. Nehmen wir an, wir wollen das File von Diskette ins Windowsverzeichnis kopieren. Dann bilden wir den ganzen DOS-Befehl als String: cmd$="copy A:\"+fname$+" "+winpath$
und übergeben ihn der SHELL: SHELL(cmd$). fname$ enthält den Filenamen, z.B. "myprog.exe". Und das war's dann.

Was haben wir gelernt?

Übung:

  1. Schreiben Sie ein Programm (einfache Version), das alle Dateien mit der Endung .txt oder .bas in einem beliebig zu wählenden Verzeichnis durchsucht und darin alle DOS-Umlaute in Windows-Umlaute umsetzt - oder umgekehrt. "Einfache Version" heisst: Nur für Ihre Windows-Version. Um zu wissen, welchen Code in DOS- und Windows-Programme jeweils haben, müssen Sie erstmal zwei Auswertungen machen: Einfach jeweils mit einem Windows- und einem DOS-Editor die Umlaute schreiben, abspeichern, mit QBASIC einlesen und mit der ASC()-Funktion schauen, welche Codes sich dahinter verbergen. Das Ergebnis ist dann die "Übersetzungstabelle".
  2. Erweitern Sie das Programm so, dass es auch in den Unterverzeichnissen des angegeben Verzeichnissen die Umwandlung vornimmt!
  3. Erweitern Sie die Version so, dass es zuerst die Windowsversion ermittelt und dann die verschiedenen dir-Ausgabeformate der Windowsversionen berücksichtigt.