[Back to MEMORY SWAG index]  [Back to Main SWAG index]  [Original]

{
JD3GTRCW.TRANSCOM@transcom.safb.af.mil (CONROY WILLIAM F)

I have seen numerous requests for XMS routines.  Here are some I have
written for a programming effort I headed.
Feel free to use in any way fit.
}

{$O+,F+}
UNIT XMSUnit;
{    Programmer:  Major William F. Conroy III                             }
{    Last Mod:    3/12/93                                                 }
{    Touched:     File date set to coorespond to baseline date            }
{                 for Computer Aided Aircrew Scheduling System            }
{                                                                         }
{ This unit is written to give access to the XMS memory Specification for }
{ the IBM PC.  Do not alter this unit without an excellent understanding  }
{ of the PC internal architecture, the Extended Memory Specification(XMS) }
{ and the Borland Inline Assembler.  For a much more in depth discussion  }
{ of the XMS memory standard and how to implement it on a PC class
  computer }
{ Refer to "Extending Dos" by Ray Duncan, Published by Addison Wesley     }

INTERFACE

TYPE
  PHandlePtrArray = ^THandlePtrArray;
  THandlePtrArray = ARRAY [1..10]OF WORD;
  {  This type definition is used by the graphics system as a way   }
  {  to dynamically allocate space to hold the handles required to  }
  {  access the extended memory.                                    }

  PXMSParamBlock  = ^TXMSParamBlock;
  TXMSParamBlock  = RECORD
    LengthOfBlock   : LONGINT;   { Size of block to move }
    SourceEMBHandle : WORD;
    { 0 if source is in conventional memory,       }
    { handle returned by AllocateEMB otherwise     }
    SourceOffset    : LONGINT;
    { if SourceEMBHandle= 0 SourceOffset contains  }
    { a far pointer in Intel standard format else  }
    { SourceOffset indicates offset from the base  }
    { of the block.                                }
    DestEMBHandle   : WORD;
    { 0 if source is in conventional memory,       }
    { handle returned by AllocateEMB otherwise     }
    DestOffset      : LONGINT;
    { if DestEMBHandle= 0 DestOffset contains      }
    { a far pointer in Intel standard format else  }
    { DestOffset indicates offset from the base    }
    { of the block.                                }
  END;
  { This type definition is used by the XMM memory manager for      }
  { block memory moves. As required by the xms specification.       }

VAR
  XMSExists : BOOLEAN;

  { Function AllocateEMB allocates an Extended Memory Block in Extended }
  { memory.  It requests the block via the Extended Memory Manager(XMM) }
  { It returns True if it was successful False otherwise.  If true, if  }
  { EMB_Handle will contain the Extended Memory Block Handle.  If       }
  {returning false, the errorcode is in the ErrorCode parameter.        }
FUNCTION AllocateEMB(VAR EMB_Handle, ParRequested, ErrorCode : WORD) : BOOLEAN;

  { Function FreeEMB releases an Extended Memory Block in Extended Memory }
  { allocated by the AllocateEMB function call.  It requests the XMM      }
  { remove the block.  It returns True if it was successful False         }
  { otherwise.  If true, if block was released correctly.  If returning   }
  { false, the errorcode is in the ErrorCode parameter.                   }
FUNCTION FreeEMB(VAR EMB_Handle, ErrorCode : WORD) : BOOLEAN;

  { Function MoveEMB allows memory tranfers between conventional and XMS  }
  { Memory.  This function requires a filled in TXMSParamBlock record.    }
  { It returns True if it was successful False otherwise.  If true, the   }
  { memory block was successfully moved.  If returning false, the         }
  { errorcode is in the ErrorCode parameter.                   }
FUNCTION MoveEMB(PParamBlock : PXMSParamBlock; VAR ErrorCode : WORD) : BOOLEAN;



IMPLEMENTATION

VAR
  XMMAddress        : POINTER;
  XMS_Version       : WORD;
  XMM_DriverVersion : WORD;
  HMA_Exists        : BOOLEAN;
  LastErrorCode     : WORD;


{---------------------------------------------------------------------------}
{                                                                         }
{                             Local Procedure                             }
{                            function XMSPresent                          }
{                                                                         }
{  This function return true if there is an Extended memory manager present }
{  in the system capable of supporting our XMS requests.  It uses a DOS   }
{  multiplexing interrupt request to determine if the driver signiture is }
{  present in the system.  This is the Microsoft recomended method of     }
{  determining the presence of this driver.                               }
{                                                                         }
{---------------------------------------------------------------------------}

