Получить серийный номер жесткого диска (Delphi)
Сегодня узнаем, как можно узнать серийный номер жесткого диска. Именно железки, а не логического диска.
Для тех кому нужен номер логического диска, вот код:
Код Delphi:
function GetHDSerNo: shortstring; export; var VolumeName, FileSystemName : array [0..MAX_PATH-1] of Char; VolumeSerialNo : Cardinal; MaxComponentLength, FileSystemFlags : DWORD; begin try GetVolumeInformation('C:\',VolumeName,MAX_PATH,@VolumeSerialNo, MaxComponentLength,FileSystemFlags, FileSystemName,MAX_PATH); Result:=IntToHex(HiWord(VolumeSerialNo),4)+ '-'+IntToHex(LoWord(VolumeSerialNo),4); except ; end; end;
А теперь, собственно, по сути... С незапамятных времен у меня лежал такой замечательный код:
Код Delphi:
{ **** UBPFD *********** by delphibase.endimus.com **** >> Полyчение серийного номера IDE диска. Функция получает серийный номер первого физического диска IDE (не серийный номер тома!). Используется S.M.A.R.T. API, а под Windows NT/2K/XP запрос производится не напрямую к диску, а через miniport драйвер контроллера, что позволяет читать серийный номер не имея прав администратора. Функция может не работать, если первый контролер в системе не ATA или если первое устройство не является винчестером, который поддерживает SMART (современные винчестеры поддерживают). Автор: Alex Konshin, akonshin@earthlink.net, Boston, USA Copyright: http://home.earthlink.net/~akonshin/index.htm Дата: 30 декабря 2002 г. ***************************************************** } 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 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; 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 := ''; 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 := PChar(@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;
Но, как выяснилось, этот код не работает с SATA HDD. В итоге нашел другой код...
Код Delphi:
const SMART_GET_VERSION = $074080; SMART_SEND_DRIVE_COMMAND = $07C084; SMART_RCV_DRIVE_DATA = $07C088; // Values of ds_bDriverError DRVERR_NO_ERROR = 0; DRVERR_IDE_ERROR = 1; DRVERR_INVALID_FLAG = 2; DRVERR_INVALID_COMMAND = 3; DRVERR_INVALID_BUFFER = 4; DRVERR_INVALID_DRIVE = 5; DRVERR_INVALID_IOCTL = 6; DRVERR_ERROR_NO_MEM = 7; DRVERR_INVALID_REGISTER = 8; DRVERR_NOT_SUPPORTED = 9; DRVERR_NO_IDE_DEVICE = 10; // Values of ir_bCommandReg ATAPI_ID_CMD = $A1; ID_CMD = $EC; SMART_CMD = $B0; type TIdeRegs = packed record bFeaturesReg, bSectorCountReg, bSectorNumberReg, bCylLowReg, bCylHighReg, bDriveHeadReg, bCommandReg, bReserved: Byte; end; type TWinVersion = (wvUnknown, wv95, wv98, wvME, wvNT3, wvNT4, wvW2K, wvXP, wv2003,wvVista,wvSeven,wv8); TDriverStatus = packed record bDriverError: Byte; bIDEError: Byte; bReserved: array[1..2] of Byte; dwReserved: array[1..2] of DWORD; end; TSendCmdInParams = packed record dwBufferSize: DWORD; irDriveRegs: TIdeRegs; bDriveNumber: Byte; bReserved: array[1..3] of Byte; dwReserved: array[1..4] of DWORD; bBuffer: Byte; end; TSendCmdOutParams = packed record dwBufferSize: DWORD; dsDriverStatus: TDriverStatus; bBuffer: array[1..512] of Byte; end; TGetVersionInParams = packed record bVersion, bRevision, bReserved, bIDEDeviceMap: Byte; dwCapabilities: DWORD; dwReserved: array[1..4] of DWORD; end; // ... procedure CorrectDevInfo(var _params: TSendCmdOutParams); asm lea edi, _params.bBuffer add edi,14h mov ecx,0Ah @@SerNumLoop: mov ax,[edi] xchg al,ah stosw loop @@SerNumLoop add edi,6 mov cl,18h @@ModelNumLoop: mov ax,[edi] xchg al,ah stosw loop @@ModelNumLoop end; function HddSerialAndModel(Param:String):String; var i: DWORD; FTmpHDD: string; dev: THandle; scip: TSendCmdInParams; scop: TSendCmdOutParams; gvip: TGetVersionInParams; ret: DWORD; begin dev := CreateFile('\\.\PhysicalDrive0', GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if dev <> INVALID_HANDLE_VALUE then begin if DeviceIoControl(dev, SMART_GET_VERSION, nil, 0, @gvip, SizeOf(gvip), ret, nil) then begin scip.dwBufferSize := 512; scip.bDriveNumber := 0; scip.irDriveRegs.bSectorCountReg := 1; scip.irDriveRegs.bSectorNumberReg := 1; scip.irDriveRegs.bDriveHeadReg := $A0; // ??? scip.irDriveRegs.bCommandReg := ID_CMD; // ??? if not DeviceIoControl(dev, SMART_RCV_DRIVE_DATA, @scip, SizeOf(scip), @scop, SizeOf(scop), ret, nil) then ShowMessage(SysErrorMessage(GetLastError)) else if scop.dsDriverStatus.bDriverError = DRVERR_NO_ERROR then begin CorrectDevInfo(scop); if Param='Serial' then begin SetLength(FTmpHDD, 20); Move(scop.bBuffer[21], FTmpHDD[1], 20); Result:=FTmpHDD; end; if Param='Model' then begin SetLength(FTmpHDD, 40); Move(scop.bBuffer[55], FTmpHDD[1], 40); Result:=FTmpHDD; end; end else ShowMessageFmt('Error code: %d', [scop.dsDriverStatus.bDriverError]) end else ShowMessage(SysErrorMessage(GetLastError)); CloseHandle(dev); end; end;
Оставьте свой комментарий
Войдите, чтобы оставлять комментарии
Оставить комментарий как гость