
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@922 8e941d3f-bd1b-0410-a28a-d453659cc2b4
236 lines
7.7 KiB
ObjectPascal
236 lines
7.7 KiB
ObjectPascal
// Extracting IDE(ATA) disk serial number.
|
|
|
|
// (c) 2000-2003 Alex Konshin
|
|
// mailto:akonshin@earthlink.net
|
|
// http://home.earthlink.net/~akonshin/index.htm
|
|
//
|
|
// 30 Jul 2000 created
|
|
// 22 Oct 2003 refactoring
|
|
// 24 Jun 2009 adapted for Lazarus OnGuard package by Bogusław Brandys
|
|
unit idesn;
|
|
|
|
interface
|
|
|
|
{$mode delphi}{$H+}
|
|
|
|
//-------------------------------------------------------------
|
|
// Tries to extract the serial number from specified IDE disk.
|
|
//
|
|
// Parameters:
|
|
// ControllerNumber - SCSI port number of the controller.
|
|
// DriveNumber - Device index (0..4).
|
|
//
|
|
//
|
|
// Notes:
|
|
// 1. The parameter ControllerNumber is ignored on Windows 9x/ME platforms and should be 0.
|
|
// 2. This function CAN NOT extract SCSI disk serial number.
|
|
//
|
|
function GetIdeDiskSerialNumber( ControllerNumber, DriveNumber : Integer; var OutBuf : AnsiString ) : Boolean;
|
|
|
|
//=============================================================
|
|
implementation
|
|
|
|
uses
|
|
Windows,
|
|
SysUtils; // only for Win32Platform, SysErrorMessage and class Exception
|
|
|
|
|
|
//-------------------------------------------------------------
|
|
// Tries to extract the serial number from specified IDE disk.
|
|
//
|
|
// Parameters:
|
|
// ControllerNumber - SCSI port number of the controller.
|
|
// DriveNumber - SCSI port number of the controller.
|
|
// Notes:
|
|
// 1. The parameter ControllerNumber is ignored on Windows 9x/ME platforms and should be 0.
|
|
// 2. This function CAN NOT extract SCSI disk serial number.
|
|
//
|
|
function GetIdeDiskSerialNumber( ControllerNumber, DriveNumber : Integer; var OutBuf : AnsiString ) : 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 for future use. Must be zero.
|
|
end;
|
|
IDEREGS = TIDERegs;
|
|
PIDERegs = ^TIDERegs;
|
|
|
|
TSendCmdInParams = packed record
|
|
cBufferSize : DWORD; // Buffer size in bytes
|
|
irDriveRegs : TIDERegs; // 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;
|
|
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;
|
|
s : String;
|
|
pInData : PSendCmdInParams;
|
|
pOutData : Pointer; // PSendCmdInParams;
|
|
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
|
|
Str(ControllerNumber,s);
|
|
// Get SCSI port handle
|
|
hDevice := CreateFile(
|
|
PChar('\\.\Scsi'+s+':'),
|
|
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 := DriveNumber;
|
|
with irDriveRegs do
|
|
begin
|
|
bFeaturesReg := 0;
|
|
bSectorCountReg := 1;
|
|
bSectorNumberReg := 1;
|
|
bCylLowReg := 0;
|
|
bCylHighReg := 0;
|
|
bDriveHeadReg := $A0 or ((DriveNumber and 1) shl 4);
|
|
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 := PChar(@pInData^.bBuffer);
|
|
with pInData^ do
|
|
begin
|
|
cBufferSize := IDENTIFY_BUFFER_SIZE;
|
|
bDriveNumber := DriveNumber;
|
|
with irDriveRegs do
|
|
begin
|
|
bFeaturesReg := 0;
|
|
bSectorCountReg := 1;
|
|
bSectorNumberReg := 1;
|
|
bCylLowReg := 0;
|
|
bCylHighReg := 0;
|
|
bDriveHeadReg := $A0 or ((DriveNumber and 1) shl 4);
|
|
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(s,sSerialNumber,SizeOf(sSerialNumber));
|
|
end;
|
|
OutBuf := Trim(s);
|
|
Result := true;
|
|
|
|
end;
|
|
|
|
|
|
|
|
end.
|
|
|
|
|
|
|