;
;-------------------------------------------------------------------
!TOPIC 1 OpXms
The OpXms unit contains a variety of routines for working with extended
memory. It allows you to determine whether or not XMS memory is installed
and, if so, how much is currently available. You can allocate and deallocate
extended memory.

This unit also has routines for working with the High Memory Area (HMA).
To use the HMA, routines are also provided to enable, disable, and query the
state of the CPU's A20 line, which must be enabled in order to use
the HMA.

Allocated extended memory blocks may be locked. This assures that they will
not be moved by the XMS memory manager. This unit contains routines to lock,
unlock, and get information about allocated extended memory blocks.

Some XMS memory managers support routines to allocate and free Upper Memory
Blocks (UMB). UMBs are areas of memory located above the 640K of DOS
accessable memory and below the 1 megabyte boundary. This memory is generally
only accessable under 386 extended memory managers. This unit contains
routines to allocate and free UMBs.

For further information on XMS memory, it is recommended that you read the
documentation that accompanies Microsoft's HIMEM.SYS XMS driver. Also, the
Addison Wesley book "Extending MS-DOS" contains an excellent discussion of XMS
memory.

  0015AllocateExtMem             0022AllocUpperMemBlock       0002Declarations
  0005Error codes                0016FreeExtMem               0023FreeUpperMemBlock
  0020GetHandleInfo              0010GlobalDisableA20         0009GlobalEnableA20
  0012LocalDisableA20            0011LocalEnableA20           0018LockExtMemBlock
  0017MoveExtMemBlock            0013QueryA20                 0014QueryFreeExtMem
  0008ReleaseHMA                 0021ResizeExtMemBlock        0007RequestHMA
  0019UnlockExtMemBlock          0024XmsErrorString           0006XmsInstalled
;
;-------------------------------------------------------------------
!TOPIC 2 Declarations
!NOINDEX
OPXMS provides the following types and variables:

  0003ExtMemPtr           0004XmsControl

;
;-------------------------------------------------------------------
!TOPIC 3 ExtMemPtr
!NOINDEX
type
  ExtMemPtr      =
    record
      case Boolean of
        False : (RealPtr : Pointer);
        True  : (ProtectedPtr : LongInt);
    end;

A variant record used to specify pointers to either conventional or extended
memory. In conventional memory, pointers are normal Segment:Offset dword
pointers. In protected memory, linear (LongInt) pointers are used. This type
is used only for the 0017MoveExtMemBlock function.
;
;-------------------------------------------------------------------
!TOPIC 4 XmsControl
!NOINDEX
var
  XmsControl       : Pointer;

Stores a pointer to the XMS control procedure. This is intended primarily for
internal use.
;-------------------------------------------------------------------
!TOPIC 5 Error codes
!NOINDEX
The following is a list of the error code constants interfaced by the
0001OPXMS unit:

  FuncNotImplemented   = $80; {function is not implemented}
  VDiskDeviceDetected  = $81; {a VDISK compatible device found}
  A20Error             = $82; {an A20 error occurred}
  GeneralDriverError   = $8E; {general driver error}
  UnrecoverableError   = $8F; {unrecoverable driver error}
  HmaDoesNotExist      = $90; {high memory area does not exist}
  HmaAlreadyInUse      = $91; {high memory area already in use}
  HmaSizeTooSmall      = $92; {size requested less than /HMAMIN}
  HmaNotAllocated      = $93; {high memory area not allocated}
  A20StillEnabled      = $94; {A20 line is still enabled}
  AllExtMemAllocated   = $A0; {all extended memory is allocated}
  OutOfExtMemHandles   = $A1; {extended memory handles exhausted}
  InvalidHandle        = $A2; {invalid handle}
  InvalidSourceHandle  = $A3; {invalid source handle}
  InvalidSourceOffset  = $A4; {invalid source offset}
  InvalidDestHandle    = $A5; {invalid destination handle}
  InvalidDestOffset    = $A6; {invalid destination offset}
  InvalidLength        = $A7; {invalid length}
  OverlapInMoveReq     = $A8; {overlap in move request}
  ParityErrorDetected  = $A9; {parity error detected}
  BlockIsNotLocked     = $AA; {block is not locked}
  BlockIsLocked        = $AB; {block is locked}
  LockCountOverflowed  = $AC; {lock count overflowed}
  LockFailed           = $AD; {lock failed}
  SmallerUMBAvailable  = $B0; {a smaller upper memory block is avail}
  NoUMBAvailable       = $B1; {no upper memory blocks are available}
  InvalidUMBSegment    = $B2; {invalid upper memory block segment}

The routine 0024XmsErrorString can be used to translate an error code
returned by an OPXMS function into an error message.
;
;-------------------------------------------------------------------
!TOPIC 6 XmsInstalled
!NOINDEX
function 0001OpXms.XmsInstalled : Boolean;

Returns True if an XMS memory manager is installed.
;
;-------------------------------------------------------------------
!TOPIC 7 RequestHMA
!NOINDEX
function 0001OpXms.RequestHMA(Bytes : Word) : Byte;

