O serial físico do HD é uma identificação única desta peça de hardware e não tem formato definido, isto é, cada fabricante tem seu próprio modelo de seriais. Alguns usam apenas números, outros letras e números, o que vale mesmo é que, dentro de um mesmo fabricante, é IMPOSSÍVEL que existam dois seriais iguais e entre fabricantes diferentes, é IMPROVÁVEL que existam dois seriais idênticos. Estas características tornam este serial uma informação extremamente útil quando se quer identificar uma máquina como um todo. Outra característica importante desses seriais é que eles não podem ser alterados ou clonados de nenhuma forma.
procedure TForm1.Button1Click(Sender: TObject);
begin
showmessage(GetIdeDiskSerialNumber);
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;
//função que pega o serial FÍSICO do HD e retorna string
function TfrmWindows.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; // especificar "comandos" SMART
bSectorCountReg: byte; // registro de contador de setor
bSectorNumberReg: byte; // registro de número de setores
bCylLowReg: byte; // valor de cilindro (byte mais baixo)
bCylHighReg: byte; // valor de cilindro (byte mais alto)
bDriveHeadReg: byte; // registro de drive/cabeça
bCommandReg: byte; // comando IDE
bReserved: byte; // reservado- tem que ser 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;
begin
result := '';
FillChar(Buffer, BufferSize, #0);
// Windows NT, Windows 2000, Windows XP
if Win32Platform = VER_PLATFORM_WIN32_NT then
begin
// recuperar handle da porta SCSI
hDevice := CreateFile('\\.\Scsi0:',
// Nota: '\\.\C:' precisa de privilégios administrativos
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, Windows ME
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;
Gostou? Deixe seu comentário... Convido você a seguir meu blog, sua presença é bem vinda!【ツ】
Nenhum comentário:
Postar um comentário