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

    {
    With this unit, it doesn't matter if the overlay is separate,
    or tacked onto the end of the .EXE file -- the program will
    run either way.

    As written, this unit also uses OVERXMS, a PD unit written
    Wilbert Van Leijen.  Floating around the BBS's as OVERXMS.ZIP
    You may delete the references to XMS.
    The XMS stuff is in there because the program I copied this
    code from will run on a 486 and just about all of the college
    machines have XMS memory -- few if any have EMS. }

    {$A-,B+,D-,F+,I-,L-,N-,O-,Q+,R-,S-,V-}

    UNIT RVOVRLAY;

    { This unit starts the overlay manager }

    INTERFACE
    Const
      ovrNoXMSDriver = -7;   { No XMS driver installed }
      ovrNoXMSMemory = -8;   { Insufficient XMS memory available }

    IMPLEMENTATION

    USES DOS, OVERLAY;

    { OVERXMS - Loads overlays in XMS.
      Assembly-language portion written by Wilbert van Leijen }
    Procedure OvrInitXMS; External;
    {$L OVERXMS.OBJ }

    Function Exist(Filename:string):boolean;
    {returns true if file exists}

    var Inf: SearchRec;

    begin
      FindFirst(Filename,AnyFile,Inf);
      Exist := (DOSError = 0);
    end;  {Func Exist}

    Procedure S_Write (Msg : string);

    BEGIN  {Dirty trick to generate less code}
      Write (msg);
    END;

    Procedure WriteOvrErrMsg;

    VAR
      garbage:char;

    BEGIN
      WRITE ('Overlay error: ',OvrResult,'  ');
      IF (OvrResult = ovrOk) THEN S_WRITE ('Ok - No error');
      IF (OvrResult = ovrError) THEN S_WRITE ('Missing Overlay error');
      IF (OvrResult = ovrNotFound) THEN S_WRITE ('Overlay file not found');
      IF (OvrResult = ovrNoMemory) THEN S_WRITE ('No Memory for overlays');
      IF (OvrResult = ovrIOError) THEN S_WRITE ('Overlay IO Error');
      IF (OvrResult = ovrNoEMSDriver) THEN S_WRITE ('No EMS Driver');
      IF (OvrResult = ovrNoEMSMemory) THEN S_WRITE ('No EMS Memory');
      IF (OvrResult = ovrNoXMSDriver) THEN S_WRITE ('No XMS Driver');
      IF (OvrResult = ovrNoXMSMemory) THEN S_WRITE ('No XMS Memory');
      S_WRITE (^M^J);
      read (garbage);
      If OvrResult <> OvrOK THEN HALT (98);
    END;  { Procedure WriteOvrErrMsg }

    BEGIN      { main }

      IF (lo(DosVersion) < 3) THEN
        BEGIN
          WriteLn ('You are using DOS version ',Lo(DosVersion),
                   '.',Hi(DosVersion));
          Writeln ('Mulesoft Revenge requires DOS v3.0 or greater.');
          HALT (99);
        END;

      { Start overlay manager and assume that overlay is in
        the .EXE file.  If not found in .EXE file, assume the
        overlay file is separate from the .EXE file. }

      OVRINIT (paramstr(0));

      If (OvrResult = ovrError) THEN  { Overlay not at end of .EXE file }
        OVRINIT (copy(paramstr(0), 1, Length(paramstr(0))-3) + 'OVR');
      IF (OvrResult <> OvrOk) THEN
          WriteOvrErrMsg
      ELSE     { Try to load the overlay into XMS memory }
        BEGIN
          OvrInitXms;
          IF (OvrResult <> OvrOk) THEN
            OvrInitEms;
        END;
    END.

    {------------------------- snip, snip ----------------------------}

       Here is the .OBJ file that goes with this file ...
       you will need XX3402 o decode this output:

       Cut this out to a file named OVERXMS.XX.
       Execute XX3402 d OVERXMS.XX

       You will then get the file OVERXMS.OBJ to compile this unit

    *XX3402-000913-020294--72--85-48736-----OVERXMS.OBJ--1-OF--1
    U+o+0qxqNL7sPLAiEJBBFMUU++++53FpQa7j623nQqJhMalZQW+UJaJmQqZjPW+n9X8NW-A+
    ECafC26Q0qxqNL7sPLAiEJBBnMU1+21dH7M0++-cW+A+E84IZUM+-2F-J234a+Q+G-c++U2-
    ytM4++F1HoF3FNU5+0Wi+EA-+MKAJ++7I373FYZMIoJ5++V3K2ZII37DEk+7HpNGIYJHJIlI
    ++hDJZ71HoF3H2ZHJ++AHpNGF2xHG23CF2l3++dDJZ76FI3EHp75++dDJZ7GFI32EZJ4+0OE
    2E+++UdDJZ77HYZIK2pHCE2+xcU2+20W+N4UgU20++093VU+h+fz5U++l+M2+8A++6k4+U19
    Aw+nocgS+++15U++UwAEXgAa+kM6+6DG+0O95Us+0xhptfg+-DTnYY8o0TwS+++9k5E2WFMM
    +ABJWymCFUMacEU+ckU+Aw0X0U0V4+0X1++acFM+cks+7e2M+8AE+1D+cl6+clE+7e2E+8AK
    +9E9jUU+zls+++j+R+F6ukGEiDnzLQc0+0O93UU+xw6-+5E4EWPz-UU+WFM6+1D+ckc+ckk+
    cks+cE++cl++cFU+cl6+WHsI+6YS3U0o0vs6+DwS+++1ycDH++j+R+9skzb1JMjgcE++AwY1
    -U++-F++Xg-EEGOV1U+9k5LhAxgnzkRFcE++7eAE+0O75VU+7cYy3U-HJkM4zls+++RTKmP5
    -V++++1rq566u4jzQUBNsgy9tJr1Aw+v-U++REF6uqOEi+-1nGwwU5E4iDbzupSEi--1nGy7
    5U++X+M0+CWmzbI4iDXzunyEu5PzQl093VU+h+fz5U++iDnzumeEWls++9EynG55-U++HU0A
    1U6+l+M++8A2+6k4-U15-U++++0A1U6+Aw0X++19RdnW+AE0J+5203E-l+lI+QED-U20l-A4
    +E925+M--AEU-U2-l2BI+QF9J+52KJE-l3tI+QFVJ+52N3E-l4hI+QFmJ+52RpE-l5dI+QG-
    J+52VZE-l6dI+QGiJ+52gpE-l9NI+QGtJ+52j+M--gGzJ+52kZE-lAJI+QH7J+52nJE-lB7I
    +QHKJ+52uEM--AHj-U2-lEQ4+EP35EM--wIx-U23lJhI+QJTJ+53QpE-lLZI+QK1-U23lMg4
    +ET3XJE0lN24+ET3ZEM-+gKMJ+53b3E-lO+4+E93cZE0lOM4+E93ekM-+z88+U++R+++
    ***** END OF BLOCK 1 *****

    {---------------------         OVERXMS.ASM   --------------------- }
    {                          NEED MASM,TASM to compile               }

    TITLE Turbo Pascal XMS support for loading overlays - By Wilbert van Leijen
    PAGE 65, 132
    LOCALS @@

    Data       SEGMENT Word Public
               ASSUME  DS:Data

    ;  XMS block move record

    XmsMoveType STRUC
               BlkSize     DD    ?
               SrcHandle   DW    ?
               SrcOffset   DD    ?
               DestHandle  DW    ?
               DestOffset  DD    ?
    XmsMoveType ENDS

    ;  TP overlay manager record

    OvrHeader  STRUC
               ReturnAddr  DD    ?         ; Virtual return address
               FileOfs     DD    ?         ; Offset into overlay file
               CodeSize    DW    ?         ; Size of overlay
               FixupSize   DW    ?         ; Size of fixup table
               EntryPts    DW    ?         ; Number of procedures
               CodeListNext DW   ?         ; Segment of next overlay
               LoadSeg     DW    ?         ; Start segment in memory
               Reprieved   DW    ?         ; Loaded in memory flag
               LoadListNext DW   ?         ; Segment of next in load list
               XmsOffset   DD    ?         ; Offset into allocated XMS block
               UserData    DW    3 DUP(?)
    OvrHeader  ENDS

    XmsDriver  DD      ?                   ; Entry point of XMS driver
    ExitSave   DD      ?                   ; Pointer to previous exit proc
    XmsMove    XmsMoveType <>
    OvrXmsHandle DW    ?                   ; Returned by XMS driver

               Extrn   PrefixSeg : Word
               Extrn   ExitProc : DWord
               Extrn   OvrResult : Word
               Extrn   OvrCodeList : Word
               Extrn   OvrDosHandle : Word
               Extrn   OvrHeapOrg : Word
               Extrn   OvrReadBuf : DWord
    Data       ENDS

    Code       SEGMENT Byte Public
               ASSUME  CS:Code
               Public  OvrInitXMS

    ovrIOError     EQU     -4
    ovrNoXMSDriver EQU     -7
    ovrNoXMSMemory EQU     -8

    OvrXmsExit PROC

    ; Release handle and XMS memory

            MOV    DX, [OvrXmsHandle]
            MOV    AH, 10
            CALL   [XmsDriver]

    ; Restore pointer to previous exit procedure

            LES    AX, [ExitSave]
            MOV    Word Ptr [ExitProc], AX
            MOV    Word Ptr [ExitProc+2], ES
            RETF
    OvrXmsExit ENDP

    AllocateXms PROC

    ;  Determine the size of the XMS block to allocate:
    ;  Walk the CodeListNext chain
    ;  Store the total codesize in DX:AX

            XOR    AX, AX
            XOR    DX, DX
            MOV    BX, [OvrCodeList]
    @@1:    ADD    BX, [PrefixSeg]
            ADD    BX, 10h
            MOV    ES, BX
            ADD    AX, ES:[OvrHeader.CodeSize]
            ADC    DX, 0
            MOV    BX, ES:[OvrHeader.CodeListNext]
            OR     BX, BX
            JNZ    @@1

    ;  Obtain number of kilobytes to allocate

            MOV    BX, 1024
            DIV    BX
            XCHG   DX, AX
            INC    DX

    ;  Allocate the block

            MOV    AH, 9
            CALL   [XmsDriver]
            OR     AX, AX
            JZ     @@2
            MOV    [OvrXmsHandle], DX
    @@2:    RETN
    AllocateXms ENDP

    ;  Function XmsReadFunc(OvrSeg : Word) : Integer; Far;

    XmsReadFunc PROC

    ;  Swap the code from XMS to the heap

            PUSH   BP
            MOV    BP, SP
            MOV    ES, [BP+6]
            MOV    AX, ES:[OvrHeader.CodeSize]
            MOV    Word Ptr [XmsMove.BlkSize], AX
            XOR    AX, AX
            MOV    Word Ptr [XmsMove.BlkSize+2], AX
            MOV    AX, [OvrXmsHandle]
            MOV    [XmsMove.SrcHandle], AX
            MOV    AX, Word Ptr ES:[OvrHeader.XmsOffset]
            MOV    Word Ptr [XmsMove.SrcOffset], AX
            MOV    AX, Word Ptr ES:[OvrHeader.XmsOffset+2]
            MOV    Word Ptr [XmsMove.SrcOffset+2], AX
            XOR    AX, AX
            MOV    [XmsMove.DestHandle], AX
            MOV    Word Ptr [XmsMove.DestOffset], AX
            MOV    AX, ES:[OvrHeader.LoadSeg]
            MOV    Word Ptr [XmsMove.DestOffset+2], AX
            MOV    AH, 11
            LEA    SI, XmsMove
            CALL   [XmsDriver]
            OR     AX, AX
            JZ     @@1
            DEC    AX
            JMP    @@2

    @@1:    MOV    AX, ovrIOError
    @@2:    POP    BP
            RETF   2
    XmsReadFunc ENDP

    ;  Copy an overlaid unit from the heap to XMS
    ;  If successful, carry flag is cleared
    ;  In/Out:
    ;    BX:DI = offset into XMS memory block

    CopyUnitToXms PROC

    ;  XMS requires that an even number of bytes is moved

            MOV    DX, ES:[OvrHeader.CodeSize]
            TEST   DX, 1
            JZ     @@1
            INC    DX
            INC    ES:[OvrHeader.CodeSize]

    ;  Get the fields of the XMS block move structure

    @@1:    MOV    Word Ptr [XmsMove.BlkSize], DX
            XOR    AX, AX
            MOV    Word Ptr [XmsMove.BlkSize+2], AX
            MOV    [XmsMove.SrcHandle], AX
            MOV    Word Ptr [XmsMove.SrcOffset], AX
            MOV    AX, [OvrHeapOrg]
            MOV    Word Ptr [XmsMove.SrcOffset+2], AX
            MOV    AX, [OvrXmsHandle]
            MOV    [XmsMove.DestHandle], AX
            MOV    Word Ptr [XmsMove.DestOffset], DI
            MOV    Word Ptr [XmsMove.DestOffset+2], BX
            MOV    AH, 11
            LEA    SI, XmsMove
            CALL   [XmsDriver]

    ;  Bump code size

            ADD    DI, DX
            ADC    BX, 0

    ;  Check return code from XMS driver

            OR     AX, AX
            JZ     @@2
            CLC
            RETN

    @@2:    STC
            RETN
    CopyUnitToXms ENDP

    OvrXmsLoad PROC
            PUSH   BP
            MOV    BP, SP

    ;  Walk the CodeList chain
    ;  First segment is PrefixSeg+10h+OvrCodeList
    ;  Push each element of overlaid unit list on the stack
    ;  Keep the size of the linked list in CX

            MOV    AX, [OvrCodeList]
            XOR    CX, CX
    @@1:    ADD    AX, [PrefixSeg]
            ADD    AX, 10h
            MOV    ES, AX
            PUSH   AX
            INC    CX
            MOV    AX, ES:[OvrHeader.CodeListNext]
            OR     AX, AX
            JNZ    @@1

    ;  Loop:
    ;    Pop each element of the overlaid unit list from the stack

            XOR    BX, BX
            XOR    DI, DI
    @@2:    POP    ES
            PUSH   CX
            MOV    AX, [OvrHeapOrg]
            MOV    ES:[OvrHeader.LoadSeg], AX
            MOV    Word Ptr ES:[OvrHeader.XmsOffset+2], BX
            MOV    Word Ptr ES:[OvrHeader.XmsOffset], DI

    ;  Load overlay from disk

            PUSH   BX
            PUSH   DI
            PUSH   ES
            PUSH   ES
            CALL   [OvrReadBuf]
            POP    ES
            POP    DI
            POP    BX

    ;  Flag unit as 'unloaded'; check return code

            MOV    ES:[OvrHeader.LoadSeg], 0
            NEG    AX
            JC     @@3

            CALL   CopyUnitToXms
            JC     @@3

            POP    CX
            LOOP   @@2

    @@3:    MOV    SP, BP
            POP    BP
            RETN
    OvrXMSLoad ENDP

    OvrInitXMS PROC

    ;  Make sure the file's been opened

            XOR    AX, AX
            CMP    AX, [OvrDOSHandle]
            JNE    @@1
            DEC    AX                      ; ovrError
            JMP    @@5

    ;  Check presence of XMS driver

    @@1:    MOV    AX, 4300h
            INT    2Fh
            CMP    AL, 80h
            JE     @@2
            MOV    AX, ovrNoXmsDriver
            JMP    @@5

    ;  Get XMS driver's entry point

    @@2:    MOV    AX, 4310h
            INT    2Fh
            MOV    Word Ptr [XmsDriver], BX
            MOV    Word Ptr [XmsDriver+2], ES
            CALL   AllocateXms
            JNZ    @@3
            MOV    AX, ovrNoXMSMemory
            JMP    @@5

    ;  Load the overlay into XMS

    @@3:    CALL   OvrXmsLoad
            JNC    @@4

    ;  An error occurred.  Release handle and XMS memory

            MOV    DX, [OvrXmsHandle]
            MOV    AH, 10
            CALL   [XmsDriver]
            MOV    AX, ovrIOError
            JMP    @@5

    ;  Close file

    @@4:    MOV    BX, [OvrDOSHandle]
            MOV    AH, 3Eh
            INT    21h

    ;  OvrReadBuf := XmsReadFunc

            MOV    Word Ptr [OvrReadBuf], Offset XmsReadFunc
            MOV    Word Ptr [OvrReadBuf+2], CS

    ;  ExitSave := ExitProc
    ;  ExitProc := OvrXmsExit

            LES    AX, [ExitProc]
            MOV    Word Ptr [ExitSave], AX
            MOV    Word Ptr [ExitSave+2], ES
            MOV    Word Ptr [ExitProc], Offset OvrXmsExit
            MOV    Word Ptr [ExitProc+2], CS

    ;  Return result of initialisation

            XOR    AX, AX
    @@5:    MOV    [OvrResult], AX
            RETF
    OvrInitXMS ENDP

    Code       ENDS
               END

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