Request the High Memory Area (HMA). Bytes is amount of memory if TSR or
device driver, or $FFFF if application program. Possible return codes:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $90 if the HMA does not exist
  $91 if the HMA is already in use
  $92 if Bytes is less than the /HMAMIN= parameter

See also:
  0008ReleaseHMA
;
;-------------------------------------------------------------------
!TOPIC 8 ReleaseHMA
!NOINDEX
function 0001OpXms.ReleaseHMA : Byte;

Release the High Memory Area. Possible return codes:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $90 if the HMA does not exist
  $93 if the HMA was not allocated

See also:
  0007RequestHMA
;
;-------------------------------------------------------------------
!TOPIC 9 GlobalEnableA20
!NOINDEX
function 0001OpXms.GlobalEnableA20 : Byte;

Attempt to enable the A20 line. Should be used only by programs that
have control of the HMA. Possible return codes:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $82 if an A20 error occurs

See also:
  0010GlobalDisableA20              0011LocalEnableA20
  0012LocalDisableA20               0013QueryA20
;
;-------------------------------------------------------------------
!TOPIC 10 GlobalDisableA20
!NOINDEX
function 0001OpXms.GlobalDisableA20 : Byte;

Attempt to disable the A20 line. Possible return codes:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $82 if an A20 error occurs
  $94 if the A20 line is still enabled

See also:
  0009GlobalEnableA20               0011LocalEnableA20
  0012LocalDisableA20               0013QueryA20
;
;-------------------------------------------------------------------
!TOPIC 11 LocalEnableA20
!NOINDEX
function 0001OpXms.LocalEnableA20 : Byte;

Attempt to enable the A20 line. Should be used only by programs that
need direct access to extended memory. Possible return codes:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $82 if an A20 error occurs

See also:
  0010GlobalDisableA20              0009GlobalEnableA20
  0012LocalDisableA20               0013QueryA20
;
;-------------------------------------------------------------------
!TOPIC 12 LocalDisableA20
!NOINDEX
function 0001OpXms.LocalDisableA20 : Byte;

Attempt to disable the A20 line. Possible return codes:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $82 if an A20 error occurs
  $94 if the A20 line is still enabled

See also:
  0010GlobalDisableA20              0009GlobalEnableA20
  0011LocalEnableA20                0013QueryA20
;
;-------------------------------------------------------------------
!TOPIC 13 QueryA20
!NOINDEX
function 0001OpXms.QueryA20 : Byte;

Checks to see if the A20 line is physically enabled. Possible return codes:

  $00 A20 line disabled
  $01 A20 line enabled
  $80 if the function is not implemented
  $81 if a VDISK device is detected

See also:
  0010GlobalDisableA20               0009GlobalEnableA20
  0011LocalEnableA20                 0012LocalDisableA20
;
;-------------------------------------------------------------------
!TOPIC 14 QueryFreeExtMem
!NOINDEX
function 0001OpXms.QueryFreeExtMem(var TotalFree,
                               LargestBlock : Word) : Byte;

Return the amount of total free extended memory in TotalFree, and the Size
of the largest free block of extended memory in LargestBlock. Both values
are specified in number of kilobytes. Possible function results:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $A0 if all extended memory is allocated
;
;-------------------------------------------------------------------
!TOPIC 15 AllocateExtMem
!NOINDEX
function 0001OpXms.AllocateExtMem(SizeInK : Word;
                              var XmsHandle : Word) : Byte;

Allocate a block of extended memory SizeInK kilobytes in size, returning
the XMS handle in XmsHandle. Possible function results:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $A0 if all extended memory is allocated
  $A1 if all extended memory handles are in use

See also: 0016FreeExtMem
;
;-------------------------------------------------------------------
!TOPIC 16 FreeExtMem
!NOINDEX
function 0001OpXms.FreeExtMem(XmsHandle : Word) : Byte;

Free a previously allocated block of extended memory. XmsHandle is the XMS
handle returned by the previous call to 0015AllocateExtMem.
Possible function results:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $A2 if XmsHandle is invalid
  $AB if XmsHandle is currently locked

See also: 0015AllocateExtMem
;
;-------------------------------------------------------------------
!TOPIC 17 MoveExtMemBlock
!NOINDEX
function 0001OpXms.MoveExtMemBlock(BlockLength : LongInt;
                               SourceHandle : Word;
                               SourcePtr : ExtMemPtr;
                               DestHandle : Word;
                               DestPtr : ExtMemPtr) : Byte;

