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

{
³>anybody know how I can determine the size of the driver in
³>memory?
³ I would assume they take the Drivers name and search through the
³ Memory Control Blocks maintained by DOS and seeing if the driver
³ owns any of them.  But there might be an easier way.

There is.  An undocumented DOS function (52h) gives you the "list of
lists", which contains the first device driver in a linked list, which
you can then traverse.  (See Schulman's _Undocumented DOS_.)

Take the address of the device driver header, and look at the 0 offset
in the "segment" which is 1 segment address unit before the beginning
of the device driver header.  For example, if the device driver header
is at $1234:$0000, look at address $1233:0.  If the byte at that
address is "M", "Z", or "D", we have either a valid memory control
block header ("M" or "Z"), or a "device driver subheader" ("D") which
follows the same format.  In either case, the word at <segment>:0003
gives the number of 16-byte paragraphs used by that memory block;
multiply by 16 to get the size in bytes.  The following TP code should
illustrate this (*only* HexW is used from OPString; substitute your
own or any PD/Shareware hex conversion routine if you don't have OPro):
}

USES DOS, OPString;
TYPE
  PMCBhdr = ^TMCBhdr;
  TMCBhdr = RECORD
    Signature: CHAR;  { 'M', 'Z', or one of the valid 'subblock' letters}
    OwnerSeg:  WORD;  { Segment of "owner" of this block }
    SizeParas: WORD;  { Size of block, in 16-byte paragraphs }
    Unused:    ARRAY [1..3] OF CHAR;
    Name:      ARRAY [1..8] OF CHAR; {Name of owner program (DOS 4+)}
  END;
  PDevHdr = ^TDevHdr;
  TDevHdr = RECORD
    NextDriver: POINTER;              { Next driver in device chain }
    Attr:       WORD;                 { Driver attribute word }
    Strategy:   WORD;                 { Offset within this segment }
    Interrupt:  WORD;                 {   of the driver strategy & }
                                      {   interrupt routines.      }
    Name:       ARRAY [1..8] OF CHAR; { Device name for char devs; }
                 {   for block devices, first byte is # of logical }
                 {   devices associated with this driver, others   }
                 {   are unused.                                   }
  END;

PROCEDURE DisplayDeviceHeader( DevHdr: PDevHdr );
  VAR
    MCBptr: ^TMCBhdr;
    Size:   LONGINT;
  BEGIN
    { The line to be displayed will look something like this:      }
    { ssss:oooo dev_name mem_size owner_name                       }
    { The last two columns are displayed only under DOS 4+, and    }
    { only when the information is found -- may fail under 386^Max }
    Write( HexW( Seg( DevHdr^ ) ), ':', HexW( Ofs( DevHdr^ ) ), ' ' );

    { See if it's a character device.  If it is, then it has a name }
    { to display.                                                   }
    IF (DevHdr^.Attr AND $8000) <> 0 THEN
      Write( DevHdr^.Name:12, ' ' )
    ELSE  { Block device -- write # of logical drives }
      Write( Ord( DevHdr^.Name[1] ):3, ' drive(s) ' );

    { See if the DOS version supports the 'sub-MCBs' introduced for }
    { device drivers in the first MCB in DOS version 4, and/or the  }
    { Name field in the MCB introduced in v4.                       }
    IF Lo( DosVersion ) >= 4 THEN BEGIN
      MCBptr := Ptr( Seg( DevHdr^ ) - 1, 0 );

      { Check for MCB sig., and make sure the MCB "owns itself" }
      IF (MCBptr^.Signature IN ['M', 'Z', 'D']) AND
         (MCBptr^.OwnerSeg = Seg( DevHdr^ ) ) THEN BEGIN
        Size := MCBptr^.SizeParas * 16;
        Write( Size:6, MCBptr^.Name:9 );
      END; { IF MCB signature }
    END; { IF DosVersion }
    WriteLn;
  END; {DisplayDeviceHeader}

VAR
  Regs: REGISTERS;  CurDevice: PDevHdr;
BEGIN { main program }
  Regs.AH := $52;
  MSDos( Regs );
  IF Lo( DosVersion ) < 3 THEN                { Get first device in list; }
    CurDevice := Ptr( Regs.ES, Regs.BX+$17 )  { location varies by DOS    }
  ELSE                                        { version.                  }
    CurDevice := Ptr( Regs.ES, Regs.BX+$22 );
  REPEAT
    DisplayDeviceHeader( CurDevice );
    CurDevice := CurDevice^.NextDriver;
  UNTIL Ofs( CurDevice^ ) = $FFFF;
END.

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