Contributor: KIM KOKKONEN             

{$R-,S-}

{PEXTEND
 ------------------------------------------------------------------
 This unit provides a single function, DpmiExtendHandles, for
 extending the file handle table for DOS protected mode applications
 under Borland Pascal 7.0.

 The standard DOS call for this purpose (AH = $67) does odd things to
 DOS memory when run from a BP7 pmode program. If you Exec from a
 program that has extended the handle table, DOS memory will be
 fragmented, leaving a stranded block of almost 64K at the top of DOS
 memory. The function implemented here avoids this problem.

 If you haven't used an ExtendHandles function before, note that you
 cannot get more handles than the FILES= statement in CONFIG.SYS
 allows. (Other utilities such as FILES.COM provided with QEMM do the
 same thing.) However, even if you have FILES=255, any single program
 cannot open more than 20 files (and DOS uses up 5 of those) unless
 you use a routine like DpmiExtendHandles. This routine allows up to
 255 open files as long as the FILES= statement provides for them.

 This code works only for DOS 3.0 or later. Since (to my knowledge)
 DPMI cannot be used with earlier versions of DOS, the code doesn't
 check the DOS version.

 Don't call this function more than once in the same program.

 Version 1.0,
   Written 12/15/92, Kim Kokkonen, TurboPower Software
}

{$IFNDEF DPMI}
  !! Error: this unit for DPMI applications only
{$ENDIF}

unit PExtend;
  {-Extend handle table for DOS protected mode applications}

interface

function DpmiExtendHandles(Handles : Byte) : Word;
  {-Extend handle table to Handles size.
    Returns 0 for success, else a DOS error code.
    Does nothing and returns 0 if Handles <= 20.}

implementation

uses
  WinApi;

function DpmiExtendHandles(Handles : Byte) : Word;
type
  DosMemRec =
    record
      Sele, Segm : Word;
    end;
var
  OldTable : Pointer;
  OldSize : Word;
  NewTable : Pointer;
  DosMem : DosMemRec;
begin
  DpmiExtendHandles := 0;
  if Handles <= 20 then
    Exit;

  {Allocate new table area in DOS memory}
  LongInt(DosMem) := GlobalDosAlloc(Handles);
  if LongInt(DosMem) = 0 then begin
    DpmiExtendHandles := 8;
    Exit;
  end;

  {Initialize new table with closed handles}
  NewTable := Ptr(DosMem.Sele, 0);
  FillChar(NewTable^, Handles, $FF);

  {Copy old table to new. Assume old table in PrefixSeg}
  OldTable := Ptr(PrefixSeg, MemW[PrefixSeg:$34]);
  OldSize := Mem[PrefixSeg:$32];
  move(OldTable^, NewTable^, OldSize);

  {Set new handle table size and pointer}
  Mem[PrefixSeg:$32] := Handles;
  MemW[PrefixSeg:$34] := 0;
  MemW[PrefixSeg:$36] := DosMem.Segm;
end;

end.