FUNCTION XMSPresent : BOOLEAN; ASSEMBLER;

ASM
  MOV AX, 4300h                  { MultiPlexing interrupt request number  }
  INT 2fh                       { Dos Multiplexing Interrupt             }
  CMP AL, 80h                    { was the signature byte returned in AL  }
  JZ  @1                         { yes?, jump to @1                       }
  MOV AX, 00h                    { set false for return                   }
  JMP @2                        { unconditional jump to end of function  }
 @1:
  MOV AX, 01h                    { set True for return then fall thru to  }
                                { exit.                                  }
 @2:
END;

{------------------------------------------------------------------------- --}
{                                                                          }
{                            Local Procedure                               }
{                      function ReturnDriverAddress                        }
{                                                                          }
{  This function return true if it could determine the device driver entry  }
{  point.  This information is required to call any XMS functions. It uses  }
{  a DOS multiplexing interrupt request to get this address. This is the }
{  Microsoft recomended method of getting the base address of this driver.  }
{  This address is required to setup an indirect call to the driver by the  }
{  XMS functions.                                                           }
{                                                                           }
{---------------------------------------------------------------------------}
FUNCTION ReturnDriverAddress : POINTER; ASSEMBLER;
  {  This function returns the address for the XMM memory manager  }
  {  This value is required to later call the driver for XMS calls }

ASM
  MOV AX, 4310h                  { MultiPlexing interrupt request number }
  INT 2fh                       { Dos Multiplexing Interrupt            }
                                { Set Registers up for Return of Pointer }
  MOV AX, BX                     { Set Offset Value                      }
  MOV DX, ES                     { Set Segment Value                     }
END;

{-------------------------------------------------------------------------}
{                                                                         }
{                               Local Procedure                           }
{                            function GetXMSVersion                       }
{                                                                         }
{-------------------------------------------------------------------------}
FUNCTION GetXMSVersion(VAR XMS_Version, XMM_DriverVersion : WORD;
                       VAR HMA_Exists : BOOLEAN;
                       VAR ErrorCode : WORD) : BOOLEAN; ASSEMBLER;

  { This function loads the version numbers into the unit global }
  { variables. The information is coded in binary Coded Decimal. }

ASM
  XOR  AX, AX                     { set ax to zero                        }
  CALL XMMAddress               { indirect call to XMM driver           }
  CMP  AX, 00h                    { error set ?                           }
  JZ   @1                         { Jump error finish                     }

  LES  DI, XMS_Version            { Load XMS_Version Address into es:di   }
  MOV  ES:[DI],AX                { Load variable indirect                }

  LES  DI, XMM_DriverVersion      { Load XMM_DriverVrsn Address in es:di  }
  MOV  ES:[DI],BX                { Load variable Indirect                }

  LES  DI, HMA_Exists             { Load HMA_Exists Address in es:di      }
  MOV  ES:[DI],DX                { Load variable Indirect                }

  LES  DI,ErrorCode              { Load ErrorCode Address into es:di     }
  MOV  WORD PTR ES:[DI],00h      { Clear Error Code                      }
  MOV  AX, 01h                    { set function return to true           }
  JMP  @2                        { Jump to finish                        }

 @1:
  LES DI, ErrorCode              { Load error code address in es:di      }
  MOV WORD PTR ES:[DI],00h      { copy 0  into ErrorCode                }
 @2:
END;

{-------------------------------------------------------------------------}
{                                                                         }
{                             Exported Procedure                          }
{                            function AllocateEMB                         }
{                                                                         }
{                                                                         }
{    Function AllocateEMB allocates an Extended Memory Block in Extended  }
{    memory.  It requests the block via the Extended Memory Manager(XMM)  }
{    It returns True if it was successful False otherwise.  If true, if   }
{    EMB_Handle will contain the Extended Memory Block Handle.  If        }
{    returning false, the errorcode is in the ErrorCode parameter.        }
{                                                                         }
{-------------------------------------------------------------------------}
FUNCTION AllocateEMB(VAR EMB_Handle, ParRequested,
                         ErrorCode : WORD) : BOOLEAN; ASSEMBLER;

