Category : Files from Magazines
Archive   : ITP9011.ZIP
Filename : EMS.PAS

 
Output of file : EMS.PAS contained in archive : ITP9011.ZIP
{*************************** EMS.PAS ************************
*** Demonstrate calls to Extended memory manager ***
************************************************************}

USES

Crt,Dos;

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

TYPE
PtrType = RECORD {Define a pointer record }
Offset : Word; { type so we can access the}
Segment : Word { individual pointer fields}
END;
DeviceName = ARRAY[1..8] OF Char; {Defined to test device Name}

CONST

EmsInt = $67; {EMS Interrupt number }
IOCtlFunc = $44; {IOCtl DOS Function number }
PageLen = 16384; {Length of memory page }
MsgLen = 16; {Message len plus len byte }
MsgsPerPage = PageLen DIV MsgLen; {Number of messages in page }
NumMsgs = 5000; {Number EMS messages }

{*** Emm functions ***}

GetStatus = $40;
GetPageFrameAddr = $41;
GetUnallocPages = $42;
GetEmmVersion = $46;
AllocatePages = $43;
MapHandlePage = $44;
DeallocatePages = $45;

VAR
P0, P1, P2, P3 : Pointer; {Pointers to physical pages }
EmmHandle : Integer; {Handle for EMM allocated pages }
Tmp : FILE; {Temp file to test if EMM exists}
MsgBuf : Pointer; {Pointer into mapped memory }
Buff : String[15]; {Buffer for msg stored in EM }
I : Integer; {Dummy variable }
EmmRegs : Registers; {Registers for interrupt calls }
Page,Index : Integer; {Used to address page frame }
EmsVector : Pointer; {EMM address from Int $67 }
StrNum : String[4]; {Holds record # for EMM msg }

{******** Function to convert word value to Hex string *********}

FUNCTION Hex(IntNbr : Word): String;
CONST
HexDigit :ARRAY[0..15] OF Char = '0123456789ABCDEF';
VAR
S : String[2]; {Temporary String}
TempByte : Byte;
BEGIN
TempByte := Hi(IntNbr); {Convert upper nibble}
S := HexDigit[TempByte DIV 16] +
HexDigit[TempByte MOD 16];
TempByte := Lo(IntNbr); {Convert lower nibble}
Hex := S + HexDigit[TempByte DIV 16] +
HexDigit[TempByte MOD 16];
END;

{******** Create a string that contains a pointer value ********}

FUNCTION PrintPointer(P : Pointer): String;

BEGIN
PrintPointer := Hex(PtrType(P).Segment) + ':' +
Hex(PtrType(P).Offset);
END;

{*********** Print the EMM Status to the screen ****************}

PROCEDURE EmmPrintStatus(Status: Byte);

CONST
EmmStatus : ARRAY [$80..$8F] OF String =
('Driver malfunction',
'Hardware malfunction',
'',
'Bad Handle',
'Undefined FUNCTION',
'No free handles',
'Page map context Error',
'Insufficient memory pages',
'Not enough free pages',
'Can''t allocate zero (0) pages',
'Logical page out of range',
'Physical page out of range',
'Page map hardware RAM full',
'Page map already has a Handle',
'Page map not mapped to Handle',
'Undefined subfunction number');

BEGIN
CASE Status OF
0 : WriteLn('Ok');
$80..$8F : WriteLn('EMM: ',EmmStatus[Status])
ELSE WriteLn('EMM: Unknown status = $',Hex(Status))
END
END;



{******** Generic procedure to call the EMM interrupt **********}

PROCEDURE CallEmm(EmmFunction : Byte; VAR R : Registers);

BEGIN
R.AH := EmmFunction;
Intr(EmsInt,R);
IF (R.AH <> 0) THEN BEGIN
EmmPrintStatus(EmmRegs.AH);
Halt(EmmRegs.AH)
END
END;

{****************** Main Program *****************************}


BEGIN

ClrScr;

{$DEFINE CheckFile} {Undefine to test second method}

{$IFDEF CheckFile} {Check EMM driver - Method 1}

GetIntVec(EmsInt,EmsVector);
PtrType(EmsVector).Offset := 10;
IF (DeviceName(EmsVector^) <> 'EMMXXXX0') THEN BEGIN
WriteLn('No EMM driver present');
Halt(1)
END;

{$ELSE} {Check EMM driver - Method 2}

{***** Determine if EMM is installed by opening EMMXXXX0 *****}

{$I-}
Assign(Tmp,'EMMXXXX0');
Reset(Tmp);
{$I+}
IF (IOResult <> 0) THEN BEGIN {Opened file without error?}
WriteLn('No EMM driver present');
WriteLn('IO error #',IOResult:3);
Halt(1)
END;

EmmRegs.AH := IOCtlFun {Call IOCtl function to }
EmmRegs.AL := $00; { test whether EMMXXXX0 is}
EmmRegs.BX := FileRec(Tmp).Handle; { a file or a device }

MsDos(EmmRegs);
Close(Tmp);

IF (EmmRegs.Flags AND 1) = 0 THEN {Call successfull}
IF (EmmRegs.DX AND $80) = $80 THEN {Handle is for a device}
WriteLn('Handle refers to a device')
ELSE BEGIN
WriteLn('Handle refers to a FILE');
WriteLn('Unable to contact EMM driver if present');
Halt(1)
END
ELSE BEGIN {Call unsuccessfull}
CASE EmmRegs.AX OF
1 : WriteLn('Invalid IOCTL subfunction');
5 : WriteLn('Access to IOCTL denied');
6 : WriteLn('Invalid Handle')
ELSE WriteLn('Unknown error # ',Hex(EmmRegs.AX))
END;
WriteLn('Unable to contact EMM driver');
Halt(1)
END;


{$ENDIF}

WriteLn('EMM driver present');

{******** Print the current status of the EMM driver ********}

CallEmm(GetStatus,EmmRegs);
WriteLn('EMM Status Ok');

{******** Print the version number of EMM driver *************}

CallEmm(GetEmmVersion,EmmRegs);

WriteLn('EMS driver version = ',
(EmmRegs.AL SHR 4):1,'.',
(EmmRegs.AL AND $0F):1);

IF EmmRegs.AL < $32 THEN BEGIN
WriteLn('Error - EMM is version is earlier than 3.2');
Halt(1)
END;

{***** Print the page frame & physical window addresses ******}

CallEmm(GetPageFrameAddr,EmmRegs);

PtrType(P0).Segment := EmmRegs.BX; { Window 0 -> P0 = BX:0000 }
PtrType(P0).Offset := $0;
PtrType(P1).Segment := EmmRegs.BX; { Window 1 -> P1 = BX:4000 }
PtrType(P1).Offset := $4000;
PtrType(P2).Segment := EmmRegs.BX; { Window 2 -> P2 = BX:8000 }
PtrType(P2).Offset := $8000;
PtrType(P3).Segment := EmmRegs.BX; { Window 3 -> P3 = BX:C000 }
PtrType(P3).Offset := $C000;

WriteLn('Page frame segment address = ',Hex(EmmRegs.BX));
WriteLn('Physical page 0 address = ',PrintPointer(P0));
WriteLn('Physical page 1 address = ',PrintPointer(P1));
WriteLn('Physical page 2 address = ',PrintPointer(P2));
WriteLn('Physical page 3 address = ',PrintPointer(P3));

{***** Print # of unallocated pages and total # of pages *****}

CallEmm(GetUnallocPages,EmmRegs);
WriteLn('Total EMS pages = ',EmmRegs.DX:4);
WriteLn('Unused EMS pages = ',EmmRegs.BX:4);

{***** Allocate some pages of expanded memory *****}

EmmRegs.BX := (NumMsgs + MsgsPerPage) DIV MsgsPerPage;
CallEmm(AllocatePages,EmmRegs);
WriteLn('Allocated ',EmmRegs.BX,
' pages to handle # ',EmmRegs.DX);
EmmHandle := EmmRegs.DX;

{***** Load EMS RAM with data *****}

MsgBuf := P0; {* Set Message pointer to Page 0 *}

FOR I := 0 TO NumMsgs-1 DO BEGIN
Str(I:4,StrNum); {Create msg string }
Buff := ' EMS msg # ' + StrNum;
IF (I MOD 100) = 0 THEN Write('.'); {Dsp status on screen}
Page := I DIV MsgsPerPage;
Index := I MOD MsgsPerPage;
PtrType(MsgBuf).Offset := Index * SizeOf(Buff);

{**** Map indicated logical page into physical page 0 ****}

EmmRegs.AH := MapHandlePage; {Map EMS page cmd }
EmmRegs.BX := Page; {Logical page number }
EmmRegs.AL := 0; {Physical page 0 }
EmmRegs.DX := EmmHandle; {EMM RAM handle }

Intr(EmsInt,EmmRegs);

IF EmmRegs.AH = 0 THEN
Move(Buff[0],MsgBuf^,SizeOf(Buff)) {Set message into mem}
ELSE BEGIN
EmmPrintStatus(EmmRegs.AH);
I := NumMsgs
END
END;

WriteLn;

{****** Allow user to access any message in the buffer ******}

I := $FF;
WHILE I <> -1 DO BEGIN
MsgBuf := P3; {Set MsgBuf to physical page 3}
Write('Enter message # to retrieve, or -1 to quit: ');
ReadLn(I);
IF (I >= 0) AND (I < NumMsgs) THEN BEGIN
Page := I DIV MsgsPerPage;
Index := I MOD MsgsPerPage;

{**** Map indicated page into physical page 3 ****}

EmmRegs.AH := MapHandlePage; {Map EMM page command}
EmmRegs.BX := Page; {Logical page number }
EmmRegs.AL := 3; {Physical page 3 }
EmmRegs.DX := EmmHandle; {EMM RAM handle }

Intr(EmsInt,EmmRegs);

IF EmmRegs.AH = 0 THEN BEGIN
Inc(PtrType(MsgBuf).Offset,Index * SizeOf(Buff));
Move(MsgBuf^,Buff[0],SizeOf(Buff));
Write('Retrieved message -> ',Buff);

WriteLn(' from page #',Page:2,' Index',Index:5);
END
ELSE BEGIN
EmmPrintStatus(EmmRegs.AH);
I := -1;
END
END
END;

{***** Free the EMS RAM back to the EMM driver ****}

EmmRegs.DX := EmmHandle;
CallEmm(DeallocatePages,EmmRegs);
WriteLn('Released all memory for handle ',EmmRegs.DX:2);
END.


  3 Responses to “Category : Files from Magazines
Archive   : ITP9011.ZIP
Filename : EMS.PAS

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/