Code:
'-------------------------------------------------------------------------------
'
'        Unit: PREPBOOT.PBL
'       Zweck: Funktionen zum Vorbereiten eines PC-Neustarts, u.a.
'               Flush-Funktion für verschiedene Disk-Caches (ohne Prüfung),
'               Netzwerkverbindungen aufheben usw.
'     Version: 1.50
'       Stand: 28.10.97
'     Sprache: PowerBASIC 3
'       Autor: (C) M.Hoffmann, Wedeler Ldstr.139, 22559 Hamburg.
' Bemerkungen:
'  Es wird nicht geprüft, welcher Cache oder ob ein Netzwerk geladen ist -
'   die Funktionen werden alle "blind" aufgerufen.
'   ACHTUNG: Alle offenen PB-Dateien werden geschlossen!
' Historie:
'  1.50 28.10.97 - Weitere(n) (Disk)Cache(s) berücksichtigen; PUSH/POP Regs;
'                  Löschen mit XOR a,a statt MOV a,0; PCTools-Flush-Funktion
'                  geändert. Evtl. noch überall PUSHALL/POPALL verwenden.
'
' c: prepboot.pbu      2119   9.07.96  15:53   v1.40
' c: prepboot.pbu      2862  28.10.97  16:17   v1.50
'

'---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

'---Definitionen----------------------------------------------------------------

%ax = 1
%bx = 2
%cx = 3
%dx = 4
%si = 5
%ds = 8
%es = 9

type dosdpltype
    notused as string*16  ' AX,BX,CX,DX,SI,DI,DS,ES (not used here)
    res as word           ' RESERVED (0)
    cid as word           ' COMPUTER ID (0 = CURRENT SYSTEM)
    pid as word           ' PROCESS ID (PSP SEGMENT ON SPECIFIED COMPUTER)
end type                  '  (not used here)

type fastAPI_RequestPackettype
    sigptr as dword       ' Zeiger auf Signaturstring
    bufptr as dword       ' Zeiger auf Datenpuffer
end type

'---Routine---------------------------------------------------------------------