ASM
  MOV  AH, 09h                    { set ax for Allocate EMB call       }
  LES  DI, ParRequested           { load ParRequested address in es:di }
  MOV  DX, ES:[DI]                { copy parRequested value in DX      }
  CALL XMMAddress               { indirect call to XMM driver        }
  CMP  AX, 00h                    { error set ?                        }
  JZ   @1                         { Jump error finish                  }
  LES  DI, EMB_Handle             { load EMB_Handle in es:di           }
  MOV  ES:[DI],DX                { copy DX into EMB_Handle            }
  MOV  AX, 01h                    { Return True                        }
  LES  DI, ErrorCode              { Load error code address in es:di   }
  MOV  WORD PTR ES:[DI],00h      { copy 0  into ErrorCode             }
  JMP  @2                        { unconditional jump to finish       }
  { Error Finish                       }
 @1:
  LES  DI, ErrorCode              { load ErrorCode in es:di            }
  MOV  BYTE PTR ES:[DI],BL       { copy BL into ErrorCode             }
 @2:
END;

{-------------------------------------------------------------------------}
{                                                                         }
{                           Exported Procedure                            }
{                            function FreeEMB                             }
{                                                                         }
{  Function FreeEMB releases an Extended Memory Block in Extended Memory  }
{  allocated by the AllocateEMB function call.  It requests the XMM       }
{  remove the block.  It returns True if it was successful False          }
{  otherwise.  If true, if block was released correctly.  If returning    }
{  false, the errorcode is in the ErrorCode parameter.                    }
{                                                                         }
{-------------------------------------------------------------------------}
FUNCTION FreeEMB(VAR EMB_Handle, ErrorCode : WORD) : BOOLEAN; ASSEMBLER;

ASM
  XOR  AX, AX                     { clear AX to zero                 }
  MOV  AH, 0Ah                    { set ax for Free EMB call         }
  LES  DI, EMB_Handle             { load EMB_Handle address in es:di }
  MOV  DX, ES:[DI]                { load EMB_Handle value in DX      }
  CALL XMMAddress               { indirect call to XMM driver      }
  CMP  AX, 00h                    { error set ?                      }
  JZ   @1                         { Jump error finish                }
  MOV  AX, 01H                    { Set True                         }
  LES  DI, ErrorCode              { Load error code address in es:di }
  MOV  WORD PTR ES:[DI],00h      { copy 0  into ErrorCode           }
  JMP  @2                        { unconditional jump to finish     }
                                { Error Finish                     }
 @1:
  LES  DI, ErrorCode              { load ErrorCode in es:di          }
  MOV  BYTE PTR ES:[DI],BL       { copy BL into ErrorCode           }
 @2:
END;

{-------------------------------------------------------------------------}
{                                                                         }
{                           Exported Procedure                            }
{                            function MoveEMB                             }
{                                                                         }
{  Function MoveEMB allows memory tranfers between conventional and XMS   }
{  Memory.  This function requires a filled in TXMSParamBlock record.     }
{  It returns True if it was successful False otherwise.  If true, the    }
{  memory block was successfully moved.  If returning false, the          }
{  errorcode is in the ErrorCode parameter.                               }
{                                                                         }
{-------------------------------------------------------------------------}
FUNCTION MoveEMB(PParamBlock : PXMSParamBlock;
                 VAR ErrorCode : WORD) : BOOLEAN; ASSEMBLER;

ASM
  MOV  AX, DS                     { move DS to AX register                }
  MOV  ES, AX                     { move AX to ES register                }
  MOV  AH, 0Bh                    { set ax for Move EMB call              }
  PUSH DS                       { push DS to Stack                      }
  LDS  SI, PParamBlock            { load PParamBlock Address to ds:si     }
  MOV  DI, OFFSET XMMAddress      { move XMMAddress offset to di          }
  CALL DWORD PTR ES:[DI]        { indirect call to XMMdriver via es:di  }
  POP  DS                        { save TP's data segment                }
  CMP  AX, 00h                    { error set ?                           }
  JZ   @1                         { Jump error finish                     }
  MOV  AX, 01H                    { Set True                              }
  LES  DI, ErrorCode              { Load error code address in es:di      }
  MOV  WORD PTR ES:[DI],00h      { copy 0  into ErrorCode                }
  JMP  @2                        { unconditional jump to finish          }
                                { Error Finish                          }
 @1:
  LES  DI, ErrorCode              { load ErrorCode in es:di               }
  MOV  WORD PTR ES:[DI],AX       { Clear ErrorCode prior to load         }
  MOV  BYTE PTR ES:[DI],BL       { copy BL into ErrorCode                }
  MOV  AX, 01h                    { Return False                          }
 @2:
END;

BEGIN
  XMSExists := XMSPresent;
  IF XMSExists THEN
  BEGIN
    XMMAddress := ReturnDriverAddress;
    GetXMSVersion(XMS_Version, XMM_DriverVersion, HMA_Exists, LastErrorCode);
  END;
END.

[Back to MEMORY SWAG index]  [Back to Main SWAG index]  [Original]