Einzelnen Beitrag anzeigen

dbdeath74

Registriert seit: 30. Aug 2005
53 Beiträge
 
#1

Problem beim auslesen der Festplatten Seriennummer

  Alt 20. Okt 2006, 10:12
Hallo,

ich schreibe gerade für uns ein Inventory Tool welches Hard- und Software der Geräte erfasst.
Zur Identifizierung des Gerätes mit unseren Stammdaten wird eine Equipment Nummer benutzt, welche normalerweise bei der Installation auf dem Gerät hinterlegt wird.

Nun kommt es leider vor das ein Gerät z.B. neu installiert wird ohne unser Wissen
Aus diesem Grund wollte ich zur Identifizierung des Gerätes einen weiteren Parameter hinzuziehen, mit dem ich erkennen kann ob es ein bekanntes Gerät ist.

Hier in der DP habe ich folgende Funktion gefunden zum auslesen der HDD Seriennummer. Sie funktioniert auch einwandfrei bei 90% unserer Geräte. Nur bei den restlichen bekomme ich beim anlegen des handle ein INVALID_HANDLE_VALUE zurück.

Die Platten unterstützen aber definitiv S.M.A.R.T. und HD-Tune kann auch problemlos die Seriennummer auslesen.

Hier mal die Funktion die ich benutze:

Delphi-Quellcode:
function GetIdeSerialNumber ():string;
const IDENTIFY_BUFFER_SIZE = 512;
type
  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;
  TSendCmdInParams = packed record
    // Buffer size in bytes
    cBufferSize : DWORD;
    // Structure with drive register values.
    irDriveRegs : TIDERegs;
    // Physical drive number to send command to (0,1,2,3).
    bDriveNumber : BYTE;
    bReserved : Array[0..2] of Byte;
    dwReserved : Array[0..3] of DWORD;
    bBuffer : Array[0..0] of Byte; // Input buffer.
  end;
  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 : DWORD;
    wMultSectorStuff : Word;
    ulTotalAddressableSectors : DWORD;
    wSingleWordDMA : Word;
    wMultiWordDMA : Word;
    bReserved : Array[0..127] of BYTE;
  end;
  PIdSector = ^TIdSector;
  TDriverStatus = packed record
    // Error code from driver, or 0 if no error.
    bDriverError : Byte;
    // Contents of IDE Error register. Only valid when bDriverError is SMART_IDE_ERROR.
    bIDEStatus : Byte;
    bReserved : Array[0..1] of Byte;
    dwReserved : Array[0..1] of DWORD;
  end;
  TSendCmdOutParams = packed record
    // Size of bBuffer in bytes
    cBufferSize : DWORD;
    // Driver status structure.
    DriverStatus : TDriverStatus;
    // Buffer of arbitrary length in which to store the data read from the drive.
    bBuffer : Array[0..0] of BYTE;
  end;

  var
    hDevice : THandle;
    cbBytesReturned : DWORD;
    SCIP : TSendCmdInParams;
    aIdOutCmd : Array [0..(SizeOf(TSendCmdOutParams)+IDENTIFY_BUFFER_SIZE-1)-1] of Byte;
    IdOutCmd : TSendCmdOutParams absolute aIdOutCmd;

  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 := ''; // return empty string on error
  if SysUtils.Win32Platform=VER_PLATFORM_WIN32_NT then // Windows NT, Windows 2000
    begin
      // warning! change name for other drives: ex.: second drive '\\.\PhysicalDrive1\'
      hDevice := CreateFile( '\\.\PhysicalDrive0', GENERIC_READ or GENERIC_WRITE,
        FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 );
    end
    else // Version Windows 95 OSR2, Windows 98
      hDevice := CreateFile( '\\.\SMARTVSD', 0, 0, nil, CREATE_NEW, 0, 0 );
  
  if hDevice=INVALID_HANDLE_VALUE then
  begin
   ShowMessage('Invalid Handle Value!');
   Exit;
  end;
  try
    FillChar(SCIP,SizeOf(TSendCmdInParams)-1,#0);
    FillChar(aIdOutCmd,SizeOf(aIdOutCmd),#0);
    cbBytesReturned := 0;
    // Set up data structures for IDENTIFY command.
    with SCIP do
    begin
      cBufferSize := IDENTIFY_BUFFER_SIZE;
// bDriveNumber := 0;
      with irDriveRegs do
      begin
        bSectorCountReg := 1;
        bSectorNumberReg := 1;
// if Win32Platform=VER_PLATFORM_WIN32_NT then bDriveHeadReg := $A0
// else bDriveHeadReg := $A0 or ((bDriveNum and 1) shl 4);
        bDriveHeadReg := $A0;
        bCommandReg := $EC;
      end;
    end;
    if not DeviceIoControl( hDevice, $0007c088, @SCIP, SizeOf(TSendCmdInParams)-1,
      @aIdOutCmd, SizeOf(aIdOutCmd), cbBytesReturned, nil ) then Exit;
  finally
    CloseHandle(hDevice);
  end;
  with PIdSector(@IdOutCmd.bBuffer)^ do
  begin
    ChangeByteOrder( sSerialNumber, SizeOf(sSerialNumber) );
    (PChar(@sSerialNumber)+SizeOf(sSerialNumber))^ := #0;
    Result := PChar(@sSerialNumber);
  end;
end;
Eine Beispielplatte bei der es nicht geht ist z.B. eine Seagate Momentus 5400 ST98823A 80GB
Hier mal der HD-Tune Auszug wo man eindeutig sieht das die Festplatte es normal kann:

Zitat:
HD Tune: ST98823A Information

Firmware version : 3.05
Serial number : 5PK0SKH2
Capacity : 74.5 GB (~80.0 GB)
Buffer size : 8192 KB
Standard : ATA/ATAPI-6
Supported mode : UDMA Mode 5 (Ultra ATA/100)
Current mode : UDMA Mode 5 (Ultra ATA/100)

S.M.A.R.T : yes
48-bit Address : no
Read Look-Ahead : yes
Write Cache : yes
Host Protected Area : no
Device Configuration Overlay : yes
Automatic Acoustic Management: no
Power Management : yes
Advanced Power Management : yes
Power-up in Standby : no
Security Mode : yes
Firmware Upgradable : yes
Kennt vielleicht jemand eine bessere/andere Methode an die HDD-Serial zu kommen? Oder kann mir sagen wieso ich ein INVALID_HANDLE_VALUE von Windows zurückbekomme beim Aufruf:
Delphi-Quellcode:
hDevice := CreateFile( '\\.\PhysicalDrive0', GENERIC_READ or GENERIC_WRITE,
        FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0 );
Ich wäre euch wirklich zu großem Dank verpflichtet

Gruß Oliver
  Mit Zitat antworten Zitat