Move a block of memory. Intended primarily for moving data to and from
extended memory and conventional memory. Can also move memory from
extended to extended and conventional to conventional. BlockLength must
always be an even number. Memory areas may overlap ONLY if SourcePtr is at
a lower address than DestPtr. If SourceHandle is 0, then SourcePtr is
interpreted as a normal segment:offset dword pointer. If SourceHandle is
non-zero, then the SourcePtr is interpreted as a 32 bit linear offset into
the extended memory associated with SourceHandle. The same is true for
DestHandle and DestPtr. This routine does NOT require that the A20 line be
enabled. Extended memory blocks used as SourcePtr or DestPtr need not be
locked before calling this routine (although they may be locked). Possible
function results:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $82 if an A20 error occurs
  $A3 if SourceHandle is invalid
  $A4 if SourcePtr is invalid
  $A5 if DestHandle is invalid
  $A6 if DestPtr is invalid
  $A7 if BlockLen is invalid
  $A8 if SourcePtr and DestPtr contain an invalid overlap
  $A9 if a memory parity error occurs
;
;-------------------------------------------------------------------
!TOPIC 18 LockExtMemBlock
!NOINDEX
function 0001OpXms.LockExtMemBlock(XmsHandle : Word;
                               var LockedBlock : ExtMemPtr) : Byte;

Locks an extended memory block and returns its base address as a 32 bit
linear address. Locked extended memory blocks are guaranteed not to move.
The LockedBlock address is valid only while the block is locked. Locked
extended memory blocks should be unlocked as soon as possible. It is
not necessary to lock a block before calling 0017MoveExtMemBlock. A count of
the number of locks is maintained by the XMS memory manager and can be
retrieved with the 0020GetHandleInfo function. Possible function results:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $A2 if XmsHandle is invalid
  $AC if the block's lock count overflows
  $AD if the lock fails

See also:  0019UnlockExtMemBlock
;
;-------------------------------------------------------------------
!TOPIC 19 UnlockExtMemBlock
!NOINDEX
function 0001OpXms.UnlockExtMemBlock(XmsHandle : Word) : Byte;

Unlocks an extended memory block. Any 32 bit linear addresses in use
obtained by calling 0018LockExtMemBlock are invalid after
UnlockExtMemBlock is called. Possible function results:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $A2 if XmsHandle is invalid
  $AC if the block's lock count overflows
  $AA if the block is not locked

See also:  0018LockExtMemBlock
;
;-------------------------------------------------------------------
!TOPIC 20 GetHandleInfo
!NOINDEX
function 0001OpXms.GetHandleInfo(XmsHandle : Word;
                             var LockCount    : Byte;
                             var HandlesLeft  : Byte;
                             var BlockSizeInK : Word) : Byte;

Return information about an extended memory handle. The lock count for
this handle, the number of XMS handles left, and the size in kilobytes of
this handle are returned. To retrieve the 32 bit linear address of this
handle, you must call 0018LockExtMemBlock. Possible function results:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $A2 if XmsHandle is invalid
;
;-------------------------------------------------------------------
!TOPIC 21 ResizeExtMemBlock
!NOINDEX
function 0001OpXms.ResizeExtMemBlock(XmsHandle : Word;
                                 NewSizeInK : Word) : Byte;

Attempts to resize the memory block associated with XmsHandle. The
extended memory block must be unlocked. If the NewSizeInK is bigger than
the previous size, then all data is preserved. If it is smaller, then all
data beyond the end of the new block size is lost. Possible function results:

  $00 successful
  $80 if the function is not implemented
  $81 if a VDISK device is detected
  $A0 if all extended memory is allocated
  $A1 if all extended memory handles are in use
  $A2 if XmsHandle is invalid
  $AB if the block is locked

See also:  0015AllocateExtMem
;
;-------------------------------------------------------------------
!TOPIC 22 AllocUpperMemBlock
!NOINDEX
function 0001OpXms.AllocUpperMemBlock(SizeInParas : Word;
                                  var SegmentBase : Word;
                                  var Size        : Word) : Byte;

Allocates an upper memory block (UMB). If insufficient memory is available in
upper memory blocks, then the size of the largest free upper memory block is
returned in Size. If this functions succeeds, then SegmentBase contains
the segment of the allocated upper memory block. Upper memory blocks are
paragraph aligned (the offset is always 0). By definition, UMBs are located
below the 1 meg address boundary. Therefore the A20 line need not be enabled
to access the memory in a UMB. There are no restrictions on using this memory
in DOS calls or pointing ISRs into this memory.

This function is not implemented by most 286 XMS drivers. It is implemented by
most 386 products like QEMM and 386^MAX. Possible function results:

  $00 successful
  $80 if the function is not implemented
  $B0 if a smaller UMB is available
  $B1 if no UMBs are available

See also:  0023FreeUpperMemBlock
;
;-------------------------------------------------------------------
!TOPIC 23 FreeUpperMemBlock
!NOINDEX
function 0001OpXms.FreeUpperMemBlock(SegmentBase : Word) : Byte;

Frees a previously allocated upper memory block.
Possible function results:

  $00 successful
  $80 if the function is not implemented
  $82 if SegmentBase does not refer to a valid UMB

See also:  0022AllocUpperMemBlock
;
;-------------------------------------------------------------------
!TOPIC 24 XmsErrorString
!NOINDEX
function 0001OpXms.XmsErrorString(ErrorCode : Byte) : String;

Return a string indicating reason for the error.

See also:  0005Error codes

