网上有这种代码了,只是因为写的较早,有些地方写的不那么言简意赅,而且在XE后的版本中有问题(因为Unicode字符的关系)
下面是精简修改过的代码,只取第一块硬盘的序列号,Win7 + XE 测试通过。需要先安装JwApi函数库,因为有些结构体在库中有声明了
unit uGetHDSN;
interface
uses
Windows, JwaWinIoctl;
function GetIdeSerialNumber: AnsiString;
implementation
type
TIdSector = packed 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 AnsiChar;
wBufferType: USHORT;
wBufferSize: USHORT;
wECCSize: USHORT;
sFirmwareRev: array [0 .. 7] of AnsiChar;
sModelNumber: array [0 .. 39] of AnsiChar;
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 = ^TIdSector;
const
IDE_ATA_IDENTIFY = $EC;
function LittleToBig(Data: Word): Word;
asm
xchg ah, al
end;
function GetIdeSerialNumber: AnsiString;
var
hDevice: THandle;
Size, cbBytesReturned: DWORD;
SCIP: TSendCmdInParams;
SCOP: PSendCmdOutParams;
P: PWORD;
I: Integer;
begin
Result := '';
hDevice := CreateFile('\\.\PhysicalDrive0', GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or
FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
if hDevice = INVALID_HANDLE_VALUE then
Exit;
Size := SizeOf(TSendCmdOutParams) + IDENTIFY_BUFFER_SIZE - 1;
SCOP := AllocMem(Size);
SCIP.irDriveRegs.bCommandReg := IDE_ATA_IDENTIFY;
if DeviceIoControl(hDevice, SMART_RCV_DRIVE_DATA, @SCIP, SizeOf(TSendCmdInParams) - 1, SCOP, Size,
cbBytesReturned, nil) = False then
begin
FreeMem(SCOP);
CloseHandle(hDevice);
Exit;
end;
// 处理一下序列号在内存中的顺序
with PIdSector(@SCOP^.bBuffer[0])^ do
begin
SetLength(Result, Length(sSerialNumber));
P := @Result[1];
CopyMemory(P, @sSerialNumber[0], Length(sSerialNumber));
for I := 1 to Length(sSerialNumber) div 2 do
begin
P^ := LittleToBig(P^);
Inc(P);
end;
end;
FreeMem(SCOP);
end;
end.