{
获取SCSI硬盘出厂系列号
需要系统管理员权限,不支持磁盘阵列
这里只取了第0个或第1个硬盘的序列号
}
function GetScsiSerialNumber( const i: smallint): string ;
type
TScsiPassThrough = record
Length: Word;
ScsiStatus: Byte;
PathId: Byte;
TargetId: Byte;
Lun: Byte;
CdbLength: Byte;
SenseInfoLength: Byte;
DataIn: Byte;
DataTransferLength: ULONG;
TimeOutValue: ULONG;
DataBufferOffset: DWORD;
SenseInfoOffset: ULONG;
Cdb: array [ 0 .. 15 ] of Byte;
end ;
TScsiPassThroughWithBuffers = record
spt: TScsiPassThrough;
bSenseBuf: array [ 0 .. 31 ] of Byte;
bDataBuf: array [ 0 .. 191 ] of Byte;
end ;
var
dwReturned: DWORD;
len: DWORD;
Buffer: array [ 0 ..SizeOf(TScsiPassThroughWithBuffers) + SizeOf(TScsiPassThrough) - 1 ] of Byte;
sptwb: TScsiPassThroughWithBuffers absolute Buffer;
hDevice: thandle;
begin
Result : = '' ;
if SysUtils.win32Platform = VER_PLATFORM_WIN32_NT then
begin
if i = 0 then
hDevice : = CreateFile( ' \\.\PhysicalDrive0 ' ,
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil , OPEN_EXISTING, 0 , 0 )
else
hDevice : = CreateFile( ' \\.\PhysicalDrive1 ' ,
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil , OPEN_EXISTING, 0 , 0 );
end
else exit;
if hDevice = invalid_handle_value then exit;
FillChar(Buffer, SizeOf(Buffer), # 0 );
with sptwb.spt do
begin
Length : = SizeOf(TScsiPassThrough);
CdbLength : = 6 ; // CDB6GENERIC_LENGTH
SenseInfoLength : = 24 ;
DataIn : = 1 ; // SCSI_IOCTL_DATA_IN
DataTransferLength : = 192 ;
TimeOutValue : = 2 ;
DataBufferOffset : = PChar(@sptwb.bDataBuf) - PChar(@sptwb);
SenseInfoOffset : = PChar(@sptwb.bSenseBuf) - PChar(@sptwb);
Cdb[ 0 ] : = $ 12 ; // OperationCode : = SCSIOP_INQUIRY;
Cdb[ 1 ] : = $ 01 ; // Flags : = CDB_INQUIRY_EVPD; Vital product data
Cdb[ 2 ] : = $ 80 ; // PageCode Unit serial number
Cdb[ 4 ] : = 192 ; // AllocationLength
end ;
len : = sptwb.spt.DataBufferOffset + sptwb.spt.DataTransferLength;
if DeviceIoControl(hDevice, $0004D004, @sptwb, SizeOf(TScsiPassThrough), @sptwb, len, dwReturned, nil )
and ((PChar(@sptwb.bDataBuf) + 1 )^ = #$ 80 ) then
SetString(Result, PChar(@sptwb.bDataBuf) + 4 , Ord((PChar(@sptwb.bDataBuf) + 3 )^));
end ;
{
获取IDE和SATA硬盘出厂系列号
需要系统管理员权限,不支持磁盘阵列
这里只取了第0个硬盘的序列号,要取其它硬盘只需要改变PhysicalDrive0后的数字
}
function GetIdeSerialNumber: pchar;
const IDENTIFY_BUFFER_SIZE = 512 ;
type
TIDERegs = packed record
bFeaturesReg: BYTE;
bSectorCountReg: BYTE;
bSectorNumberReg: BYTE;
bCylLowReg: BYTE;
bCylHighReg: BYTE;
bDriveHeadReg: BYTE;
bCommandReg: BYTE;
bReserved: BYTE;
end ;
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 ;
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: DWORD;
wMultSectorStuff: Word;
ulTotalAddressableSectors: DWORD;
wSingleWordDMA: Word;
wMultiWordDMA: Word;
bReserved: array [ 0 .. 127 ] of BYTE;
end ;
PIdSector = ^TIdSector;
TDriverStatus = packed record
bDriverError: Byte;
bIDEStatus: Byte;
bReserved: array [ 0 .. 1 ] of Byte;
dwReserved: array [ 0 .. 1 ] of DWORD;
end ;
TSendCmdOutParams = packed record
cBufferSize: DWORD;
DriverStatus: TDriverStatus;
bBuffer: array [ 0 .. 0 ] of BYTE;
end ;
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 ;
var
hDevice: Thandle;
cbBytesReturned: DWORD;
SCIP: TSendCmdInParams;
aIdOutCmd: array [ 0 ..(SizeOf(TSendCmdOutParams) + IDENTIFY_BUFFER_SIZE - 1 ) - 1 ] of Byte;
IdOutCmd: TSendCmdOutParams absolute aIdOutCmd;
begin
Result : = '' ;
if SysUtils.Win32Platform = VER_PLATFORM_WIN32_NT then
// Windows NT, Windows 2000
hDevice : = CreateFile( ' \\.\PhysicalDrive0 ' , GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil , OPEN_EXISTING, 0 , 0 )
else
// Version Windows 95 OSR2, Windows 98
hDevice : = CreateFile( ' \\.\SMARTVSD ' , 0 , 0 , nil , CREATE_NEW, 0 , 0 );
if hDevice = INVALID_HANDLE_VALUE then Exit;
try
FillChar(SCIP, SizeOf(TSendCmdInParams) - 1 , # 0 );
FillChar(aIdOutCmd, SizeOf(aIdOutCmd), # 0 );
cbBytesReturned : = 0 ;
with SCIP do begin
cBufferSize : = IDENTIFY_BUFFER_SIZE;
with irDriveRegs do begin
bSectorCountReg : = 1 ;
bSectorNumberReg : = 1 ;
bDriveHeadReg : = $A0;
bCommandReg : = $EC;
end ;
end ;
if not DeviceIoControl(hDevice, $0007C088, @SCIP, SizeOf(TSendCmdInParams) - 1 ,
@aIdOutCmd, SizeOf(aIdOutCmd), cbBytesReturned, nil ) then Exit;
finally
CloseHandle(hDevice);
end ;
with PIdSector(@IdOutCmd.bBuffer)^ do begin
ChangeByteOrder(sSerialNumber, SizeOf(sSerialNumber));
(Pchar(@sSerialNumber) + SizeOf(sSerialNumber))^ : = # 0 ;
Result : = Pchar(@sSerialNumber);
end ;
end ;
获取SCSI硬盘出厂系列号
需要系统管理员权限,不支持磁盘阵列
这里只取了第0个或第1个硬盘的序列号
}
function GetScsiSerialNumber( const i: smallint): string ;
type
TScsiPassThrough = record
Length: Word;
ScsiStatus: Byte;
PathId: Byte;
TargetId: Byte;
Lun: Byte;
CdbLength: Byte;
SenseInfoLength: Byte;
DataIn: Byte;
DataTransferLength: ULONG;
TimeOutValue: ULONG;
DataBufferOffset: DWORD;
SenseInfoOffset: ULONG;
Cdb: array [ 0 .. 15 ] of Byte;
end ;
TScsiPassThroughWithBuffers = record
spt: TScsiPassThrough;
bSenseBuf: array [ 0 .. 31 ] of Byte;
bDataBuf: array [ 0 .. 191 ] of Byte;
end ;
var
dwReturned: DWORD;
len: DWORD;
Buffer: array [ 0 ..SizeOf(TScsiPassThroughWithBuffers) + SizeOf(TScsiPassThrough) - 1 ] of Byte;
sptwb: TScsiPassThroughWithBuffers absolute Buffer;
hDevice: thandle;
begin
Result : = '' ;
if SysUtils.win32Platform = VER_PLATFORM_WIN32_NT then
begin
if i = 0 then
hDevice : = CreateFile( ' \\.\PhysicalDrive0 ' ,
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil , OPEN_EXISTING, 0 , 0 )
else
hDevice : = CreateFile( ' \\.\PhysicalDrive1 ' ,
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE,
nil , OPEN_EXISTING, 0 , 0 );
end
else exit;
if hDevice = invalid_handle_value then exit;
FillChar(Buffer, SizeOf(Buffer), # 0 );
with sptwb.spt do
begin
Length : = SizeOf(TScsiPassThrough);
CdbLength : = 6 ; // CDB6GENERIC_LENGTH
SenseInfoLength : = 24 ;
DataIn : = 1 ; // SCSI_IOCTL_DATA_IN
DataTransferLength : = 192 ;
TimeOutValue : = 2 ;
DataBufferOffset : = PChar(@sptwb.bDataBuf) - PChar(@sptwb);
SenseInfoOffset : = PChar(@sptwb.bSenseBuf) - PChar(@sptwb);
Cdb[ 0 ] : = $ 12 ; // OperationCode : = SCSIOP_INQUIRY;
Cdb[ 1 ] : = $ 01 ; // Flags : = CDB_INQUIRY_EVPD; Vital product data
Cdb[ 2 ] : = $ 80 ; // PageCode Unit serial number
Cdb[ 4 ] : = 192 ; // AllocationLength
end ;
len : = sptwb.spt.DataBufferOffset + sptwb.spt.DataTransferLength;
if DeviceIoControl(hDevice, $0004D004, @sptwb, SizeOf(TScsiPassThrough), @sptwb, len, dwReturned, nil )
and ((PChar(@sptwb.bDataBuf) + 1 )^ = #$ 80 ) then
SetString(Result, PChar(@sptwb.bDataBuf) + 4 , Ord((PChar(@sptwb.bDataBuf) + 3 )^));
end ;
{
获取IDE和SATA硬盘出厂系列号
需要系统管理员权限,不支持磁盘阵列
这里只取了第0个硬盘的序列号,要取其它硬盘只需要改变PhysicalDrive0后的数字
}
function GetIdeSerialNumber: pchar;
const IDENTIFY_BUFFER_SIZE = 512 ;
type
TIDERegs = packed record
bFeaturesReg: BYTE;
bSectorCountReg: BYTE;
bSectorNumberReg: BYTE;
bCylLowReg: BYTE;
bCylHighReg: BYTE;
bDriveHeadReg: BYTE;
bCommandReg: BYTE;
bReserved: BYTE;
end ;
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 ;
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: DWORD;
wMultSectorStuff: Word;
ulTotalAddressableSectors: DWORD;
wSingleWordDMA: Word;
wMultiWordDMA: Word;
bReserved: array [ 0 .. 127 ] of BYTE;
end ;
PIdSector = ^TIdSector;
TDriverStatus = packed record
bDriverError: Byte;
bIDEStatus: Byte;
bReserved: array [ 0 .. 1 ] of Byte;
dwReserved: array [ 0 .. 1 ] of DWORD;
end ;
TSendCmdOutParams = packed record
cBufferSize: DWORD;
DriverStatus: TDriverStatus;
bBuffer: array [ 0 .. 0 ] of BYTE;
end ;
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 ;
var
hDevice: Thandle;
cbBytesReturned: DWORD;
SCIP: TSendCmdInParams;
aIdOutCmd: array [ 0 ..(SizeOf(TSendCmdOutParams) + IDENTIFY_BUFFER_SIZE - 1 ) - 1 ] of Byte;
IdOutCmd: TSendCmdOutParams absolute aIdOutCmd;
begin
Result : = '' ;
if SysUtils.Win32Platform = VER_PLATFORM_WIN32_NT then
// Windows NT, Windows 2000
hDevice : = CreateFile( ' \\.\PhysicalDrive0 ' , GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil , OPEN_EXISTING, 0 , 0 )
else
// Version Windows 95 OSR2, Windows 98
hDevice : = CreateFile( ' \\.\SMARTVSD ' , 0 , 0 , nil , CREATE_NEW, 0 , 0 );
if hDevice = INVALID_HANDLE_VALUE then Exit;
try
FillChar(SCIP, SizeOf(TSendCmdInParams) - 1 , # 0 );
FillChar(aIdOutCmd, SizeOf(aIdOutCmd), # 0 );
cbBytesReturned : = 0 ;
with SCIP do begin
cBufferSize : = IDENTIFY_BUFFER_SIZE;
with irDriveRegs do begin
bSectorCountReg : = 1 ;
bSectorNumberReg : = 1 ;
bDriveHeadReg : = $A0;
bCommandReg : = $EC;
end ;
end ;
if not DeviceIoControl(hDevice, $0007C088, @SCIP, SizeOf(TSendCmdInParams) - 1 ,
@aIdOutCmd, SizeOf(aIdOutCmd), cbBytesReturned, nil ) then Exit;
finally
CloseHandle(hDevice);
end ;
with PIdSector(@IdOutCmd.bBuffer)^ do begin
ChangeByteOrder(sSerialNumber, SizeOf(sSerialNumber));
(Pchar(@sSerialNumber) + SizeOf(sSerialNumber))^ : = # 0 ;
Result : = Pchar(@sSerialNumber);
end ;
end ;