📄 unit1.pas
字号:
{
for displaying the details of hard drives in
06/11/2000 Lynn McGuire written with many contributions from others, IDE drives only under Windows NT/2K and 9X, maybe SCSI drives later
translated by Wyfinger 14/08/2007, wyfinger@mail.ru
}
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
type
// GETVERSIONOUTPARAMS contains the data returned from the
// Get Driver Version function.GETVERSIONOUTPARAMS = record bVersion : BYTE; // Binary driver version. bRevision : BYTE; // Binary driver revision. bReserved : BYTE; // Not used. bIDEDeviceMap : BYTE; // Bit map of IDE devices. fCapabilities : DWORD; // Bit mask of driver capabilities. dwReserved : array[0..3] of DWORD; // For future use.end;
PGETVERSIONOUTPARAMS = ^GETVERSIONOUTPARAMS;
LPGETVERSIONOUTPARAMS = ^GETVERSIONOUTPARAMS;
// IDE registers
IDEREGS = record bFeaturesReg : BYTE; // Used for specifying SMART "commands". bSectorCountReg : BYTE; // IDE sector count register bSectorNumberReg : BYTE; // IDE sector number register bCylLowReg : BYTE; // IDE low order cylinder value bCylHighReg : BYTE; // IDE high order cylinder value bDriveHeadReg : BYTE; // IDE drive/head register bCommandReg : BYTE; // Actual IDE command. bReserved : BYTE; // reserved for future use. Must be zero.end;
PIDEREGS = ^IDEREGS;
LPIDEREGS = ^IDEREGS;
// SENDCMDINPARAMS contains the input parameters for the
// Send Command to Drive function.SENDCMDINPARAMS = record cBufferSize : DWORD; // Buffer size in bytes irDriveRegs : IDEREGS; // Structure with drive register values. bDriveNumber : BYTE; // Physical drive number to send // command to (0,1,2,3). bReserved : array[0..2] of BYTE; // Reserved for future expansion. dwReserved : array[0..3] of DWORD; // For future use. bBuffer : array[0..0] of BYTE; // Input buffer.end;
PSENDCMDINPARAMS = ^SENDCMDINPARAMS;
LPSENDCMDINPARAMS = ^SENDCMDINPARAMS;
// Status returned from driver
DRIVERSTATUS = record
bDriverError : BYTE; // Error code from driver, or 0 if no error. bIDEStatus : BYTE; // Contents of IDE Error register. // Only valid when bDriverError is SMART_IDE_ERROR. bReserved : array[0..1] of BYTE; // Reserved for future expansion. dwReserved : array[0..1] of DWORD; // Reserved for future expansion.end;
PDRIVERSTATUS = ^DRIVERSTATUS;
LPDRIVERSTATUS = ^DRIVERSTATUS;
// Structure returned by PhysicalDrive IOCTL for several commands
SENDCMDOUTPARAMS = record cBufferSize : DWORD; // Size of bBuffer in bytes DriverStatus : DRIVERSTATUS; // Driver status structure. bBuffer : array[0..0] of BYTE; // Buffer of arbitrary length in which to store the data read from the // drive.end;PSENDCMDOUTPARAMS = ^SENDCMDOUTPARAMS;LPSENDCMDOUTPARAMS = ^SENDCMDOUTPARAMS;USHORT = BYTE;// The following struct defines the interesting part of the IDENTIFY// buffer:IDSECTOR = record wGenConfig : USHORT; wNumCyls : USHORT; wReserved : USHORT; wNumHeads : USHORT; wBytesPerTrack : USHORT; wBytesPerSector : USHORT; wSectorsPerTrack : USHORT; wVendorUnique : array[0..2] of USHORT; sSerialNumber : array[0..19] of CHAR; wBufferType : USHORT; wBufferSize : USHORT; wECCSize : USHORT; sFirmwareRev : array[0..7] of CHAR; sModelNumber : array[0..39] of CHAR; wMoreVendorUnique : USHORT; wDoubleWordIO : USHORT; wCapabilities : USHORT; wReserved1 : USHORT; wPIOTiming : USHORT; wDMATiming : USHORT; wBS : USHORT; wNumCurrentCyls : USHORT; wNumCurrentHeads : USHORT; wNumCurrentSectorsPerTrack : USHORT; ulCurrentSectorCapacity : ULONG; wMultSectorStuff : USHORT; ulTotalAddressableSectors : ULONG; wSingleWordDMA : USHORT; wMultiWordDMA : USHORT; bReserved : array[0..127] of BYTE;end;PIDSECTOR = ^IDSECTOR;SRB_IO_CONTROL = record HeaderLength : ULONG; Signature : array[0..7] of UCHAR; Timeout : ULONG; ControlCode : ULONG; ReturnCode : ULONG ReturnCode; Length : ULONG;end;PSRB_IO_CONTROL = ^SRB_IO_CONTROL;TDWArray = array of DWORD;const
// Required to ensure correct PhysicalDrive IOCTL structure setup
MAX_IDE_DRIVES = 4;
// Max number of drives assuming primary/secondary, master/slave topology
IDENTIFY_BUFFER_SIZE = 512;
// IOCTL commands
DFP_GET_VERSION = $00074080;
DFP_SEND_DRIVE_COMMAND = $0007c084;
DFP_RECEIVE_DRIVE_DATA = $0007c088;
FILE_DEVICE_SCSI = $0000001b;
IOCTL_SCSI_MINIPORT_IDENTIFY = ((FILE_DEVICE_SCSI shl 16) + $0501);
IOCTL_SCSI_MINIPORT = $0004D008; // see NTDDSCSI.H for definition
// Bits returned in the fCapabilities member of GETVERSIONOUTPARAMS
CAP_IDE_ID_FUNCTION = 1; // ATA ID command supported CAP_IDE_ATAPI_ID = 2; // ATAPI ID command supported CAP_IDE_EXECUTE_SMART_FUNCTION = 4; // SMART commannds supported
// Valid values for the bCommandReg member of IDEREGS.
IDE_ATAPI_IDENTIFY = $0A1; // Returns ID sector for ATAPI. IDE_ATA_IDENTIFY = $0EC; // Returns ID sector for ATA.
var
// Define global buffers.
IdOutCmd : Integer = SizeOf(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1;
function DoIDENTIFY(hPhysicalDriveIOCTL: THandle; pSCIP: PSENDCMDINPARAMS;
pSCOP: PSENDCMDOUTPARAMS; bIDCmd, bDriveNum: BYTE;
lpcbBytesReturned: PDWORD): Boolean;
procedure PrintIdeInfo(drive: Integer; diskdata : array of DWORD);
implementation
{$R *.dfm}
function ReadPhysicalDriveInNT: Boolean;
var
done : Boolean;
drive : Integer;
driveName : PChar;
hPhysicalDriveIOCTL : THandle;
VersionParams : GETVERSIONOUTPARAMS;
cbBytesReturned : DWORD;
bIDCmd : BYTE;
scip : SENDCMDINPARAMS;
diskdata : array[0..255] of DWORD;
ijk : Integer;
pIdSector : USHORT;
//pOut :
begin
done := False;
drive := 0;
for drive := 0 to MAX_IDE_DRIVES-1 do
begin
hPhysicalDriveIOCTL := 0;
// Try to get a handle to PhysicalDrive IOCTL, report failure
// and exit if can't.
driveName := PChar(Format('\\.\PhysicalDrive%d', [drive]));
// Windows NT, Windows 2000, must have admin rights
hPhysicalDriveIOCTL := CreateFile(driveName, { dwDesiredAccess } GENERIC_READ or GENERIC_WRITE, { dwShareMode } FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if hPhysicalDriveIOCTL <> INVALID_HANDLE_VALUE then
begin
// Get the version, etc of PhysicalDrive IOCTL
FillChar(VersionParams, sizeof(VersionParams), 0);
if not DeviceIoControl(hPhysicalDriveIOCTL, DFP_GET_VERSION,
nil, 0, @VersionParams, sizeof(VersionParams), cbBytesReturned, nil) then
begin
ShowMessage('DFP_GET_VERSION failed for drive '+ driveName);
Exit;
end;
if VersionParams.bIDEDeviceMap > 0 then
begin
// Now, get the ID sector for all IDE devices in the system.
// If the device is ATAPI use the IDE_ATAPI_IDENTIFY command, // otherwise use the IDE_ATA_IDENTIFY command if Boolean(VersionParams.bIDEDeviceMap shr drive and $010) then bIDCmd := IDE_ATAPI_IDENTIFY else bIDCmd := IDE_ATA_IDENTIFY; FillChar(scip, sizeof(scip), 0);
FillChar(diskdata, Length(diskdata), 0);
if DoIDENTIFY(hPhysicalDriveIOCTL, @scip,
@diskdata, bIDCmd, drive, @cbBytesReturned) then
begin
ijk := 0;
//pIdSector := @PSENDCMDOUTPARAMS(IdOutCmd).bBuffer[0]; // ????
{for ijk := 0 to 256-1 do
diskdata[ijk] := PSENDCMDOUTPARAMS(IdOutCmd).bBuffer[ijk]; }
PrintIdeInfo(drive, diskdata);
done := True;
end;
end;
CloseHandle(hPhysicalDriveIOCTL);
end;
end;
end;
function DoIDENTIFY(hPhysicalDriveIOCTL: THandle; pSCIP: PSENDCMDINPARAMS;
pSCOP: PSENDCMDOUTPARAMS; bIDCmd, bDriveNum: BYTE;
lpcbBytesReturned: PDWORD): Boolean;var cbBytesReturned : DWORD;begin // Set up data structures for IDENTIFY command. pSCIP.cBufferSize := IDENTIFY_BUFFER_SIZE; pSCIP.irDriveRegs.bFeaturesReg := 0; pSCIP.irDriveRegs.bSectorCountReg := 1; pSCIP.irDriveRegs.bSectorNumberReg := 1; pSCIP.irDriveRegs.bCylLowReg := 0; pSCIP.irDriveRegs.bCylHighReg := 0; // Compute the drive number. pSCIP.irDriveRegs.bDriveHeadReg := $0A0 or ((bDriveNum and 1) shl 4); // The command can either be IDE identify or ATAPI identify. pSCIP.irDriveRegs.bCommandReg := bIDCmd; pSCIP.bDriveNumber := bDriveNum; pSCIP.cBufferSize := IDENTIFY_BUFFER_SIZE; Result := DeviceIoControl(hPhysicalDriveIOCTL, DFP_RECEIVE_DRIVE_DATA, pSCIP, sizeof(SENDCMDINPARAMS) - 1, pSCOP, sizeof(SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE - 1, cbBytesReturned, nil);end;
function ConvertToString(diskdata : Pointer; firstIndex,
lastIndex: Integer): string;
var
index : Integer;
ch : char;
begin
Result := ''; // each integer has two characters stored in it backwards for index := firstIndex to lastIndex do begin // get high byte for 1st character ch := Char(Integer(Pointer(Integer(diskdata)+2*index)^) shr 8); Result := Result + ch; ch := Char(Integer(Pointer(Integer(diskdata)+2*index)^)); Result := Result + ch; end; // end the string Result := Result + #0;end;
procedure printf(mask: string; Args: array of const);
begin
Form1.Memo1.Lines.Add(Format(mask, Args));
end;
procedure PrintIdeInfo(drive: Integer; diskdata : array of DWORD);
var
DriveType : string;
Header : string;
begin
// get drive type info if Boolean(diskdata[4] and $00080) then DriveType := 'Removable' else if Boolean(diskdata[4] and $00040) then DriveType := 'Fixed' else DriveType := 'Unknown'; case drive div 2 of 0: Header := 'Primary Controller - '; 1: Header := 'Secondary Controller - '; 2: Header := 'Tertiary Controller - '; 3: Header := 'Quaternary Controller - '; end; case drive mod 2 of 0: Header := Header + 'Master drive'; 1: Header := Header + 'Slave drive'; end; printf(Header, []); printf('Drive Model Number________________: %s', [ConvertToString (@diskdata, 35, 54)]); printf('Drive Serial Number_______________: %s', [ConvertToString (@diskdata, 18, 27)]); printf('Drive Controller Revision Number__: %s', [ConvertToString (@diskdata, 31, 34)]); printf('Controller Buffer Size on Drive___: %u bytes', [Word(Pointer(Integer(@diskdata)+58)^) * 512]); printf('Drive Type________________________: %s', [DriveType]); printf('Physical Geometry: '+ '%u Cylinders, %u Heads, %u Sectors per track', [Word(Pointer(Integer(@diskdata)+18)^), Word(Pointer(Integer(@diskdata)+22)^), Word(Pointer(Integer(@diskdata)+28)^)]); printf(' ', []);end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Lines.Clear;
ReadPhysicalDriveInNT;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -