UNIT XmsLib;

INTERFACE

VAR XmsPresent   : BOOLEAN;
    XmsErrorCode : BYTE;

    XmsVersion    : WORD;
    XmsVersionStr : STRING[10];
    XmmVersion    : WORD;
    XmmVersionStr : STRING[10];


PROCEDURE QueryFreeExtendedMemory (VAR ExtMaxAvail,ExtMemAvail : WORD);
FUNCTION  AllocateXMB (SizeInK : WORD; VAR Handle : WORD) : BOOLEAN;
FUNCTION  FreeXMB (Handle : WORD) : BOOLEAN;
FUNCTION  CopyToXmb (Len : WORD; FromPtr : POINTER; ToHandle : WORD; ToOfs : LONGINT) : BOOLEAN;
FUNCTION  CopyFromXmb (Len : WORD; ToPtr : POINTER; FromHandle : WORD; FromOfs : LONGINT) : BOOLEAN;
FUNCTION  XmsErrorStr : STRING;
(*
FUNCTION reallocXMB(newSizeInK, handle : word) : boolean;
*)


IMPLEMENTATION

TYPE XmsMoveRecord = RECORD
                           Length       : LONGINT; { # of bytes to transfer }
                           SourceHandle : WORD;
                           SourceOffset : LONGINT;
                           DestHandle   : WORD;
                           DestOffset   : LONGINT;
                     END;

VAR XmsAddress : POINTER;
    MoveRec    : XmsMoveRecord;


{--------------------------------------------------------------------------}
{ DetectXms                                                                }
{                                                                          }
{ Deze routine kijkt of er een XMS driver aanwezig is.                     }
{                                                                          }
PROCEDURE DetectXMS;

VAR Str1,Str2,Str3 : STRING[5];

BEGIN
     ASM
        MOV XmsPresent,FALSE
        MOV AX,$4300
        INT $2F
        CMP AL,$80
        JNE @@1
        MOV XmsPresent,TRUE
        @@1:
     END;

     IF XmsPresent THEN
     BEGIN
          ASM
             { bepaal het directe aanroepadres van de Xms driver }
             MOV AX,$4310
             INT $2F { adres terug in ES:BX }
             MOV WORD PTR [XmsAddress],BX
             MOV WORD PTR [XmsAddress+2],ES

             { bepaal de versie nummers van de Xms driver en de Xmm }
             MOV AH,0
             CALL [XmsAddress]
             MOV XmsVersion,AX
             MOV XmmVersion,BX
          END;

          Str (XmsVersion DIV $100,Str1);
          Str (XmsVersion MOD $100,Str2);
          XmsVersionStr:=Str1+'.'+Str2;

          Str (XmmVersion DIV $100,Str1);
          Str ((XmmVersion MOD $100)-(XmmVersion MOD $10),Str2);
          Str (XmmVersion MOD $10,Str3);
          XmmVersionStr:=Str1+'.'+Str2+Str3;
     END;
END;


{--------------------------------------------------------------------------}
{ QueryFreeExtendedMemory                                                  }
{                                                                          }
{ Deze routine vraagt bij de XMM op hoeveel geheugen er nog vrij is en wat }
{ het grootst beschikbare blok is. Deze waarden worden terug gegeven via   }
{ de VAR parameters.                                                       }
{                                                                          }
PROCEDURE QueryFreeExtendedMemory (VAR ExtMaxAvail,ExtMemAvail : WORD);
BEGIN
     ASM
        MOV AH,8
        CALL [XmsAddress]
        LES DI,ExtMaxAvail
        MOV ES:[DI],AX
        LES DI,ExtMemAvail
        MOV ES:[DI],DX
        MOV XmsErrorCode,BL
     END;
END;


{--------------------------------------------------------------------------}
{ AllocateXMB                                                              }
{                                                                          }
{ Deze routine vraagt een block aan in het XMB met de opgegeven grootte.   }
{ Om deze te gebruiken moet de terug gegeven handle gebruik worden. Merk   }
{ op dat de opgegeven lengte in KILOBYTES is en niet in bytes, zoals       }
{ gebruikelijk.                                                            }
{                                                                          }
FUNCTION AllocateXMB (SizeInK : WORD; VAR Handle : WORD) : BOOLEAN;
BEGIN
     ASM
        MOV AH,9
        MOV DX,SizeInK
        CALL [XmsAddress]
        MOV @Result,AL
        LES DI,Handle
        MOV ES:[DI],DX
        MOV XmsErrorCode,BL
     END;
END;


{--------------------------------------------------------------------------}
{ FreeXMB                                                                  }
{                                                                          }
{ Met deze routine kan een verkregen blok XMB geheugen weer vrijgegeven    }
{ worden door middel van de handle.                                        }
{                                                                          }
FUNCTION FreeXMB (Handle : WORD) : BOOLEAN;
BEGIN
     ASM
        MOV AH,10
        MOV DX,Handle
        CALL [XmsAddress]
        MOV @Result,AL
        MOV XmsErrorCode,BL
     END;
END;


{--------------------------------------------------------------------------}
{ MoveXmbBlock                                                             }
{                                                                          }
{ Dit is de laatste interface routine tussen de XMM en deze unit. Hier     }
{ wordt een interface structure gevuld en met een far pointer daar naartoe }
{ de XMM aangeroepen. Die doet daarna het echte verplaatswerk.             }
{ Len moet een even getal zijn.                                            }
{                                                                          }
FUNCTION MoveXmbBlock (Len : LONGINT;
                       SrcHandle : WORD; SrcOfs : LONGINT;
                       DstHandle : WORD; DstOfs : LONGINT) : BOOLEAN;

BEGIN
     WITH MoveRec DO
     BEGIN
          Length:=Len;
          SourceHandle:=SrcHandle;
          SourceOffset:=SrcOfs;
          DestHandle:=DstHandle;
          DestOffset:=DstOfs;
     END; { with }

     ASM
        MOV AH,11
        MOV SI,OFFSET MoveRec
        CALL [XmsAddress]
        MOV @Result,AL
        MOV XmsErrorCode,BL
     END;
END;


{--------------------------------------------------------------------------}
{ CopyToXmb                                                                }
{                                                                          }
{ Deze routine kopieert een blok data van de lagere 640Kb, bijvoorbeeld de }
{ heap, naar het Xmb.                                                      }
{                                                                          }
FUNCTION CopyToXmb (Len : WORD; FromPtr : POINTER; ToHandle : WORD; ToOfs : LONGINT) : BOOLEAN;
BEGIN
     CopyToXmb:=MoveXmbBlock (Len,0,Longint (FromPtr),ToHandle,ToOfs);
END;


{--------------------------------------------------------------------------}
{ CopyFromXmb                                                              }
{                                                                          }
{ Deze routine kopieert een blok data van het Xmb naar bijvoorbeeld de     }
{ heap.                                                                    }
{                                                                          }
FUNCTION CopyFromXmb (Len : WORD; ToPtr : POINTER; FromHandle : WORD; FromOfs : LONGINT) : BOOLEAN;
BEGIN
     CopyFromXmb:=MoveXmbBlock (Len,FromHandle,FromOfs,0,Longint (ToPtr));
END;


(*
FUNCTION reallocXMB;
var
   reallocGranted : boolean;
begin
   asm
      mov ah, $f
      mov bx, newSizeInK
      mov dx, handle
      call [xmsAddress]
      mov reallocGranted, al
      mov xmsErrorCode, bl
   end; { asm }
   reallocXMB := reallocGranted;
end; {reallocXMB}
*)


{--------------------------------------------------------------------------}
{ XmsErrorStr                                                              }
{                                                                          }
{ Deze routine zoekt in de tabel met foutmeldingen naar de bijbehorende    }
{ tekst en geeft deze terug. Niet alle omschrijvingen zijn hier opgenomen. }
{                                                                          }
FUNCTION XmsErrorStr : STRING;

VAR Lp : BYTE;

BEGIN
     CASE XmsErrorCode OF
          $8E : XmsErrorStr:='General driver error';
          $8F : XmsErrorStr:='Fatal driver error';
          $A0 : XmsErrorStr:='No more free extended memory';
          $A1 : XmsErrorStr:='No more XMS handles';
          $A2 : XmsErrorStr:='Invalid handle';
          $A3 : XmsErrorStr:='Invalid source handle';
          $A4 : XmsErrorStr:='Invalid source offset';
          $A5 : XmsErrorStr:='Invalid destination handle';
          $a6 : XmsErrorStr:='Invalid destination offset';
          $A7 : XmsErrorStr:='Invalid length';
          $A8 : XmsErrorStr:='Move resulted in overlap';
          $A9 : XmsErrorStr:='Parity error';
          ELSE  XmsErrorStr:='Unknown XMS error';
     END; { case }
END;


{--------------------------------------------------------------------------}
{ unit initialization                                                      }
{                                                                          }
BEGIN
     DetectXMS;
END.
