4. Standardproblems (Part 1)


4.1. Compatability between the PBUs and LIBs of the 3.x Versions
4.2. Not enough memory in the PowerBASIC-IDE
4.3. Finding out the filename and path to the filename
4.4. No free memory with ENVIRON$
4.5. No Returnerrorlevel with SHELL
4.6. Cutting files
4.7. Error 502/514 when using C-OBJ-Files
4.8. Preventing a Warmboot with CTRL-ALT-DEL
4.9. Opening more than 15 Files with PowerBASIC and/or DOS
4.10. HEX$-DWORD Routine for PowerBASIC 3.1/3.2

4.1. Compatability between the PBUs and LIBs of the 3.x Versions

Other than the PowerBASIC-Update from V2.10 to 3.00, the PBU/LIBs of the 3.x Versions are downwards compatible. That means that you can continue to use an under PowerBASIC 3.0 developed PBU/LIB under the two higher PowerBASIC Versions.
But you can't use a PowerBASIC 3.1 PBU/LIB with any of the older Versions. There are probably some differences between the Versions 3.0-3.1 because of the new Number-System when exchanging sourcecode. In that case please read the Chapter 'Errors ...'.

4.2. Not enough memory in the PowerBASIC-IDE

There is a Tool by Bob Zale himself which activates parts of the VGA- Graphic-RAM and the parts of the monochrome Herculescard for PowerBASIC. The Tool 'PBPLUS96' (96kByte more RAM) was written for PowerBASIC Version 2.00, but still works with Version 3.10.

4.3. Finding out the filename and the path to the filename

We often stand in front of the problem that we can start our program over a path command, but that it can't find its own data and INI-Files anymore after that. The solution is quite simple: DOS saves this information in the PSP or in its Environmentblock.
    '   Finding the path and filename of the current program in
    '   PowerBASIC 3.0/3.2
    '   von Thomas Gohel


        ! mov ax, &h6200
        ! int &h21
        ! mov es, bx
        ! mov ax, word ptr es:[&h2C]
        ! mov pbvDefSeg, ax           ; undocumented 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
        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. No free memory with ENVIRON$

This chapter is partly documented in the manuals, but I want to give some advanced tips, because this subject often causes misunderstandig. The structure of the environmentblock in connection with the Program Segment Prefix (PSP) is not documented further, but it is of enourmous meaning gor the better understanding of this error.

Shortly said, you can only modify the existing environent, and not add any new entries!! You can use three ways if you want to add entries anyways:

a) Delete part of the environment and then add the new entry or first create a Dummy-Environmententry and the delete or modify it using the ENVIRON-Command.

b) When you want to start a DOS-SHELL with an information:
           OldEnv$ = ENVIRON$("PROMPT")
           SHELL "COMMAND.COM /K SET PROMPT=PowerBASIC " + OldEnv$
The trick with this is that when you call a SHELL a new PSP will be created and the memory will be allocated correctly.

c) Get the address of the PSP, get the pointer to the current Environmentblock and then read the environment into a string, where it can be modified. The allocate a DOS-Memoryblock using INT21, save the modified environment therem abd the set the pointer to the Environmentblock within the PSP to the new one. (Also see: Already available PD-Solutions)

4.5. No Returnerrorlevel with SHELL

