Unit HardDisk; INTERFACE FUNCTION GetHardDiskNaam : STRING; FUNCTION GetHardDiskSerieNummer : STRING; FUNCTION GetHardDiskControlleNummer : STRING; PROCEDURE GetHardDiskGegevens; CONST CodeerTabel : ARRAY[0..24] OF BYTE = (3,1,2,1,4,1,3,2,6,4,6,5,1,2,6,4,2,6,3,4,6,2,4,1,2); TYPE CharArray = ARRAY[0..24] OF CHAR; VAR HardDiskGegevens : ARRAY[1..256] OF INTEGER; HardDiskNaam : CharArray; SerieNummer : CharArray; ControlleNummer : CharArray; C_HardDiskNaam: STRING; C_HardDiskSerieNummer : STRING; C_HardDiskControlleNummer : STRING; C_LicentieNaam: STRING; IMPLEMENTATION FUNCTION GetHardDiskNaam : STRING; VAR Teller : INTEGER; Lus : INTEGER; BEGIN GetHardDiskNaam := ''; Teller := 1; FOR Lus := 1 TO 18 DO BEGIN HardDiskNaam[Teller] := CHR( ( HardDiskGegevens[27+Lus] DIV 256 )); Inc(Teller); HardDiskNaam[Teller] := CHR( ( HardDiskGegevens[27+Lus] MOD 256 )); Inc(Teller); END; GetHardDiskNaam := HardDiskNaam; END; FUNCTION GetHardDiskSerieNummer : STRING; VAR Teller : INTEGER; Lus : INTEGER; BEGIN GetHardDiskSerieNummer := ''; Teller := 1; FOR Lus := 1 TO 8 DO BEGIN SerieNummer[Teller] := CHR( ( HardDiskGegevens[10+Lus] DIV 256 )); Inc(Teller); SerieNummer[Teller] := CHR( ( HardDiskGegevens[10+Lus] MOD 256 )); Inc(Teller); END; GetHardDiskSerieNummer := SerieNummer; END; FUNCTION GetHardDiskControlleNummer : STRING; VAR Teller : INTEGER; Lus : INTEGER; BEGIN GetHardDiskControlleNummer := ''; Teller := 1; FOR Lus := 1 TO 3 DO BEGIN ControlleNummer[Teller] := CHR( ( HardDiskGegevens[23+Lus] DIV 256 )); Inc(Teller); ControlleNummer[Teller] := CHR( ( HardDiskGegevens[23+Lus] MOD 256 )); Inc(Teller); END; GetHardDiskControlleNummer := ControlleNummer; END; PROCEDURE GetHardDiskGegevens; VAR Lus : INTEGER; BEGIN WHILE ( Port[$1f7] <> $50) DO ; Port[$1F6] := $A0 ; Port[$1F7] := $EC ; WHILE ( Port[$1f7] <> $58 ) DO ; FOR Lus := 1 TO 256 DO BEGIN HardDiskGegevens[Lus] := Portw[$1F0] ; END; END; END.
还有另一个,我没测试,不过应该可以用 function GetHDSerialNumber(Drv : String): String; var VolumeSerialNumber : DWORD; MaximumComponentLength : DWORD; FileSystemFlags : DWORD; begin if Drv[Length(Drv)] =':' then Drv := Drv + '\'; GetVolumeInformation(pChar(Drv), nil, 0, @VolumeSerialNumber, MaximumComponentLength, FileSystemFlags, nil, 0); Result := IntToHex(HiWord(VolumeSerialNumber), 4) + '-' + IntToHex(LoWord(VolumeSerialNumber), 4); end; ********************************** function GetHardDiskSerial(const DriveLetter: Char): string; var NotUsed: DWORD; VolumeFlags: DWORD; VolumeInfo: array[0..MAX_PATH] of Char; VolumeSerialNumber: DWORD; begin GetVolumeInformation(PChar(DriveLetter + ':\'), nil, SizeOf(VolumeInfo), @VolumeSerialNumber, NotUsed, VolumeFlags, nil, 0); Result := Format('Label = %s VolSer = %8.8X', [VolumeInfo, VolumeSerialNumber]) end; procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage(GetHardDiskSerial('c')); end;
斑竹用VC编写的DLL,可以获得硬盘的型号、序列号以及计算机 ID,带Delphi的源程序:函数以及定义: function ReadPhysicalDrive(driveID:integer;buffer:Pointer;bufLen:integer):integer; stdcall; external 'DiskID.dll' name 'ReadPhysicalDriveInNT'; 获得WinNT下的硬盘型号以及序列号。参数driveID为硬盘的位置,IDE1上的主盘为0,类推到IDE2上的从盘的driveID为3。 function ReadPhysicalDrive9X(driveID:integer;buffer:Pointer;bufLen:integer):integer; stdcall; external 'DiskID.dll' name 'ReadDrivePortsInWin9X'; 获得Win9X下的硬盘型号以及序列号。参数同上 function getHardDriveComputerID:int64; stdcall; external 'DiskID.dll' name 'getHardDriveComputerID'; 获得计算机的ID http://www.applevb.com/lib/diskio.rar
下面方法可以准确的得到硬盘的型号和生产序列号等参数! function GetIdeDiskSerialNumber(var SerialNumber: string; var ModelNumber: string; var FirmwareRev: string; var TotalAddressableSectors: ULong; var SectorCapacity: ULong; var SectorsPerTrack: Word): Boolean; //得到硬盘物理号 type TSrbIoControl = packed record HeaderLength: ULong; Signature: array[0..7] of Char; Timeout: ULong; ControlCode: ULong; ReturnCode: ULong; Length: ULong; end; SRB_IO_CONTROL = TSrbIoControl; PSrbIoControl = ^TSrbIoControl; TIDERegs = packed 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. Must be zero. end; IDEREGS = TIDERegs; PIDERegs = ^TIDERegs; TSendCmdInParams = packed record cBufferSize: DWORD; irDriveRegs: TIDERegs; bDriveNumber: Byte; bReserved: array[0..2] of Byte; dwReserved: array[0..3] of DWORD; bBuffer: array[0..0] of Byte; end; SENDCMDINPARAMS = TSendCmdInParams; PSendCmdInParams = ^TSendCmdInParams; TIdSector = packed record wGenConfig: Word; wNumCyls: Word; wReserved: Word; wNumHeads: Word; wBytesPerTrack: Word; wBytesPerSector: Word; wSectorsPerTrack: Word; wVendorUnique: array[0..2] of Word; sSerialNumber: array[0..19] of Char; wBufferType: Word; wBufferSize: Word; wECCSize: Word; sFirmwareRev: array[0..7] of Char; sModelNumber: array[0..39] of Char; wMoreVendorUnique: Word; wDoubleWordIO: Word; wCapabilities: Word; wReserved1: Word; wPIOTiming: Word; wDMATiming: Word; wBS: Word; wNumCurrentCyls: Word; wNumCurrentHeads: Word; wNumCurrentSectorsPerTrack: Word; ulCurrentSectorCapacity: ULong; wMultSectorStuff: Word; ulTotalAddressableSectors: ULong; wSingleWordDMA: Word; wMultiWordDMA: Word; bReserved: array[0..127] of Byte; end; PIdSector = ^TIdSector;const IDE_ID_FUNCTION = $EC; IDENTIFY_BUFFER_SIZE = 512; DFP_RECEIVE_DRIVE_DATA = $0007C088; IOCTL_SCSI_MINIPORT = $0004D008; IOCTL_SCSI_MINIPORT_IDENTIFY = $001B0501; DataSize = sizeof(TSendCmdInParams) - 1 + IDENTIFY_BUFFER_SIZE; BufferSize = sizeof(SRB_IO_CONTROL) + DataSize; W9xBufferSize = IDENTIFY_BUFFER_SIZE + 16; var hDevice: THandle; cbBytesReturned: DWORD; pInData: PSendCmdInParams; pOutData: Pointer; // PSendCmdOutParams Buffer: array[0..BufferSize - 1] of Byte; srbControl: TSrbIoControl absolute Buffer; procedure ChangeByteOrder(var Data; Size: Integer); var ptr: PChar; i: Integer; c: Char; begin ptr := @Data; for i := 0 to (Size shr 1) - 1 do begin c := ptr^; ptr^ := (ptr + 1)^; (ptr + 1)^ := c; Inc(ptr, 2); end; end;begin Result := False; FillChar(Buffer, BufferSize, #0); if Win32Platform = VER_PLATFORM_WIN32_NT then begin // Windows NT, Windows 2000 // Get SCSI port handle hDevice := CreateFile('\\.\Scsi0:', GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if hDevice = INVALID_HANDLE_VALUE then Exit; try srbControl.HeaderLength := sizeof(SRB_IO_CONTROL); System.Move('SCSIDISK', srbControl.Signature, 8); srbControl.Timeout := 2; srbControl.Length := DataSize; srbControl.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY; pInData := PSendCmdInParams(PChar(@Buffer) + sizeof(SRB_IO_CONTROL)); pOutData := pInData; with pInData^ do begin cBufferSize := IDENTIFY_BUFFER_SIZE; bDriveNumber := 0; with irDriveRegs do begin bFeaturesReg := 0; bSectorCountReg := 1; bSectorNumberReg := 1; bCylLowReg := 0; bCylHighReg := 0; bDriveHeadReg := $A0; bCommandReg := IDE_ID_FUNCTION; end; end; if not DeviceIoControl(hDevice, IOCTL_SCSI_MINIPORT, @Buffer, BufferSize, @Buffer, BufferSize, cbBytesReturned, nil) then Exit; finally CloseHandle(hDevice); end; end else begin // Windows 95 OSR2, Windows 98 hDevice := CreateFile('\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0); if hDevice = INVALID_HANDLE_VALUE then Exit; try pInData := PSendCmdInParams(@Buffer); pOutData := @pInData^.bBuffer; with pInData^ do begin cBufferSize := IDENTIFY_BUFFER_SIZE; bDriveNumber := 0; with irDriveRegs do begin bFeaturesReg := 0; bSectorCountReg := 1; bSectorNumberReg := 1; bCylLowReg := 0; bCylHighReg := 0; bDriveHeadReg := $A0; bCommandReg := IDE_ID_FUNCTION; end; end; if not DeviceIoControl(hDevice, DFP_RECEIVE_DRIVE_DATA, pInData, sizeof(TSendCmdInParams) - 1, pOutData, W9xBufferSize, cbBytesReturned, nil) then Exit; finally CloseHandle(hDevice); end; end; with PIdSector(PChar(pOutData) + 16)^ do begin ChangeByteOrder(sSerialNumber, sizeof(sSerialNumber)); SetString(SerialNumber, sSerialNumber, sizeof(sSerialNumber)); //硬盘生产序号 ChangeByteOrder(sModelNumber, sizeof(sModelNumber)); SetString(ModelNumber, sModelNumber, sizeof(sModelNumber)); //硬盘型号 ChangeByteOrder(sFirmwareRev, sizeof(sFirmwareRev)); SetString(FirmwareRev, sFirmwareRev, sizeof(sFirmwareRev)); //硬盘硬件版本 Result := True; ChangeByteOrder(ulTotalAddressableSectors, sizeof(ulTotalAddressableSectors)); TotalAddressableSectors := ulTotalAddressableSectors; //硬盘ulTotalAddressableSectors参数 ChangeByteOrder(ulCurrentSectorCapacity, sizeof(ulCurrentSectorCapacity)); SectorCapacity := ulCurrentSectorCapacity; //硬盘wBytesPerSector参数 ChangeByteOrder(wNumCurrentSectorsPerTrack, sizeof(wNumCurrentSectorsPerTrack)); SectorsPerTrack := wNumCurrentSectorsPerTrack; //硬盘wSectorsPerTrack参数 end; end; --------------------------------- 如果硬盘有多个的话,修改里面的参数就可以查出第二、第三个硬盘的型号、ID等参数。 引用如: procedure TForm1.BitBtn1Click(Sender: TObject); var S1, S2, S3: string; W5: Word; W4, W3: ULong; begin GetIdeDiskSerialNumber(S1, S2, S3, W3, W4, W5); Label1.Caption := '序列号:' + S1; Label2.Caption := '硬盘型号:' + S2; Label3.Caption := '硬件版本:' + S3; Label6.Caption := 'TotalAddressableSectors:' + inttostr(W3); Label7.Caption := 'SectorCapacity:' + inttostr(W4); Label8.Caption := 'SectorsPerTrack:' + inttostr(W5); end;
{========================================================================= 功 能: 得到硬盘序列号 参 数: 返回值: 硬盘序列号 备 注: ===========================================================================} function GetIdeDiskSerialNumber : String; type TSrbIoControl = packed record HeaderLength : ULONG; Signature : Array[0..7] of Char; Timeout : ULONG; ControlCode : ULONG; ReturnCode : ULONG; Length : ULONG; end; SRB_IO_CONTROL = TSrbIoControl; PSrbIoControl = ^TSrbIoControl; TIDERegs = packed 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. Must be zero. end; IDEREGS = TIDERegs; PIDERegs = ^TIDERegs; TSendCmdInParams = packed record cBufferSize : DWORD; irDriveRegs : TIDERegs; bDriveNumber : Byte; bReserved : Array[0..2] of Byte; dwReserved : Array[0..3] of DWORD; bBuffer : Array[0..0] of Byte; end; SENDCMDINPARAMS = TSendCmdInParams; PSendCmdInParams = ^TSendCmdInParams; TIdSector = packed record wGenConfig : Word; wNumCyls : Word; wReserved : Word; wNumHeads : Word; wBytesPerTrack : Word; wBytesPerSector : Word; wSectorsPerTrack : Word; wVendorUnique : Array[0..2] of Word; sSerialNumber : Array[0..19] of Char; wBufferType : Word; wBufferSize : Word; wECCSize : Word; sFirmwareRev : Array[0..7] of Char; sModelNumber : Array[0..39] of Char; wMoreVendorUnique : Word; wDoubleWordIO : Word; wCapabilities : Word; wReserved1 : Word; wPIOTiming : Word; wDMATiming : Word; wBS : Word; wNumCurrentCyls : Word; wNumCurrentHeads : Word; wNumCurrentSectorsPerTrack : Word; ulCurrentSectorCapacity : ULONG; wMultSectorStuff : Word; ulTotalAddressableSectors : ULONG; wSingleWordDMA : Word; wMultiWordDMA : Word; bReserved : Array[0..127] of Byte; end; PIdSector = ^TIdSector; const IDE_ID_FUNCTION = $EC; IDENTIFY_BUFFER_SIZE = 512; DFP_RECEIVE_DRIVE_DATA = $0007c088; IOCTL_SCSI_MINIPORT = $0004d008; IOCTL_SCSI_MINIPORT_IDENTIFY = $001b0501; DataSize = sizeof(TSendCmdInParams)-1+IDENTIFY_BUFFER_SIZE; BufferSize = SizeOf(SRB_IO_CONTROL)+DataSize; W9xBufferSize = IDENTIFY_BUFFER_SIZE+16; var hDevice : THandle; cbBytesReturned : DWORD; pInData : PSendCmdInParams; pOutData : Pointer; // PSendCmdOutParams Buffer : Array[0..BufferSize-1] of Byte; srbControl : TSrbIoControl absolute Buffer; procedure ChangeByteOrder( var Data; Size : Integer ); var ptr : PChar; i : Integer; c : Char; begin ptr := @Data; for i := 0 to (Size shr 1)-1 do begin c := ptr^; ptr^ := (ptr+1)^; (ptr+1)^ := c; Inc(ptr,2); end; end; begin Result := ''; FillChar(Buffer,BufferSize,#0); if Win32Platform=VER_PLATFORM_WIN32_NT then begin // Windows NT, Windows 2000 // Get SCSI port handle hDevice := CreateFile( '\\.\Scsi0:', GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 ); if hDevice=INVALID_HANDLE_VALUE then Exit; try srbControl.HeaderLength := SizeOf(SRB_IO_CONTROL); System.Move('SCSIDISK',srbControl.Signature,8); srbControl.Timeout := 2; srbControl.Length := DataSize; srbControl.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY; pInData := PSendCmdInParams(PChar(@Buffer) +SizeOf(SRB_IO_CONTROL)); pOutData := pInData; with pInData^ do begin cBufferSize := IDENTIFY_BUFFER_SIZE; bDriveNumber := 0; with irDriveRegs do begin bFeaturesReg := 0; bSectorCountReg := 1; bSectorNumberReg := 1; bCylLowReg := 0; bCylHighReg := 0; bDriveHeadReg := $A0; bCommandReg := IDE_ID_FUNCTION; end; end; if not DeviceIoControl( hDevice, IOCTL_SCSI_MINIPORT, @Buffer, BufferSize, @Buffer, BufferSize, cbBytesReturned, nil ) then Exit; finally CloseHandle(hDevice); end; end else begin // Windows 95 OSR2, Windows 98 hDevice := CreateFile( '\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0 ); if hDevice=INVALID_HANDLE_VALUE then Exit; try pInData := PSendCmdInParams(@Buffer); pOutData := @pInData^.bBuffer; with pInData^ do begin cBufferSize := IDENTIFY_BUFFER_SIZE; bDriveNumber := 0; with irDriveRegs do begin bFeaturesReg := 0; bSectorCountReg := 1; bSectorNumberReg := 1; bCylLowReg := 0; bCylHighReg := 0; bDriveHeadReg := $A0; bCommandReg := IDE_ID_FUNCTION; end; end; if not DeviceIoControl( hDevice, DFP_RECEIVE_DRIVE_DATA, pInData, SizeOf(TSendCmdInParams)-1, pOutData, W9xBufferSize, cbBytesReturned, nil ) then Exit; finally CloseHandle(hDevice); end; end; with PIdSector(PChar(pOutData)+16)^ do begin ChangeByteOrder(sSerialNumber,SizeOf(sSerialNumber)); SetString(Result,sSerialNumber,SizeOf(sSerialNumber)); end; end;
INTERFACE
FUNCTION GetHardDiskNaam : STRING;
FUNCTION GetHardDiskSerieNummer : STRING;
FUNCTION GetHardDiskControlleNummer : STRING;
PROCEDURE GetHardDiskGegevens;
CONST
CodeerTabel : ARRAY[0..24] OF BYTE =
(3,1,2,1,4,1,3,2,6,4,6,5,1,2,6,4,2,6,3,4,6,2,4,1,2);
TYPE
CharArray = ARRAY[0..24] OF CHAR;
VAR
HardDiskGegevens : ARRAY[1..256] OF INTEGER;
HardDiskNaam : CharArray;
SerieNummer : CharArray;
ControlleNummer : CharArray;
C_HardDiskNaam: STRING;
C_HardDiskSerieNummer : STRING;
C_HardDiskControlleNummer : STRING;
C_LicentieNaam: STRING;
IMPLEMENTATION
FUNCTION GetHardDiskNaam : STRING;
VAR
Teller : INTEGER;
Lus : INTEGER;
BEGIN
GetHardDiskNaam := '';
Teller := 1;
FOR Lus := 1 TO 18 DO
BEGIN
HardDiskNaam[Teller] := CHR( ( HardDiskGegevens[27+Lus] DIV 256 ));
Inc(Teller);
HardDiskNaam[Teller] := CHR( ( HardDiskGegevens[27+Lus] MOD 256 ));
Inc(Teller);
END;
GetHardDiskNaam := HardDiskNaam;
END;
FUNCTION GetHardDiskSerieNummer : STRING;
VAR
Teller : INTEGER;
Lus : INTEGER;
BEGIN
GetHardDiskSerieNummer := '';
Teller := 1;
FOR Lus := 1 TO 8 DO
BEGIN
SerieNummer[Teller] := CHR( ( HardDiskGegevens[10+Lus] DIV 256 ));
Inc(Teller);
SerieNummer[Teller] := CHR( ( HardDiskGegevens[10+Lus] MOD 256 ));
Inc(Teller);
END;
GetHardDiskSerieNummer := SerieNummer;
END;
FUNCTION GetHardDiskControlleNummer : STRING;
VAR
Teller : INTEGER;
Lus : INTEGER;
BEGIN
GetHardDiskControlleNummer := '';
Teller := 1;
FOR Lus := 1 TO 3 DO
BEGIN
ControlleNummer[Teller] := CHR( ( HardDiskGegevens[23+Lus] DIV 256 ));
Inc(Teller);
ControlleNummer[Teller] := CHR( ( HardDiskGegevens[23+Lus] MOD 256 ));
Inc(Teller);
END;
GetHardDiskControlleNummer := ControlleNummer;
END;
PROCEDURE GetHardDiskGegevens;
VAR
Lus : INTEGER;
BEGIN
WHILE ( Port[$1f7] <> $50) DO ;
Port[$1F6] := $A0 ;
Port[$1F7] := $EC ;
WHILE ( Port[$1f7] <> $58 ) DO ;
FOR Lus := 1 TO 256 DO
BEGIN
HardDiskGegevens[Lus] := Portw[$1F0] ;
END;
END;
END.
function GetHDSerialNumber(Drv : String): String;
var
VolumeSerialNumber : DWORD;
MaximumComponentLength : DWORD;
FileSystemFlags : DWORD;
begin
if Drv[Length(Drv)] =':' then Drv := Drv + '\';
GetVolumeInformation(pChar(Drv),
nil,
0,
@VolumeSerialNumber,
MaximumComponentLength,
FileSystemFlags,
nil,
0);
Result := IntToHex(HiWord(VolumeSerialNumber), 4) +
'-' +
IntToHex(LoWord(VolumeSerialNumber), 4);
end;
**********************************
function GetHardDiskSerial(const DriveLetter: Char): string;
var
NotUsed: DWORD;
VolumeFlags: DWORD;
VolumeInfo: array[0..MAX_PATH] of Char;
VolumeSerialNumber: DWORD;
begin
GetVolumeInformation(PChar(DriveLetter + ':\'),
nil, SizeOf(VolumeInfo), @VolumeSerialNumber, NotUsed,
VolumeFlags, nil, 0);
Result := Format('Label = %s VolSer = %8.8X',
[VolumeInfo, VolumeSerialNumber])
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage(GetHardDiskSerial('c'));
end;
function ReadPhysicalDrive(driveID:integer;buffer:Pointer;bufLen:integer):integer; stdcall; external 'DiskID.dll' name 'ReadPhysicalDriveInNT';
获得WinNT下的硬盘型号以及序列号。参数driveID为硬盘的位置,IDE1上的主盘为0,类推到IDE2上的从盘的driveID为3。
function ReadPhysicalDrive9X(driveID:integer;buffer:Pointer;bufLen:integer):integer; stdcall; external 'DiskID.dll' name 'ReadDrivePortsInWin9X';
获得Win9X下的硬盘型号以及序列号。参数同上
function getHardDriveComputerID:int64; stdcall; external 'DiskID.dll' name 'getHardDriveComputerID';
获得计算机的ID http://www.applevb.com/lib/diskio.rar
function GetIdeDiskSerialNumber(var SerialNumber: string; var ModelNumber: string;
var FirmwareRev: string; var TotalAddressableSectors: ULong;
var SectorCapacity: ULong; var SectorsPerTrack: Word): Boolean; //得到硬盘物理号
type
TSrbIoControl = packed record
HeaderLength: ULong;
Signature: array[0..7] of Char;
Timeout: ULong;
ControlCode: ULong;
ReturnCode: ULong;
Length: ULong;
end;
SRB_IO_CONTROL = TSrbIoControl;
PSrbIoControl = ^TSrbIoControl; TIDERegs = packed 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. Must be zero.
end;
IDEREGS = TIDERegs;
PIDERegs = ^TIDERegs; TSendCmdInParams = packed record
cBufferSize: DWORD;
irDriveRegs: TIDERegs;
bDriveNumber: Byte;
bReserved: array[0..2] of Byte;
dwReserved: array[0..3] of DWORD;
bBuffer: array[0..0] of Byte;
end;
SENDCMDINPARAMS = TSendCmdInParams;
PSendCmdInParams = ^TSendCmdInParams; TIdSector = packed record
wGenConfig: Word;
wNumCyls: Word;
wReserved: Word;
wNumHeads: Word;
wBytesPerTrack: Word;
wBytesPerSector: Word;
wSectorsPerTrack: Word;
wVendorUnique: array[0..2] of Word;
sSerialNumber: array[0..19] of Char;
wBufferType: Word;
wBufferSize: Word;
wECCSize: Word;
sFirmwareRev: array[0..7] of Char;
sModelNumber: array[0..39] of Char;
wMoreVendorUnique: Word;
wDoubleWordIO: Word;
wCapabilities: Word;
wReserved1: Word;
wPIOTiming: Word;
wDMATiming: Word;
wBS: Word;
wNumCurrentCyls: Word;
wNumCurrentHeads: Word;
wNumCurrentSectorsPerTrack: Word;
ulCurrentSectorCapacity: ULong;
wMultSectorStuff: Word;
ulTotalAddressableSectors: ULong;
wSingleWordDMA: Word;
wMultiWordDMA: Word;
bReserved: array[0..127] of Byte;
end;
PIdSector = ^TIdSector;const
IDE_ID_FUNCTION = $EC;
IDENTIFY_BUFFER_SIZE = 512;
DFP_RECEIVE_DRIVE_DATA = $0007C088;
IOCTL_SCSI_MINIPORT = $0004D008;
IOCTL_SCSI_MINIPORT_IDENTIFY = $001B0501;
DataSize = sizeof(TSendCmdInParams) - 1 + IDENTIFY_BUFFER_SIZE;
BufferSize = sizeof(SRB_IO_CONTROL) + DataSize;
W9xBufferSize = IDENTIFY_BUFFER_SIZE + 16;
var
hDevice: THandle;
cbBytesReturned: DWORD;
pInData: PSendCmdInParams;
pOutData: Pointer; // PSendCmdOutParams
Buffer: array[0..BufferSize - 1] of Byte;
srbControl: TSrbIoControl absolute Buffer; procedure ChangeByteOrder(var Data; Size: Integer);
var ptr: PChar;
i: Integer;
c: Char;
begin
ptr := @Data;
for i := 0 to (Size shr 1) - 1 do
begin
c := ptr^;
ptr^ := (ptr + 1)^;
(ptr + 1)^ := c;
Inc(ptr, 2);
end;
end;begin
Result := False;
FillChar(Buffer, BufferSize, #0);
if Win32Platform = VER_PLATFORM_WIN32_NT then
begin // Windows NT, Windows 2000
// Get SCSI port handle
hDevice := CreateFile('\\.\Scsi0:',
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0);
if hDevice = INVALID_HANDLE_VALUE then Exit;
try
srbControl.HeaderLength := sizeof(SRB_IO_CONTROL);
System.Move('SCSIDISK', srbControl.Signature, 8);
srbControl.Timeout := 2;
srbControl.Length := DataSize;
srbControl.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY;
pInData := PSendCmdInParams(PChar(@Buffer)
+ sizeof(SRB_IO_CONTROL));
pOutData := pInData;
with pInData^ do
begin
cBufferSize := IDENTIFY_BUFFER_SIZE;
bDriveNumber := 0;
with irDriveRegs do
begin
bFeaturesReg := 0;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := 0;
bCylHighReg := 0;
bDriveHeadReg := $A0;
bCommandReg := IDE_ID_FUNCTION;
end;
end;
if not DeviceIoControl(hDevice, IOCTL_SCSI_MINIPORT,
@Buffer, BufferSize, @Buffer, BufferSize,
cbBytesReturned, nil) then Exit;
finally
CloseHandle(hDevice);
end;
end
else
begin // Windows 95 OSR2, Windows 98
hDevice := CreateFile('\\.\SMARTVSD', 0, 0, nil,
CREATE_NEW, 0, 0);
if hDevice = INVALID_HANDLE_VALUE then Exit;
try
pInData := PSendCmdInParams(@Buffer);
pOutData := @pInData^.bBuffer;
with pInData^ do
begin
cBufferSize := IDENTIFY_BUFFER_SIZE;
bDriveNumber := 0;
with irDriveRegs do
begin
bFeaturesReg := 0;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := 0;
bCylHighReg := 0;
bDriveHeadReg := $A0;
bCommandReg := IDE_ID_FUNCTION;
end;
end;
if not DeviceIoControl(hDevice, DFP_RECEIVE_DRIVE_DATA,
pInData, sizeof(TSendCmdInParams) - 1, pOutData,
W9xBufferSize, cbBytesReturned, nil) then Exit;
finally
CloseHandle(hDevice);
end;
end;
with PIdSector(PChar(pOutData) + 16)^ do
begin
ChangeByteOrder(sSerialNumber, sizeof(sSerialNumber));
SetString(SerialNumber, sSerialNumber, sizeof(sSerialNumber)); //硬盘生产序号 ChangeByteOrder(sModelNumber, sizeof(sModelNumber));
SetString(ModelNumber, sModelNumber, sizeof(sModelNumber)); //硬盘型号 ChangeByteOrder(sFirmwareRev, sizeof(sFirmwareRev));
SetString(FirmwareRev, sFirmwareRev, sizeof(sFirmwareRev)); //硬盘硬件版本
Result := True;
ChangeByteOrder(ulTotalAddressableSectors, sizeof(ulTotalAddressableSectors));
TotalAddressableSectors := ulTotalAddressableSectors; //硬盘ulTotalAddressableSectors参数 ChangeByteOrder(ulCurrentSectorCapacity, sizeof(ulCurrentSectorCapacity));
SectorCapacity := ulCurrentSectorCapacity; //硬盘wBytesPerSector参数 ChangeByteOrder(wNumCurrentSectorsPerTrack, sizeof(wNumCurrentSectorsPerTrack));
SectorsPerTrack := wNumCurrentSectorsPerTrack; //硬盘wSectorsPerTrack参数
end;
end;
---------------------------------
如果硬盘有多个的话,修改里面的参数就可以查出第二、第三个硬盘的型号、ID等参数。
引用如:
procedure TForm1.BitBtn1Click(Sender: TObject);
var
S1, S2, S3: string;
W5: Word;
W4, W3: ULong;
begin
GetIdeDiskSerialNumber(S1, S2, S3, W3, W4, W5);
Label1.Caption := '序列号:' + S1;
Label2.Caption := '硬盘型号:' + S2;
Label3.Caption := '硬件版本:' + S3;
Label6.Caption := 'TotalAddressableSectors:' + inttostr(W3);
Label7.Caption := 'SectorCapacity:' + inttostr(W4);
Label8.Caption := 'SectorsPerTrack:' + inttostr(W5);
end;
功 能: 得到硬盘序列号
参 数:
返回值: 硬盘序列号
备 注: ===========================================================================}
function GetIdeDiskSerialNumber : String;
type
TSrbIoControl = packed record
HeaderLength : ULONG;
Signature : Array[0..7] of Char;
Timeout : ULONG;
ControlCode : ULONG;
ReturnCode : ULONG;
Length : ULONG;
end;
SRB_IO_CONTROL = TSrbIoControl;
PSrbIoControl = ^TSrbIoControl; TIDERegs = packed 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. Must be zero.
end;
IDEREGS = TIDERegs;
PIDERegs = ^TIDERegs; TSendCmdInParams = packed record
cBufferSize : DWORD;
irDriveRegs : TIDERegs;
bDriveNumber : Byte;
bReserved : Array[0..2] of Byte;
dwReserved : Array[0..3] of DWORD;
bBuffer : Array[0..0] of Byte;
end;
SENDCMDINPARAMS = TSendCmdInParams;
PSendCmdInParams = ^TSendCmdInParams; TIdSector = packed record
wGenConfig : Word;
wNumCyls : Word;
wReserved : Word;
wNumHeads : Word;
wBytesPerTrack : Word;
wBytesPerSector : Word;
wSectorsPerTrack : Word;
wVendorUnique : Array[0..2] of Word;
sSerialNumber : Array[0..19] of Char;
wBufferType : Word;
wBufferSize : Word;
wECCSize : Word;
sFirmwareRev : Array[0..7] of Char;
sModelNumber : Array[0..39] of Char;
wMoreVendorUnique : Word;
wDoubleWordIO : Word;
wCapabilities : Word;
wReserved1 : Word;
wPIOTiming : Word;
wDMATiming : Word;
wBS : Word;
wNumCurrentCyls : Word;
wNumCurrentHeads : Word;
wNumCurrentSectorsPerTrack : Word;
ulCurrentSectorCapacity : ULONG;
wMultSectorStuff : Word;
ulTotalAddressableSectors : ULONG;
wSingleWordDMA : Word;
wMultiWordDMA : Word;
bReserved : Array[0..127] of Byte;
end;
PIdSector = ^TIdSector; const
IDE_ID_FUNCTION = $EC;
IDENTIFY_BUFFER_SIZE = 512;
DFP_RECEIVE_DRIVE_DATA = $0007c088;
IOCTL_SCSI_MINIPORT = $0004d008;
IOCTL_SCSI_MINIPORT_IDENTIFY = $001b0501;
DataSize = sizeof(TSendCmdInParams)-1+IDENTIFY_BUFFER_SIZE;
BufferSize = SizeOf(SRB_IO_CONTROL)+DataSize;
W9xBufferSize = IDENTIFY_BUFFER_SIZE+16;
var
hDevice : THandle;
cbBytesReturned : DWORD;
pInData : PSendCmdInParams;
pOutData : Pointer; // PSendCmdOutParams
Buffer : Array[0..BufferSize-1] of Byte;
srbControl : TSrbIoControl absolute Buffer; procedure ChangeByteOrder( var Data; Size : Integer );
var ptr : PChar;
i : Integer;
c : Char;
begin
ptr := @Data;
for i := 0 to (Size shr 1)-1 do
begin
c := ptr^;
ptr^ := (ptr+1)^;
(ptr+1)^ := c;
Inc(ptr,2);
end;
end; begin
Result := '';
FillChar(Buffer,BufferSize,#0);
if Win32Platform=VER_PLATFORM_WIN32_NT then
begin // Windows NT, Windows 2000
// Get SCSI port handle
hDevice := CreateFile( '\\.\Scsi0:',
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, 0, 0 );
if hDevice=INVALID_HANDLE_VALUE then Exit;
try
srbControl.HeaderLength := SizeOf(SRB_IO_CONTROL);
System.Move('SCSIDISK',srbControl.Signature,8);
srbControl.Timeout := 2;
srbControl.Length := DataSize;
srbControl.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY;
pInData := PSendCmdInParams(PChar(@Buffer)
+SizeOf(SRB_IO_CONTROL));
pOutData := pInData;
with pInData^ do
begin
cBufferSize := IDENTIFY_BUFFER_SIZE;
bDriveNumber := 0;
with irDriveRegs do
begin
bFeaturesReg := 0;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := 0;
bCylHighReg := 0;
bDriveHeadReg := $A0;
bCommandReg := IDE_ID_FUNCTION;
end;
end;
if not DeviceIoControl( hDevice, IOCTL_SCSI_MINIPORT,
@Buffer, BufferSize, @Buffer, BufferSize,
cbBytesReturned, nil ) then Exit;
finally
CloseHandle(hDevice);
end;
end
else
begin // Windows 95 OSR2, Windows 98
hDevice := CreateFile( '\\.\SMARTVSD', 0, 0, nil,
CREATE_NEW, 0, 0 );
if hDevice=INVALID_HANDLE_VALUE then Exit;
try
pInData := PSendCmdInParams(@Buffer);
pOutData := @pInData^.bBuffer;
with pInData^ do
begin
cBufferSize := IDENTIFY_BUFFER_SIZE;
bDriveNumber := 0;
with irDriveRegs do
begin
bFeaturesReg := 0;
bSectorCountReg := 1;
bSectorNumberReg := 1;
bCylLowReg := 0;
bCylHighReg := 0;
bDriveHeadReg := $A0;
bCommandReg := IDE_ID_FUNCTION;
end;
end;
if not DeviceIoControl( hDevice, DFP_RECEIVE_DRIVE_DATA,
pInData, SizeOf(TSendCmdInParams)-1, pOutData,
W9xBufferSize, cbBytesReturned, nil ) then Exit;
finally
CloseHandle(hDevice);
end;
end;
with PIdSector(PChar(pOutData)+16)^ do
begin
ChangeByteOrder(sSerialNumber,SizeOf(sSerialNumber));
SetString(Result,sSerialNumber,SizeOf(sSerialNumber));
end;
end;