5 1 1 1 1 1 1 1 1 1 1 Рейтинг 5.00 (1 Голос)

Получить серийный номер жесткого диска (Delphi)

Сегодня узнаем, как можно узнать серийный номер жесткого диска. Именно железки, а не логического диска.

Для тех кому нужен номер логического диска, вот код:

Код Delphi:
  1. function GetHDSerNo: shortstring; export;
  2. var VolumeName, FileSystemName : array [0..MAX_PATH-1] of Char;
  3. VolumeSerialNo : Cardinal;
  4. MaxComponentLength, FileSystemFlags : DWORD;
  5. begin
  6. try
  7. GetVolumeInformation('C:\',VolumeName,MAX_PATH,@VolumeSerialNo,
  8. MaxComponentLength,FileSystemFlags, FileSystemName,MAX_PATH);
  9. Result:=IntToHex(HiWord(VolumeSerialNo),4)+ '-'+IntToHex(LoWord(VolumeSerialNo),4);
  10. except ;
  11. end;
  12. end;

 А теперь, собственно, по сути... С незапамятных времен у меня лежал такой замечательный код:

Код Delphi:
  1. { **** UBPFD *********** by delphibase.endimus.com ****
  2. >> Полyчение серийного номера IDE диска.
  3. Функция получает серийный номер первого физического диска IDE (не серийный номер тома!).
  4. Используется S.M.A.R.T. API, а под Windows NT/2K/XP запрос производится не напрямую к диску,
  5. а через miniport драйвер контроллера, что позволяет читать серийный номер не имея прав администратора.
  6. Функция может не работать, если первый контролер в системе не ATA или если первое устройство
  7. не является винчестером, который поддерживает SMART (современные винчестеры поддерживают).
  8. Автор: Alex Konshin, akonshin@earthlink.net, Boston, USA
  9. Copyright: http://home.earthlink.net/~akonshin/index.htm
  10. Дата: 30 декабря 2002 г.
  11. ***************************************************** }
  12. function GetIdeDiskSerialNumber: string;
  13. type
  14. TSrbIoControl = packed record
  15. HeaderLength: ULONG;
  16. Signature: array[0..7] of Char;
  17. Timeout: ULONG;
  18. ControlCode: ULONG;
  19. ReturnCode: ULONG;
  20. Length: ULONG;
  21. end;
  22. SRB_IO_CONTROL = TSrbIoControl;
  23. PSrbIoControl = ^TSrbIoControl;
  24.  
  25. TIDERegs = packed record
  26. bFeaturesReg: Byte; // Used for specifying SMART "commands".
  27. bSectorCountReg: Byte; // IDE sector count register
  28. bSectorNumberReg: Byte; // IDE sector number register
  29. bCylLowReg: Byte; // IDE low order cylinder value
  30. bCylHighReg: Byte; // IDE high order cylinder value
  31. bDriveHeadReg: Byte; // IDE drive/head register
  32. bCommandReg: Byte; // Actual IDE command.
  33. bReserved: Byte; // reserved for future use. Must be zero.
  34. end;
  35. IDEREGS = TIDERegs;
  36. PIDERegs = ^TIDERegs;
  37.  
  38. TSendCmdInParams = packed record
  39. cBufferSize: DWORD; // Buffer size in bytes
  40. irDriveRegs: TIDERegs; // Structure with drive register values.
  41. bDriveNumber: Byte; // Physical drive number to send command to (0,1,2,3).
  42. bReserved: array[0..2] of Byte; // Reserved for future expansion.
  43. dwReserved: array[0..3] of DWORD; // For future use.
  44. bBuffer: array[0..0] of Byte; // Input buffer.
  45. end;
  46. SENDCMDINPARAMS = TSendCmdInParams;
  47. PSendCmdInParams = ^TSendCmdInParams;
  48.  
  49. TIdSector = packed record
  50. wGenConfig: Word;
  51. wNumCyls: Word;
  52. wReserved: Word;
  53. wNumHeads: Word;
  54. wBytesPerTrack: Word;
  55. wBytesPerSector: Word;
  56. wSectorsPerTrack: Word;
  57. wVendorUnique: array[0..2] of Word;
  58. sSerialNumber: array[0..19] of Char;
  59. wBufferType: Word;
  60. wBufferSize: Word;
  61. wECCSize: Word;
  62. sFirmwareRev: array[0..7] of Char;
  63. sModelNumber: array[0..39] of Char;
  64. wMoreVendorUnique: Word;
  65. wDoubleWordIO: Word;
  66. wCapabilities: Word;
  67. wReserved1: Word;
  68. wPIOTiming: Word;
  69. wDMATiming: Word;
  70. wBS: Word;
  71. wNumCurrentCyls: Word;
  72. wNumCurrentHeads: Word;
  73. wNumCurrentSectorsPerTrack: Word;
  74. ulCurrentSectorCapacity: ULONG;
  75. wMultSectorStuff: Word;
  76. ulTotalAddressableSectors: ULONG;
  77. wSingleWordDMA: Word;
  78. wMultiWordDMA: Word;
  79. bReserved: array[0..127] of Byte;
  80. end;
  81. PIdSector = ^TIdSector;
  82.  
  83. const
  84. IDE_ID_FUNCTION = $EC;
  85. IDENTIFY_BUFFER_SIZE = 512;
  86. DFP_RECEIVE_DRIVE_DATA = $0007C088;
  87. IOCTL_SCSI_MINIPORT = $0004D008;
  88. IOCTL_SCSI_MINIPORT_IDENTIFY = $001B0501;
  89. DataSize = sizeof(TSendCmdInParams) - 1 + IDENTIFY_BUFFER_SIZE;
  90. BufferSize = SizeOf(SRB_IO_CONTROL) + DataSize;
  91. W9xBufferSize = IDENTIFY_BUFFER_SIZE + 16;
  92. var
  93. hDevice: THandle;
  94. cbBytesReturned: DWORD;
  95. pInData: PSendCmdInParams;
  96. pOutData: Pointer; // PSendCmdInParams;
  97. Buffer: array[0..BufferSize - 1] of Byte;
  98. srbControl: TSrbIoControl absolute Buffer;
  99.  
  100. procedure ChangeByteOrder(var Data; Size: Integer);
  101. var
  102. ptr: PChar;
  103. i: Integer;
  104. c: Char;
  105. begin
  106. ptr := @Data;
  107. for i := 0 to (Size shr 1) - 1 do
  108. begin
  109. c := ptr^;
  110. ptr^ := (ptr + 1)^;
  111. (ptr + 1)^ := c;
  112. Inc(ptr, 2);
  113. end;
  114. end;
  115.  
  116. begin
  117. Result := '';
  118. FillChar(Buffer, BufferSize, #0);
  119. if Win32Platform = VER_PLATFORM_WIN32_NT then
  120. begin // Windows NT, Windows 2000
  121. // Get SCSI port handle
  122. hDevice := CreateFile('\\.\Scsi0:', GENERIC_READ or GENERIC_WRITE,
  123. FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
  124. if hDevice = INVALID_HANDLE_VALUE then
  125. Exit;
  126. try
  127. srbControl.HeaderLength := SizeOf(SRB_IO_CONTROL);
  128. System.Move('SCSIDISK', srbControl.Signature, 8);
  129. srbControl.Timeout := 2;
  130. srbControl.Length := DataSize;
  131. srbControl.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY;
  132. pInData := PSendCmdInParams(PChar(@Buffer) + SizeOf(SRB_IO_CONTROL));
  133. pOutData := pInData;
  134. with pInData^ do
  135. begin
  136. cBufferSize := IDENTIFY_BUFFER_SIZE;
  137. bDriveNumber := 0;
  138. with irDriveRegs do
  139. begin
  140. bFeaturesReg := 0;
  141. bSectorCountReg := 1;
  142. bSectorNumberReg := 1;
  143. bCylLowReg := 0;
  144. bCylHighReg := 0;
  145. bDriveHeadReg := $A0;
  146. bCommandReg := IDE_ID_FUNCTION;
  147. end;
  148. end;
  149. if not DeviceIoControl(hDevice, IOCTL_SCSI_MINIPORT, @Buffer,
  150. BufferSize, @Buffer, BufferSize, cbBytesReturned, nil) then
  151. Exit;
  152. finally
  153. CloseHandle(hDevice);
  154. end;
  155. end
  156. else
  157. begin // Windows 95 OSR2, Windows 98
  158. hDevice := CreateFile('\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0);
  159. if hDevice = INVALID_HANDLE_VALUE then
  160. Exit;
  161. try
  162. pInData := PSendCmdInParams(@Buffer);
  163. pOutData := PChar(@pInData^.bBuffer);
  164. with pInData^ do
  165. begin
  166. cBufferSize := IDENTIFY_BUFFER_SIZE;
  167. bDriveNumber := 0;
  168. with irDriveRegs do
  169. begin
  170. bFeaturesReg := 0;
  171. bSectorCountReg := 1;
  172. bSectorNumberReg := 1;
  173. bCylLowReg := 0;
  174. bCylHighReg := 0;
  175. bDriveHeadReg := $A0;
  176. bCommandReg := IDE_ID_FUNCTION;
  177. end;
  178. end;
  179. if not DeviceIoControl(hDevice, DFP_RECEIVE_DRIVE_DATA, pInData,
  180. SizeOf(TSendCmdInParams) - 1, pOutData, W9xBufferSize,
  181. cbBytesReturned, nil) then
  182. Exit;
  183. finally
  184. CloseHandle(hDevice);
  185. end;
  186. end;
  187. with PIdSector(PChar(pOutData) + 16)^ do
  188. begin
  189. ChangeByteOrder(sSerialNumber, SizeOf(sSerialNumber));
  190. SetString(Result, sSerialNumber, SizeOf(sSerialNumber));
  191. end;
  192. end;

Но, как выяснилось, этот код не работает с SATA HDD. В итоге нашел другой код...

Код Delphi:
  1. const
  2. SMART_GET_VERSION = $074080;
  3. SMART_SEND_DRIVE_COMMAND = $07C084;
  4. SMART_RCV_DRIVE_DATA = $07C088;
  5. // Values of ds_bDriverError
  6. DRVERR_NO_ERROR = 0;
  7. DRVERR_IDE_ERROR = 1;
  8. DRVERR_INVALID_FLAG = 2;
  9. DRVERR_INVALID_COMMAND = 3;
  10. DRVERR_INVALID_BUFFER = 4;
  11. DRVERR_INVALID_DRIVE = 5;
  12. DRVERR_INVALID_IOCTL = 6;
  13. DRVERR_ERROR_NO_MEM = 7;
  14. DRVERR_INVALID_REGISTER = 8;
  15. DRVERR_NOT_SUPPORTED = 9;
  16. DRVERR_NO_IDE_DEVICE = 10;
  17. // Values of ir_bCommandReg
  18. ATAPI_ID_CMD = $A1;
  19. ID_CMD = $EC;
  20. SMART_CMD = $B0;
  21.  
  22. type
  23. TIdeRegs = packed record
  24. bFeaturesReg,
  25. bSectorCountReg,
  26. bSectorNumberReg,
  27. bCylLowReg,
  28. bCylHighReg,
  29. bDriveHeadReg,
  30. bCommandReg,
  31. bReserved: Byte;
  32. end;
  33. type
  34. TWinVersion = (wvUnknown, wv95, wv98, wvME, wvNT3, wvNT4, wvW2K, wvXP,
  35. wv2003,wvVista,wvSeven,wv8);
  36. TDriverStatus = packed record
  37. bDriverError: Byte;
  38. bIDEError: Byte;
  39. bReserved: array[1..2] of Byte;
  40. dwReserved: array[1..2] of DWORD;
  41. end;
  42.  
  43. TSendCmdInParams = packed record
  44. dwBufferSize: DWORD;
  45. irDriveRegs: TIdeRegs;
  46. bDriveNumber: Byte;
  47. bReserved: array[1..3] of Byte;
  48. dwReserved: array[1..4] of DWORD;
  49. bBuffer: Byte;
  50. end;
  51.  
  52. TSendCmdOutParams = packed record
  53. dwBufferSize: DWORD;
  54. dsDriverStatus: TDriverStatus;
  55. bBuffer: array[1..512] of Byte;
  56. end;
  57.  
  58. TGetVersionInParams = packed record
  59. bVersion,
  60. bRevision,
  61. bReserved,
  62. bIDEDeviceMap: Byte;
  63. dwCapabilities: DWORD;
  64. dwReserved: array[1..4] of DWORD;
  65. end;
  66. // ...
  67. procedure CorrectDevInfo(var _params: TSendCmdOutParams);
  68. asm
  69. lea edi, _params.bBuffer
  70.  
  71. add edi,14h
  72. mov ecx,0Ah
  73.  
  74. @@SerNumLoop: mov ax,[edi]
  75. xchg al,ah
  76. stosw
  77. loop @@SerNumLoop
  78.  
  79. add edi,6
  80. mov cl,18h
  81.  
  82. @@ModelNumLoop: mov ax,[edi]
  83. xchg al,ah
  84. stosw
  85. loop @@ModelNumLoop
  86. end;
  87.  
  88. function HddSerialAndModel(Param:String):String;
  89. var
  90. i: DWORD;
  91. FTmpHDD: string;
  92. dev: THandle;
  93. scip: TSendCmdInParams;
  94. scop: TSendCmdOutParams;
  95. gvip: TGetVersionInParams;
  96. ret: DWORD;
  97. begin
  98. dev := CreateFile('\\.\PhysicalDrive0', GENERIC_READ or GENERIC_WRITE,
  99. FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
  100. if dev <> INVALID_HANDLE_VALUE then
  101. begin
  102. if DeviceIoControl(dev, SMART_GET_VERSION, nil, 0, @gvip, SizeOf(gvip), ret, nil) then
  103. begin
  104. scip.dwBufferSize := 512;
  105. scip.bDriveNumber := 0;
  106. scip.irDriveRegs.bSectorCountReg := 1;
  107. scip.irDriveRegs.bSectorNumberReg := 1;
  108. scip.irDriveRegs.bDriveHeadReg := $A0; // ???
  109. scip.irDriveRegs.bCommandReg := ID_CMD; // ???
  110. if not DeviceIoControl(dev, SMART_RCV_DRIVE_DATA, @scip, SizeOf(scip), @scop, SizeOf(scop), ret, nil) then
  111. ShowMessage(SysErrorMessage(GetLastError))
  112. else
  113. if scop.dsDriverStatus.bDriverError = DRVERR_NO_ERROR then
  114. begin
  115. CorrectDevInfo(scop);
  116. if Param='Serial' then
  117. begin
  118. SetLength(FTmpHDD, 20);
  119. Move(scop.bBuffer[21], FTmpHDD[1], 20);
  120. Result:=FTmpHDD;
  121. end;
  122. if Param='Model' then
  123. begin
  124. SetLength(FTmpHDD, 40);
  125. Move(scop.bBuffer[55], FTmpHDD[1], 40);
  126. Result:=FTmpHDD;
  127. end;
  128. end
  129. else
  130. ShowMessageFmt('Error code: %d', [scop.dsDriverStatus.bDriverError])
  131. end
  132. else
  133. ShowMessage(SysErrorMessage(GetLastError));
  134. CloseHandle(dev);
  135. end;
  136. end;

 

Оставьте свой комментарий

Оставить комментарий как гость

0
  • Комментариев нет
Получить серийный номер жесткого диска (Delphi) - 5.0 out of 5 based on 1 vote