You often need to check the Errorcode of an ended program in a SHELL- Command. This is not possible directly under PowerBASIC, because PowerBASIC runs a program using COMMAND.COM and because of that the Errorcode can't be returned (This is a problem of MS-DOS!!).
To solve this problem there is for instance an alternative SHELL- Command in form of a FUNCTION (as Sourcecode):
    '   Errorlevel in PowerBASIC 3.0/3.2
    '   by Thomas Gohel (after a pattern from PDS, by Bernd Hohmann)

    DECLARE FUNCTION PBShell% (FileName$)

    PRINT "Fehlercode ist: "; PBShell%("c:\dos\command.com")

    FUNCTION PBShell% (FileName$)
        LOCAL Dummy%

        Datei$ = FileName$                  ' Copy filename.
        Datei$ = LTRIM$(Datei$)             ' Trim filename.
        i% = INSTR(Datei$, " ")             ' Pass Command ?
        IF i% > 0 THEN                      '
           Cmd$ = MID$(Datei$, i%)          ' Cut Command
           Datei$ = LEFT$(Datei$, i% - 1)   ' Cut filename
        END IF                              '
        Datei$ = UCASE$(Datei$)
        i% = INSTR(Datei$, ".")             ' Is a dot in it ?
        IF i% > 0 THEN                      '
           Ext$ = MID$(Datei$, i%)          ' Get extension
        ELSE                                '
           Ext$ = ""                        ' Extension is empty
        END IF                              '
        SELECT CASE Ext$                    ' Test extension.
            CASE ".BAT"                     ' Batch over COMMAND.COM
                Cmd$ = "/C " + Datei$ + " " + Cmd$
                Datei$ = ENVIRON$("COMSPEC")
            CASE ".COM"                     ' Free
            CASE ".EXE"                     ' Free
            CASE ELSE                       ' No Extension,
                Datei$ = Datei$ + ".EXE"    ' Add .EXE.
        END SELECT                          '

        Datei$ = Datei$ + CHR$(0)           ' Create ASCII-String.
        dNul$ = CHR$(0) + CHR$(0)           ' Doublezero for Parameterblock

        nul$ = SPACE$(127)                  ' Save 127 bytes for Strings
        MemFree& = SETMEM(0)                ' Get free space
        x& = SETMEM(-MemFree&)              ' Free all memory
        nul$ = ""                           ' restore 127 Bytes.
        IF Cmd$ > "" THEN                    ' Commandline ?
            CmdLen$ = CHR$(LEN(Cmd$))        ' Length of Cmd$ as String
            Cmd$ = CmdLen$ + Cmd$ + CHR$(13) ' Length + Cmd$ + '13'
            segm$ = MKI$(STRSEG(Cmd$))       ' Single parts of the
                                             ' Parameter-Block
            Offs$ = MKI$(STRPTR(Cmd$))       ' Add ( MID$(....)
                                             ' = segm$ doesn't work)
            Param$ = dNul$ + Offs$ + segm$   ' Create Parameterblock.
        ELSE                                 '
            Cmd$ = CHR$(13)                  ' Start of Bug-Fixed
            segm$ = MKI$(STRSEG(Cmd$))       ' Segment of Terminator
            Offs$ = MKI$(STRPTR(Cmd$))       ' Offset         -"-
            Param$ = dNul$ + Offs$ + segm$   ' Create Parameterblock.
        END IF                               ' End of Bugfixed
        DateiSeg% = STRSEG(Datei$)           ' Get addresses
        DateiOff% = STRPTR(Datei$)
        ParamSeg% = STRSEG(Param$)
        ParamOff% = STRPTR(Param$)
        ! push ds                            ; Save DS
        ! mov  ax, &h4B00                    ; EXEC-Funktion 4Bh / INT 21h
        ! mov  es, ParamSeg%                 ; Segment of Parameterblock
        ! mov  bx, ParamOff%                 ; Offset of Parameterblock
        ! mov  dx, DateiOff%                 ; Offset of Filename
        ! mov  ds, DateiSeg%                 ; Segment of Filename
        ! int  &h21                          ; Interrupt &h21
        ! pop  ds
        ! jc   ExecError
        ! jmp  ExecOk
        ! mov Dummy%, ax
        SELECT CASE Dummy%                   ' Evaluate Error.
            CASE 1   : PRINT "illegal Function call!"
            CASE 2,3 : PRINT "File not found: " + FileName$
            CASE 4   : PRINT "to many files opened"
            CASE 5   : PRINT "Access denied " + Filename$
            CASE 8   : PRINT "Not enough free memory for " + FileName$
            CASE 10  : PRINT "wrong Environmentblock"
            CASE 11  : PRINT "wrong Format"
            CASE ELSE: PRINT "Problem while executing " + FileName$
        END SELECT

        Mem2& = SETMEM(MemFree&)             ' Completely free memory.
        IF MemFree& <> Mem2& THEN            ' Free memory changed
           PRINT "Warning: possibly a TSR was installed!!"
        END IF

        ! mov  ah, &h4d                      ; Get Exit-Code
        ! int &h21                           ; Interrupt &h21
        ! mov Dummy%, al
        PBShell% = Dummy%

        ! mov  ah, &h03                      ; Pass current cursor
        ! mov  bh, &h00                      ; position
        ! int &h10                           ; Interrupt &h10
        ! inc dh                             ; Recalc to basis of 1
        ! inc dl
        ! mov NewZeile?, dh
        ! mov NewSpalte?, dl
        LOCATE NewZeile?, NewSpalte?         ' Set cursor
Further on your can modify the COMSPEC-Variable in your environment and directly run your program with COMMAND.COM.
            Comspec$ = ENVIRON$("COMSPEC")  'Save COMSPEC
            SHELL                           'Execution of MEINDEMO.EXE
            ENVIRON "COMSPEC="+Comspec$     'Restore COMSPEC
Always remember, that the SHELL-Function always transfers the Parameter '/C' to the executing program, if you want to transfer Commandlineparamters yourself.

4.6. Cutting files

You often stand in front of the problem that you have cleaned your datafile, but it is still too big. In this case this small but effective trick helps:
            OPEN "DEMO.DAT" FOR BINARY AS #1
            SEEK #1, 20
            PUT$ #1, ""
            CLOSE #1
Shortens the file 'DEMO.DAT' to a length of 20 Bytes.

Standardproblems (Part 2)

(c) 1996/2007 by Thomas Gohel, All rights and bugs reserved
(c) 1996/1997 by Thomas Geiger, english version