Code:
'------------------------------------------------------------------------------- ' ' Unit: DOSEXEC1.PBL ' Zweck: Laden und Starten eines Programmes über DosExec ' (ähnlich SHELL, aber mit Rückgabecode) ' Version: 1.30 ' Stand: 05.08.96 ' Sprache: PowerBASIC 3 ' Autor: (C) M.Hoffmann, Friedensallee 105, 22763 Hamburg. ' Bemerkungen: ' Teilinformationen aus: PBEXEC.BAS von Ethan Winer für MS-BASIC, ' konvertiert nach PowerBASIC 3.0 von Gary Blydenburgh. Ist das Carryflag ' gesetzt, sind nur die AX-Werte 1,2,3,4,8,10,11 als Fehlercodes zu inter- ' pretieren. Diese Information fehlt in ALLEN sonstigen Dokumentationen. ' 1.10: Sichern/Restaurieren DTA; wahlweises Umleiten von STDOUT; ' (inkompatible Parameterübergabe); ON LOCAL ERROR aktiviert. ' 1.20: Abfangen ungültiger Dateinamen-Erweiterungen (nur EXE und COM ok), ' Benutzen von VARPTR32 anstalle von FarPtr (100++Bytes kleiner). ' 1.30: Methode zur Ausgabeumleitung geändert, da Handle blockiert wurden. ' c: dosexec1.pbu 2128 5.08.96 16:03 \pgm\pb3\unit ' '---Compiler-------------------------------------------------------------------- $compile unit $cpu 80386 $debug map-,pbdebug-,path-,unit- $dim all $error bounds-,numeric-,overflow-,stack- $event off $float emulate $lib all- $optimize size $static '---Konstanten------------------------------------------------------------------ %flags = 0 %ax = 1 %bx = 2 %dx = 4 %ds = 8 %es = 9 '---Definitionen---------------------------------------------------------------- type DosExecParmBlockType envSeg as word cmdPtr as dword fcb1Ptr as dword fcb2Ptr as dword end type '---Routine--------------------------------------------------------------------- function DosExecPgm (Pgm as string,_ Parms as string,_ Bytes as long ,_ StdAus as string)_ public as integer ' ' Eingaben: ' Pgm: Vollständige Spezifikation des auszuführenden Programms ' Parms: Optionale Programmparameter ' Bytes: Benötigter Speicherplatz in Bytes (COMMAND wird auch geladen) ' 0: sämtlichen verfügbaren Speicher freigeben ' StdAus: Standardausgaben des gerufenen Programmes in die angegebene ' >>>> Einheit umleiten. ACHTUNG: Verwendet das rufende Programm ' >>>> die Einheit "CONS:" für Ausgaben, muß diese zuvor geschlossen ' >>>> und anschließend neu geöffnet werden! ' ' Rückgabe: ' n : Returncode des ausgeführten Programms ' : Highbyte: ' : 0 = Ende via Dos-Funktion 0 oder 4Ch ' : 1 = Abbruch via INT 23h (Ctrl+C/Break) ' : 2 = Abbruch via INT 24h (Critical Error) ' : 3 = Ende via Dos-Funktion 31 (Keep) oder INT 27h ' : Lowbyte: ' : Programmendecode ' -1 (Dos-Error 1) : nicht unterstützte Funktion ' -2 (Dos-Error 2) : Datei nicht gefunden ' -3 (Dos-Error 3) : Suchweg nicht gefunden ' -4 (Dos-Error 4) : Keine freien Handles ' -8 (Dos-Error 8) : Nicht genug Speicherplatz ' -10 (Dos-Error 10) : Ungültiges Environment ' -11 (Dos-Error 11) : Ungültiger Parameterblock ' -16 (PB) : StdOut kann nicht geöffnet werden ' -17 (PB) : Ungültige Programmspezifikation (<> EXE,COM) ' ' ACHTUNG: Da keine offizielle PB-Funktion, bleiben viele Interrupts ' umgebogen (z.B. INT9). Daher mit Vorsicht anwenden. ' dim Prog as local string* 64 ' stellt Maximallänge sicher dim CmdL as local string*128 ' stellt Maximallänge sicher dim fcb1 as local string* 16 ' nur Dummy dim fcb2 as local string* 16 ' nur Dummy dim dummy as local long ' Ergebnis von SETMEM dim ToFre as local long ' Freizugebende Bytes dim Parm as local DosExecParmBlockType ' Übergabeblock für EXEC dim Temp as local string ' Für Konstruktion der KmdoZeile dim DtaOfs as local integer ' Sicherung DTA-Segment dim DtaSeg as local integer ' Sicherung DTA-Offset dim StdHd as local integer ' PB Handle für Ausgabeeinheit dim DosHd as local integer ' DOS-Handle für Ausgabeeinheit dim DupHd as local integer ' 2. Handle für StdOut zum Retten if instr(".COM.EXE",ucase$(right$(Pgm,4))) = 0 then function = -17 exit function end if ' DTA sicherstellen (wird von EXEC umgesetzt, aber nicht restauriert!) ! mov ah,&h2f ! int &h21 ! mov DtaOfs,bx ! mov DtaSeg,es ' Erfolg wird NICHT überprüft if len(StdAus) then StdHd = FREEFILE on local error resume next open StdAus for output as #StdHd if errtest<>0 then function = -16 exit function end if on local error goto 0 ' wieder in allgem. Fehlerroutine zurückschalten DosHd = fileattr(StdHd,2) ! mov ah,&h45 ; DupHandle ! mov bx,1 ; OrgHandle von STDOUT ! int &h21 ; keine Fehlerprüfung! ! mov DupHd,ax ; Zusätzlicher Handle für STDOUT für Wiederherstellung '--------------------------------------------------------------------- ! mov ah,&h46 ; ForcDup=Umleiten ! mov bx,DosHd ; Handle von der übergebenen Datei ! mov cx,1 ; Umlenken von STDOUT in DosHd ! int &h21 ; Fehler werden ignoriert! end if Prog = left$(Pgm,63)+chr$(0) Temp = left$(" "+Parms,126) CmdL = chr$(len(Temp))+Temp+chr$(13) Parm.envSeg = 0 ' Benutze Environment des Aufrufers Parm.cmdPtr = varptr32(CmdL) Parm.fcb1Ptr = varptr32(fcb1) Parm.fcb2Ptr = varptr32(fcb2) reg %ax , &h4B00 reg %ds , varseg(Prog) reg %dx , varptr(Prog) reg %es , varseg(Parm) reg %bx , varptr(Parm) if Bytes = 0 then ToFre = fre(-1) else ToFre = Bytes end if dummy = setmem(-ToFre) call interrupt &h21 dummy = setmem(+ToFre) if reg(%flags) and 1 then select case reg(%ax) case 1,2,3,4,8,10,11 function = -reg(%ax) goto DosExecPgmExit end select end if ! mov ah,&h4D ! int &h21 ! mov function,ax DosExecPgmExit: ' DTA restaurieren ! push ds ! mov ah,&h1A ! mov dx,DtaOfs ! mov ds,DtaSeg ! int &h21 ! pop ds if len(StdAus) then close StdHd ' Übergebene Datei aus PB-Sicht schließen ! mov ah,&h46 ; ForcDup=Umleiten ! mov bx,DupHd ; Gedoppelter Handle von STDOUT ! mov cx,1 ; Umlenken von STDOUT in gedoppelten Handle, also letzt- ! int &h21 ; endlich auf sich selbst. Fehler werden ignoriert! ' behebt Problem 'No more filehandles' ' 1.30 ! mov ah,&h3e ; CloseFile (Test) ' 1.30 ! mov bx,DupHd ; CloseFile (Test) ' 1.30 ! int &h21 ; CloseFile (Test) ' 1.30 end if end function