Unit XMSArray;

{ Author: Bean, thitt@igateway.com }
{ This code is hereby released to the public domain }
{ Use this code at YOUR own risk, Hey it works for me :) }
{ Version 1.0 07-20-98 }

{$X+}

INTERFACE

{ All functions return True is successful or False if not successful }
{ If you don't want to check if successful use the extended syntax $X+ }
{ compiler directive. }
{ *** NOTE: All number of bytes to move MUST be an even number }

Type
  XMSHandle = Word;

Function XMSExist: Boolean;
{ Returns true is XMS memory is supported }

Function XMSVersion: Word;
{ Returns the XMSVersion in BCD. Version 3.0 would return 768 }

Function XMSMemAvail: LongInt;
{ Returns total amount of XMS memory available in bytes }

Function XMSMaxAvail: LongInt;
{ Returns the size of the largest block of XMS memory avaible }
{  This would be the max size that a single handle could point to }

Function XMSGetMem(Var Handle: XMSHandle; NumBytes: LongInt): Boolean;
{ Used to allocate XMS memory. The returned handle is used to access and/or }
{  free the XMS memory }

Function XMSMoveTo(Var Source; DestHandle: XMSHandle; NumBytes: LongInt): Boolean;
{ Moves bytes from conventional memory to start of XMS memory block }

Function XMSMoveToOfs(Var Source; DestHandle: XMSHandle; DestOfs, NumBytes: LongInt): Boolean;
{ Moves bytes from conventional memory to an offset in an XMS memory block }

Function XMSMoveFrom(SourceHandle: XMSHandle; Var Dest; NumBytes: LongInt): Boolean;
{ Moves bytes from start of XMS block to conventional memory }

Function XMSMoveFromOfs(SourceHandle: XMSHandle; SourceOfs: LongInt; Var Dest; NumBytes: LongInt): Boolean;
{ Moves bytes from offset on XMS block to conventional memory }

Function XMSFreeMem(Handle: XMSHandle): Boolean;
{ Releases allocated XMS memory. NOTE: XMS memory is NOT freed automatically }
{  When your program ends. You MUST explicitly free it ! }

Type
  { TXMSArray is an object oriented way of using a block of XMS as a }
  {  one dimensional array. }
  { After calling Init check if Handle is zero, if so the array could }
  {  NOT be create. In other words Handle should not be zero. }
  { NOTE: DataSize MUST be an EVEN number }
  { NOTE: Elements are numbered 0 though n-1 }
  PXMSArray = ^TXMSArray;
  TXMSArray = Object
    Handle: XMSHandle;
    Elements: LongInt;
    DataSize: LongInt;
    Constructor Init(GElements, GDataSize: LongInt);
    Destructor Done; Virtual;
    Function SetElement(GElement: LongInt; Var Data): Boolean;
    Function GetElement(GElement: LongInt; Var Data): Boolean;
  End;

  { TXMS2DArray is an object oriented way of using a block of XMS as a }
  {  two dimensional array. }
  { After calling Init check if Handle is zero, if so the array could }
  {  NOT be create. In other words Handle should not be zero. }
  { NOTE: DataSize MUST be an EVEN number }
  { NOTE: Elements are numbered 0 though n-1 }
  PXMS2DArray = ^TXMS2DArray;
  TXMS2DArray = Object
    Handle: XMSHandle;
    Rows, Columns: LongInt;
    DataSize: LongInt;
    Constructor Init(GRows, GColumns, GDataSize: LongInt);
    Destructor Done; Virtual;
    Function SetElement(GRow, GColumn: LongInt; Var Data): Boolean;
    Function GetElement(GRow, GColumn: LongInt; Var Data): Boolean;
  End;

IMPLEMENTATION

Var
  XMSOk: Boolean;
  Version: Word;
  XMSEntry: Pointer;
  XMSMoveRecd: Record
    XMS_Size: LongInt;
    XMS_SrcH: XMSHandle;
    XMS_SrcOfs: LongInt;
    XMS_DestH: XMSHandle;
    XMS_DestOfs: LongInt;
  End;

Function XMSInit(Var Version: Word): Boolean;
Var
  XMSHere: Boolean;
  Ver: Word;
Begin
  Asm
    MOV XMSHere,0  { Assume failure }
    MOV Ver,0
    MOV AX,4300H   { 4300 = Check XMS }
    INT 2FH        { Interrupt returns 80 in AL if XMS exists }
    CMP AL,80H
    JNE @NOXMS
    MOV XMSHere,1  { Set flag to true }
    MOV AX,4310H   { 4310 = Get XMS calling address }
    INT 2FH        { Returns calling address in ES:BX }
    MOV DS:[OFFSET XMSEntry],BX { Save calling address }
    MOV DS:[OFFSET XMSEntry+2],ES
    XOR AX,AX      { Zero AX }
    CALL DS:[XMSEntry] { Call XMS to get version }
    MOV Ver,AX     { Store version number }
  @NOXMS:
  End;
  Version:=Ver;
  XMSInit:=XMSHere;
End;

Function XMSExist: Boolean;
Begin
  XMSExist:=XMSOk;
End;

Function XMSVersion: Word;
Begin
  XMSVersion:=Version;
End;

Function XMSMemAvail: LongInt; { Returns zero if no XMS available }
Var
  SizeInK: Word;
Begin
  If Not XMSOk Then XMSMemAvail:=0
  Else
  Begin
    Asm
      MOV AH,8
      CALL DS:[XMSEntry]
      MOV SizeInK,DX
    End;
    XMSMemAvail:=LongInt(SizeInK) * 1024; { Convert K to bytes }
  End;
End;

Function XMSMaxAvail: LongInt;
Var
  SizeInK: Word;
Begin
  If Not XMSOk Then XMSMaxAvail:=0
  Else
  Begin
    Asm
      MOV AH,8
      CALL DS:[XMSEntry]
      MOV SizeInK,AX
    End;
    XMSMaxAvail:=LongInt(SizeInK) * 1024; { Convert K to bytes }
  End;
End;

Function XMSGetMem(Var Handle: XMSHandle; NumBytes: LongInt): Boolean;
Var
  GetOk: Boolean;
  Hand: Word;
  SizeInK: Word;
Begin
  If Not XMSOk Then XMSGetMem:=False
  Else
  Begin
    { XMS allocates in KBytes to find size in K }
    SizeInK:=Succ(Pred(NumBytes) Div 1024);
    Asm
      MOV GetOk,0  { Assume No Good }
      MOV DX,SizeInK
      MOV AH,9
      CALL DS:[XMSEntry]
      OR AX,AX
      JZ @NoGood
      MOV Hand,DX
      MOV GetOk,1
    @NoGood:
    End;
    Handle:=Hand;
    XMSGetMem:=GetOk;
  End;
End;

Function XMSMove(SourceHandle: XMSHandle; SourceOfs: LongInt;
                 DestHandle: XMSHandle; DestOfs: LongInt; Count: LongInt): Boolean;
Var
  MoveOk: Boolean;
Begin
  MoveOk:=False;
  If XMSOk and Not Odd(Count) Then
  Begin
    With XMSMoveRecd Do
    Begin
      XMS_Size:=Count;
      XMS_SrcH:=SourceHandle;
      XMS_SrcOfs:=SourceOfs;
      XMS_DestH:=DestHandle;
      XMS_DestOfs:=DestOfs;
    End;
    Asm
      MOV SI,OFFSET XMSMoveRecd
      MOV AH,0Bh
      CALL DS:[XMSEntry]
      OR AX,AX
      JZ @NoGood
      MOV MoveOk,1
    @NoGood:
    End;
  End;
  XMSMove:=MoveOk;
End;

Function XMSMoveTo(Var Source; DestHandle: XMSHandle; NumBytes: LongInt): Boolean;
Begin
  XMSMoveTo:=XMSMoveToOfs(Source, DestHandle, 0, NumBytes);
End;

Function XMSMoveToOfs(Var Source; DestHandle: XMSHandle; DestOfs, NumBytes: LongInt): Boolean;
Begin
  XMSMoveToOfs:=XMSMove(0, LongInt(@Source), DestHandle, DestOfs, NumBytes);
End;

Function XMSMoveFrom(SourceHandle: XMSHandle; Var Dest; NumBytes: LongInt): Boolean;
Begin
  XMSMoveFrom:=XMSMoveFromOfs(SourceHandle, 0, Dest, NumBytes);
End;

Function XMSMoveFromOfs(SourceHandle: XMSHandle; SourceOfs: LongInt; Var Dest; NumBytes: LongInt): Boolean;
Begin
  XMSMoveFromOfs:=XMSMove(SourceHandle, SourceOfs, 0, LongInt(@Dest), NumBytes);
End;

Function XMSFreeMem(Handle: XMSHandle): Boolean;
Begin
  If Not XMSOk Then XMSFreeMem:=False Else
  Begin
    Asm
      MOV DX,Handle
      MOV AH,0Ah
      CALL DS:[XMSEntry]
    End;
    XMSFreeMem:=True;
  End;
End;

{ **************************************************************** }

Constructor TXMSArray.Init(GElements: LongInt; GDataSize: LongInt);
Begin
  Elements:=GElements;
  DataSize:=GDataSize;
  If Odd(DataSize) or Not XMSGetMem(Handle, Elements * DataSize) Then
  Begin
    Handle:=0;
  End;
End;

Destructor TXMSArray.Done;
Begin
  XMSFreeMem(Handle);
  Handle:=0;
End;

Function TXMSArray.SetElement(GElement: LongInt; Var Data): Boolean;
Begin
  {$IFOPT R+}
  If GElement >= Elements Then RunError(201);
  {$ENDIF}
  SetElement:=XMSMoveToOfs(Data, Handle, GElement * DataSize, DataSize);
End;

Function TXMSArray.GetElement(GElement: LongInt; Var Data): Boolean;
Begin
  {$IFOPT R+}
  If GElement >= Elements Then RunError(201);
  {$ENDIF}
  GetElement:=XMSMoveFromOfs(Handle, GElement * DataSize, Data, DataSize);
End;

{ **************************************************************** }

Constructor TXMS2DArray.Init(GRows, GColumns: LongInt; GDataSize: LongInt);
Begin
  Rows:=GRows;
  Columns:=GColumns;
  DataSize:=GDataSize;
  If Odd(DataSize) or Not XMSGetMem(Handle, Columns * Rows * DataSize) Then
  Begin
    Handle:=0;
  End;
End;

Destructor TXMS2DArray.Done;
Begin
  XMSFreeMem(Handle);
  Handle:=0;
End;

Function TXMS2DArray.SetElement(GRow, GColumn: LongInt; Var Data): Boolean;
Begin
  {$IFOPT R+}
  If (GRow >= Rows) or (GColumn >= Columns) Then RunError(201);
  {$ENDIF}
  SetElement:=XMSMoveToOfs(Data, Handle, GRow * Columns * DataSize + GColumn * DataSize, DataSize);
End;

Function TXMS2DArray.GetElement(GRow, GColumn: LongInt; Var Data): Boolean;
Begin
  {$IFOPT R+}
  If (GRow >= Rows) or (GColumn >= Columns) Then RunError(201);
  {$ENDIF}
  GetElement:=XMSMoveFromOfs(Handle, GRow * Columns * DataSize + GColumn * DataSize, Data, DataSize);
End;

{ **************************************************************** }

Begin { Unit initalization code }
  XMSOk:=XMSInit(Version);
End.

    Source: geocities.com/SiliconValley/2926/tpsrc

               ( geocities.com/SiliconValley/2926)                   ( geocities.com/SiliconValley)