sub PrepareBoot (byval CallBack as dword,_
                 byval BootFlag as integer) local public

   '
   ' Ist CallBack <> 0, wird VOR allen Systemaufrufen ein CALL FAR zur
   ' angegebenen Adresse durchgeführt, falls weitere - hier nicht vorgesehene -
   ' Operationen automatisch initiiert werden sollen.
   ' Ist BootFlag = 0, wird kein Neustart durchgeführt (wenig sinnvoll -
   '                   der Neustart sollte dann im Hauptprogramm unmittelbar
   '                   anschließend erfolgen).
   ' Ist BootFlag = 1, wird ein WARMstart durchgeführt.
   ' Ist BootFlag = 2, wird ein KALTstart durchgeführt.
   ' Ist BootFlag = 3, wird ein Boot über den Tastaturkontroller durchgeführt.
   ' Ist BootFlag < 0, wird ein Boot durchgeführt, wobei zuvor der Wert
   '                 ABS(BootFlag) an die Speicheradresse 0040:0072 geschrieben
   '                 wird.
   ' PowerBASIC-Dateien werden geFLUSHt und vor dem Booten geCLOSEd.
   '

   dim l      as local string
   dim i      as local integer
   dim dosdpl as local dosdpltype
   dim fapirp as local fastAPI_RequestPackettype
   dim fapsig as local string*19

   ' User-Callbackroutine
   if CallBack <> 0 then
      ' ACHTUNG: Routine muß mit FAR RETurn enden (z.B. PB's END SUB) und
      '          die Register erhalten!
      ! call dword ptr CallBack
   end if

   ' Broadcast (nur für TSRs, die diesen Call abfangen, sinnvoll)
   ! push si
   ! mov ax,&hffff
   ! mov bx,&heeee
   ! mov cx,&hdddd
   ! mov dx,&hcccc
   ! mov si,BootFlag
   ! int &h2f
   ! pop si

   ' SMARTDrive v4+ , PC-Cache (PCTools) v8.0 -- Flush
   ' (wird möglicherweise auch von NCache2 behandelt)
   ! mov ax,&h4A10
   ! mov bx,&h0001
   ! int &h2f

   ' PCTools Cache v5.x, QCache v4.00, Super PC-Kwik v3.20+ -- Flush
   ! push si
   ! mov ah,&hA1
   ! mov si,&h4358
   ! int &h13
   ! pop si

   ' PCTools Cache v6+ -- Flush
   ! mov ax,&hFFA5
   ! mov cx,&hDDDD ; zuvor FFFF
   ! int &h16

   ' Norton NCache2 ab v7 -- Flush
   ! push si
   ! push di
   ! mov ax,&hFE03
   ! mov di,&H4E55 ; "NU"
   ! mov si,&H4346 ; TSR-ID = "CF" für NCache
   ! int &h2f
   ! pop di
   ! pop si

   ' QuickCache II v4.20
   ! mov ah,&h21
   ! int &h13

   ' FAST! v4.02+
   fapsig = chr$(&h13,&h07,&h06,&h08,&h11,&h18,&h0f,&h0e,&h02,&h18,_
                 &h13,&h08,&h0b,&h08,&h01,&h00,&h04,&h08,&h15)
   fapirp.sigptr = varptr32(fapsig)
   reg %es,varseg(fapirp)
   reg %bx,varptr(fapirp)
   reg %ax,&h8009 ' Funktion 09 = Flush-Cache
   reg %cx,&h6572 ' Konstante
   reg %dx,&h1970 ' Konstante
   call interrupt &h13

   ' PC Magazine PCSpool
   ! mov ah,&hC2
   ! mov dx,0
   ! int &h17
   ! mov ah,&hC2
   ! mov dx,1
   ! int &h17
   ! mov ah,&hC2
   ! mov dx,2
   ! int &h17
   ! mov ah,&hC2
   ! mov dx,3
   ! int &h17

   ' Dos-PRINT-Tsr (keine Prüfung, ob geladen)
   ! mov ax,&h0103 ; "Cancel all files"
   ! int &h2f

   ' close pending Network-print jobs
   ! mov ax,&h5D09
   ! int &h21

   ' SHARE: Close all files for given computer
   '  (entspricht NICHT net files /close)
   dosdpl.cid = 0  ' nur diese Angabe wird von diesem Call benutzt
   reg %ax,&h5D03
   reg %ds,varseg(dosdpl)
   reg %dx,varptr(dosdpl)
   call interrupt &h21

   ' Vor dem Aufheben der Netzwerkredirektionen auf das Startlaufwerk wechseln
   '  Bei Fehler jedoch zurück auf's aktuelle
   reg %ax,&h3305
   call interrupt &h21
   l = left$(curdir$,2)
   on local error resume next
   chdrive chr$(bits?(reg(%dx))+64)
   if errtest <> 0 then
      chdrive l
   end if
   on local error goto 0

   ' Netzwerkredirektionen aufheben (ohne Prüfung, ob tatsächlich vorhanden)
   for i=65 to 93
      if i < 91 then
         l = chr$(i)+":"+chr$(0)
      else
         l = "LPT"+chr$(i-42,0)
      end if
      reg %ax,&h5F04
      reg %ds,strseg(l)
      reg %si,strptr(l)
      call interrupt &h21
   next

   ' Manche Disk-Caches, z.B. NCache2 lt. Doku, werten diesen Funktions-
   ' aufruf als Zeichen, ausstehende Daten zurückzuschreiben; daher der
   ' Vollständigkeit halber.
   ! mov ah,&h0D ; Dos 'Disk Reset'
   ! int &h21

   ' BIOS-Diskreset für Disks und Festplatten (evtl. ist dies der Call,
   ' den NCache abfängt (s.o.)
   ! xor ah,ah
   ! xor dl,dl
   ! int &h13
   ! xor ah,ah
   ! mov dl,&h80
   ! int &h13

   ' Normale DOS-Idle-Calls als letztes (zur Sicherheit)
   call interrupt &h28 ' DOS-Idle
   ' INT28 zerstört Register, daher CALL (Fehler im DOS)
   ! mov ax,&h1680 ; release TimeSlice
   ! int &h2f
   ! mov ax,&h8400 ; Network-Keyboard-Busyloop
   ! int &h2a

   ' PB-Dateien FLUSHen
   flush

   def seg = &h40
   if BootFlag = 1 then
      pokei &h72, &h1234
      ' Expanded-Memory-Manager auf Warmstart vorbereiten
      ! mov ah,&h5C
      ! int &h67
   elseif BootFlag = 2 then
      pokei &h72, &h0
   elseif BootFlag < 0 then
      pokei &h72, abs(BootFlag)
   elseif BootFlag = 3 then
      reset
      do
         if (inp(&h64) and &b10) = &b00 then
            out &h64,&hFE
            rem Auf einigen Geräten scheint dies nicht zu gehen
            rem also mit anderer Methode fortfahren
            pokei &h72, &h0
            BootFlag = 1
            exit loop
         end if
      loop
   end if
   def seg

   if BootFlag < 3 and BootFlag <> 0 then
      ' PB-Dateien schließen
      reset
      def seg=&hffff
      i = 0
      call absolute i
   end if

end sub

'===============================================================================
------------------