4. Standard-Probleme (Teil 1)

English


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)


(c) 1995/2007 Thomas Gohel, All rights and bug's reserved