4. Standard-Probleme (Teil 1)
4.1. Kompatibilität der PBU's & LIB's zwischen den 3'er Versionen
4.2. Zu wenig Speicherplatz innerhalb der PowerBASIC-IDE
4.3. Ermitteln des eigenen Dateinamens und dem Pfad zum Dateinamen
4.4. Kein Speicherplatz verfügbar bei ENVIRON$
4.5. Keine Errorcode-Zurückgabe bei SHELL
4.6. Kürzen von Files
4.7. Fehler 502/514 bei Verwendung von C-OBJ-Files
4.8. Warmboot über STRG-ALT-ENTF verhindern
4.9. Öffnen von mehr als 15 Files mit PowerBASIC und/oder mit DOS
4.10. HEX$-DWORD Routine für PowerBASIC 3.1/3.2
4.1. Kompatibilität der PBU's & LIB's zwischen den 3'er Versionen
Im Gegensatz zum PowerBASIC-Update von der V2.10 auf die V3.00 sind
die PBU/LIB's der PowerBASIC 3'er Versionen untereinander abwärtkompatibel. Das
heißt, sie können eine mit PowerBASIC 3.0 erstellte PBU/LIB unter
den beiden höheren PowerBASIC Versionen weiterverwenden. Eine mit
PowerBASIC 3.1 erstellte PBU/LIB können Sie dagegen allerdings nicht
mehr in der älteren Version nutzen.
Zwischen den Versionen 3.0-3.1 gibt es aber Aufgrund des erweiterten
Zahlensystems eventuell Unterschiede beim Austausch von Sourcen
untereinander. In diesem Fall lesen Sie sich bitte auch den Abschnitt
'Fehler ...' durch.
4.2. Zu wenig Speicherplatz innerhalb der PowerBASIC-IDE
Für das 'ständig vorhandene' Speicherplatzproblem innerhalb der
integrierten Entwicklungsumgebung wurde von Bob Zale selbst ein
Tool entwickelt, welches die Bereiche des VGA-Grafik-RAM's, sowie
den Bereich der monochromen Herculeskarte für PowerBASIC erschliesst.
Obwohl das Tool 'PBPLUS96' (96kByte mehr RAM) für die PowerBASIC
Version 2.00 entwickelt wurde, funktioniert es ebenso unter
PowerBASIC Version 3.10.
4.3. Ermitteln des eigenen Dateinamens und dem Pfad zum Dateinamen
Oft stehen Sie vor dem Problem das Sie zwar Ihr Programm über einen
Pfad-Befehl aufrufen können, dieses dann aber die eigenen Daten und
INI-Files nicht mehr findet. Die Lösung ist recht einfach: DOS
speichert diese Informationen im PSP bzw. im zum PSP gehörigen
Environmentblock.
'*********************************************************************
'
' Pfad und Dateiname des aktuellen Programm ermitteln in
' PowerBASIC 3.0/3.2
'
' von Thomas Gohel
'
'*********************************************************************
$COMPILE EXE
! mov ax, &h6200
! int &h21
! mov es, bx
! mov ax, word ptr es:[&h2C]
! mov pbvDefSeg, ax ; undokumentiert in PowerBASIC 3.0
FOR i% = 0 TO 1024
IF PEEK$(i%, 4) = CHR$(0,0,1,0) THEN EXIT FOR
NEXT i%
WHILE PEEK(i% + 4) <> 0
Temp$ = Temp$ + CHR$(PEEK(i% + 4))
i% = i% + 1
WEND
DEF SEG
FOR i%=LEN(Temp$) TO 1 STEP -1
IF RIGHT$(MID$(Temp$,1,i%),1) = "\" THEN EXIT FOR
NEXT i%
ExeDir$ = MID$(Temp$,1,i%)
ExeName$ = MID$(Temp$,i%+1)
PRINT ExeDir$; " "; ExeName$
4.4. Kein Speicherplatz verfügbar bei ENVIRON$
Dieser Absatz ist zwar teilweise im Handbuch beschrieben, doch
möchte ich einige weiterführende Tips geben, da dieses Thema
immer wieder zu Missverständnissen führt. Der Aufbau des
Environmentblockes in Verbindung mit dem Programm Segment Prefix
wird nicht weiter beschrieben, ist allerdings von enormer Bedeutung
zum besseren Verständnis dieses Fehlers.
Zusammenfassend sei gesagt, das Sie nur das vorhandene Environment
modifizieren und nicht durch neue Einträge erweitern können!!
Wollen Sie nun trotzdem Einträge hinzufügen, so können Sie 3 Wege
beschreiten:
a) Teile des Environment löschen und dann den neuen Eintrag
hinzufügen oder bereits vorher einen Dummy-Environmenteintrag anlegen
und diesen dann per ENVlRON-Befehl löschen bzw. modifizieren.
b) Wenn Sie z.B. eine DOS-SHELL mit einer Information starten
wollen:
OldEnv$ = ENVIRON$("PROMPT")
SHELL "COMMAND.COM /K SET PROMPT=PowerBASIC " + OldEnv$
Der Trick hierbei ist, das bei einer SHELL automatisch ein neuer
PSP erstellt wird und somit auch der Speicher passend angefordert
wird.
c) Die Adresse des PSP ermitteln, dann den Zeiger auf den aktuellen
Environmentblock holen und jetzt das Environment komplett in
einen String packen wo es modifiziert werden kann. Abschliessend
einen passenden DOS-Speicherblock per INT21 anfordern, das
modifizierte Environment dorthin kopieren und den Zeiger zum
Environmentblock innerhalb des Programm Segment Prefix anpassen.
(siehe auch: bereits vorhandene PD-Lösungen)
4.5. Keine Errorcode-Zurückgabe bei SHELL
Vielfach ist es erforderlich, wenn nach einem SHELL-Aufruf der
Errorcode des beendeten Programms abgefragt werden kann. Dies ist
in PowerBASIC nicht direkt möglich, da PowerBASIC das Programm immer
über COMMAND.COM ausführt und deshalb der Errorcode nicht zurück-
geben werden kann (dies ist eine Eigenart von MS-DOS!!).
Bespiel:
SHELL "C:\DOS\COMMAND.COM /C MEINDEMO.EXE"
Für die Lösung dieses Problems gibt es zum einen einen alternativen
SHELL-Befehl in Form einer FUNCTION (also Sourcecode):
'**********************************************************************
'
' Errorlevel in PowerBASIC 3.0/3.2
'
' von Thomas Gohel (nach einer Vorlage aus PDS, von Bernd Hohmann)
'
'**********************************************************************
$COMPILE EXE
DECLARE FUNCTION PBShell% (FileName$)
CLS
PRINT
PRINT "Fehlercode ist: "; PBShell%("c:\dos\command.com")
END
FUNCTION PBShell% (FileName$)
LOCAL Dummy%
Datei$ = FileName$ ' Dateiname umkopieren.
Datei$ = LTRIM$(Datei$) ' Filename trimmen.
i% = INSTR(Datei$, " ") ' Kommando übergeben ?
IF i% > 0 THEN '
Cmd$ = MID$(Datei$, i%) ' Kommando abtrennen
Datei$ = LEFT$(Datei$, i% - 1) ' Filename abtrennen
END IF '
Datei$ = UCASE$(Datei$)
i% = INSTR(Datei$, ".") ' Ist ein Punkt drin ?
IF i% > 0 THEN '
Ext$ = MID$(Datei$, i%) ' Extension holen.
ELSE '
Ext$ = "" ' Extension ist leer.
END IF '
SELECT CASE Ext$ ' Extensions abtesten.
CASE ".BAT" ' Batch über COMMAND.COM
' ausführen.
Cmd$ = "/C " + Datei$ + " " + Cmd$
Datei$ = ENVIRON$("COMSPEC")
CASE ".COM" ' Frei
CASE ".EXE" ' Frei
CASE ELSE ' Keine Extension,
Datei$ = Datei$ + ".EXE" ' .EXE anhängen.
END SELECT '
Datei$ = Datei$ + CHR$(0) ' ASCIIZ-String erzeugen.
dNul$ = CHR$(0) + CHR$(0) ' Doppelnull für Parameter-Block
nul$ = SPACE$(127) ' 127 bytes für Strings retten.
MemFree& = SETMEM(0) ' Freien Speicherplatz holen.
x& = SETMEM(-MemFree&) ' Speicherplatz komplett
' freigeben.
nul$ = "" ' 127 bytes wieder freigeben.
IF Cmd$ > "" THEN ' Kommandozeile ?
CmdLen$ = CHR$(LEN(Cmd$)) ' Länge des Cmd$ als String
Cmd$ = CmdLen$ + Cmd$ + CHR$(13) ' Länge + Cmd$ + '13'
segm$ = MKI$(STRSEG(Cmd$)) ' Einzeln die Teile des
' Parameter-Blocks
Offs$ = MKI$(STRPTR(Cmd$)) ' erzeugen ( MID$(....)
' = segm$ geht nicht. )
Param$ = dNul$ + Offs$ + segm$ ' Parameterblock machen.
ELSE '
Cmd$ = CHR$(13) ' Start of Bug-Fixed
segm$ = MKI$(STRSEG(Cmd$)) ' Segment des Terminator (Dummy)
Offs$ = MKI$(STRPTR(Cmd$)) ' Offset -"-
Param$ = dNul$ + Offs$ + segm$ ' Parameterblock machen.
END IF ' End of Bugfixed
DateiSeg% = STRSEG(Datei$) ' Adressen holen
DateiOff% = STRPTR(Datei$)
ParamSeg% = STRSEG(Param$)
ParamOff% = STRPTR(Param$)
! push ds ; DS sichern
! mov ax, &h4B00 ; EXEC-Funktion 4Bh / INT 21h
! mov es, ParamSeg% ; Segment des Parameterblocks
! mov bx, ParamOff% ; Offset des Parameterblocks
! mov dx, DateiOff% ; Offset des Dateinamens
! mov ds, DateiSeg% ; Segment des Dateinamens
! int &h21 ; Interrupt &h21
! pop ds
! jc ExecError
! jmp ExecOk
ExecError:
! mov Dummy%, ax
SELECT CASE Dummy% ' Fehler auswerten.
CASE 1 : PRINT "illegaler Funktionsaufruf!"
CASE 2,3 : PRINT "Datei nicht gefunden: " + FileName$
CASE 4 : PRINT "zu viele Dateien geöffnet"
CASE 5 : PRINT "Zugriff verweigert " + Filename$
CASE 8 : PRINT "Zuwenig freier Speicher für " + FileName$
CASE 10 : PRINT "falscher Environmentblock"
CASE 11 : PRINT "falsches Format"
CASE ELSE: PRINT "Problem meim Ausführen von " + FileName$
END SELECT
ExecOk:
Mem2& = SETMEM(MemFree&) ' Speicher komplett freigeben.
IF MemFree& <> Mem2& THEN ' Speicher stimmt nicht mehr ??
PRINT "Achtung: vermutlich wurde ein TSR installiert!!"
END IF
! mov ah, &h4d ; Exit-Code ermitteln
! int &h21 ; Interrupt &h21
! mov Dummy%, al
PBShell% = Dummy%
! mov ah, &h03 ; Aktuelle Cursorposition
! mov bh, &h00 ; übergeben
! int &h10 ; Interrupt &h10
! inc dh ; Umrechnen auf Basis 1
! inc dl
! mov NewZeile?, dh
! mov NewSpalte?, dl
LOCATE NewZeile?, NewSpalte? ' Cursor setzen
END FUNCTION
Des weiteren können Sie die COMSPEC-Variable in Ihrem Environment
modifizieren und Ihr Programm ohne Umwege über COMMAND.COM direkt
ausführen.
Beispiel:
Comspec$ = ENVIRON$("COMSPEC") 'Sichern von COMSPEC
ENVIRON "COMSPEC=MEINDEMO.EXE"
SHELL 'Ausführen von MEINDEMO.EXE
ENVIRON "COMSPEC="+Comspec$ 'Restaurieren von COMSPEC
Beachten Sie allerdings, das die SHELL-Funktion immer automatisch
den Parameter '/C' dem ausführendem Programm übergibt, sofern Sie
zum Beispiel Kommandozeilenparameter übergeben wollen.
4.6. Kürzen von Files
Oft stehen Sie vor dem Problem das Sie Ihr Datenfile aufgeräumt haben,
dieses aber immer noch viel zu groß ist. In diesem Fall hilft wie so
oft ein kleiner aber effektiver Kniff:
Beispiel:
OPEN "DEMO.DAT" FOR BINARY AS #1
SEEK #1, 20
PUT$ #1, ""
CLOSE #1
Verkürzt die Datei 'DEMO.DAT' auf 20Bytes Länge.
Standard-Probleme (Teil 2)