Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Problem beim auslesen der Festplatten Seriennummer (https://www.delphipraxis.net/79323-problem-beim-auslesen-der-festplatten-seriennummer.html)

dbdeath74 20. Okt 2006 10:12


Problem beim auslesen der Festplatten Seriennummer
 
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 :wall:
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

nahpets 20. Okt 2006 12:11

Re: Problem beim auslesen der Festplatten Seriennummer
 
Schau doch mal hier im Forum bei dem aktuellen Thema MyPC nach, dass Programm kann die Seriennummern der Laufwerke auslesen.

MyPC-Thread

Stephan

dbdeath74 20. Okt 2006 13:22

Re: Problem beim auslesen der Festplatten Seriennummer
 
Hallo,

UPDATE: wie ich herausfinden konnte sind Adminrechte nötig um dieses Handle zu bekommen :gruebel:

Nur wieso brauche ich Adminrechte um die HD Serial auszulesen *grummel*
Andere Programme wie HD-Tune können das auch ohne Adminrechte ...

Also nochmal: kennt jemand einen Weg an die HD Serial zu kommen OHNE Adminrechte?

@nahpets: Ich schau es mir mal an, aber das Programm läuft nicht bei mir unter win2k SP4. Es kommt nur der SplashScreen und danach nichts mehr. Ich schau mir mal den Source an.

Gruß Oliver

Muetze1 20. Okt 2006 13:43

Re: Problem beim auslesen der Festplatten Seriennummer
 
Zitat:

Zitat von dbdeath74
Nur wieso brauche ich Adminrechte um die HD Serial auszulesen *grummel*

Du holst dir ein Handle zum direkten Zugriff auf die Festplatte und kannst somit von hinten auf die Festplatte, die Partitionen und Daten zugreifen. Damit könntest du die Daten zerschiessen - und das sollte jedes Programm mit User Rechten können - sicher?

Zitat:

Zitat von dbdeath74
Andere Programme wie HD-Tune können das auch ohne Adminrechte ...

Die besorgen sich für diese Aktion die Rechte bzw. lösen es über einen anderen Weg.

dbdeath74 20. Okt 2006 14:22

Re: Problem beim auslesen der Festplatten Seriennummer
 
Zitat:

Zitat von Muetze1
Du holst dir ein Handle zum direkten Zugriff auf die Festplatte und kannst somit von hinten auf die Festplatte, die Partitionen und Daten zugreifen. Damit könntest du die Daten zerschiessen - und das sollte jedes Programm mit User Rechten können - sicher?

Natürlich nicht. Beim genaueren Nachdenken warum es nur mit Admin Rechten geht ist mir dies auch klar geworden :?

Zitat:

Zitat von Muetze1
Die besorgen sich für diese Aktion die Rechte bzw. lösen es über einen anderen Weg.

Ja und genau das interessiert mich :( wie machen die das ?
Ich google mir ja schon den ganzen Tag die Finger wund :/

Ich habe hier einen zugegebnermassen alten Artikel gefunden der diese Problematik mit einer fast identischen Funktion beschreibt.
IDE harddisk serial
hier ist der handle aufruf aber
Delphi-Quellcode:
// Get SCSI port handle
      hDevice := CreateFile( 
        '\\.\Scsi0:', // Note: '\\.\C:' requires administrative permissions.
        GENERIC_READ or GENERIC_WRITE,
        FILE_SHARE_READ or FILE_SHARE_WRITE,
        nil, OPEN_EXISTING, 0, 0 );
1. geht das gar nicht
2. frage ich mich wieso er Scsi0 übergibt, aber oben in den Kommentaren schreibt das wäre für IDE Platten :gruebel:

Wenn mir jemand eine alternative Möglichkeit zum finden der Seriennummer aufzeigen kann wäre ich sehr dankbar :angel:
Die meisten Sachen man im Netz findet arbeiten ja mit GetVolumeInformation() .... was ja Schwachsinn ist weil das nur die Partionsnummer zurückliefert :(

Gruß Oliver

dbdeath74 23. Okt 2006 09:20

Re: Problem beim auslesen der Festplatten Seriennummer
 
Hallo,

meine weiteren Recherchen haben ergeben :

Ich kenne bisher zwei Methoden an die HDD Serial zu kommen.

1. Die Methode die ich oben gepostet habe. Braucht leider admin Rechte unter win2k.

2. Per wmi, braucht keine admin rechte. Geht leider erst ab XP :( wir haben noch win2k

3. Es MUSS eine dritte Möglichkeit ohne Adminrechte geben....
HD Tune kriegt es hin, es gibt "BEZAHL" Komponenten für Delphi die das können ( Delpji-Komponente)
Ja nur wie :?: Stundenlange Recherchen ahben bisher leider nichts ergebn :(
Bin nach wie vor über jeden Tip dankbar. Ich denke es muss über S.M.A.R.T. gehen.

Gruß Oliver

Thanatos81 23. Okt 2006 09:41

Re: Problem beim auslesen der Festplatten Seriennummer
 
Hmm, mal ne andere Überlegung. WEnn du jetzt schon stundenlang googlest und testest, wäre es nicht sinnvoller (von der Kostenseite) die $19,95 bis $59,95 für die Komponente auszugeben?

dbdeath74 23. Okt 2006 09:43

Re: Problem beim auslesen der Festplatten Seriennummer
 
Hmm

Möglich wäre das *g
Aber inzwischen hat mich der Ehrgeiz gepackt :D

Ausserdem wenn man so argumentiert könnte ich auch einfach eine der hunderte guten Inventory Tools nehmen die es günstig oder kostenlos auf dem Markt gibt :)

Gruß Oliver

ascotlx 23. Okt 2006 10:07

Re: Problem beim auslesen der Festplatten Seriennummer
 
Moin moin,

wie wär es mit GetVolumeInformation DP-Artikel . Ein Freund hat das mal so gemacht ....

Delphi-Quellcode:
function GetVolSNr:DWORD;
var
    dwSerialNumber : DWORD;
    dwMaxLength   : DWORD;
    dwFlags       : DWORD;

begin
    GetVolumeInformation(PChar('C:\'), nil, 0,
                         @dwSerialNumber, dwMaxLength,dwFlags,
                          nil, 0);
    Result := dwSerialNumber;
end;
Vielleicht hilft Dir das ja weiter ... (danke michael) :thumb:

Gruss

ascotlx

dbdeath74 23. Okt 2006 10:27

Re: Problem beim auslesen der Festplatten Seriennummer
 
Hallo,

wie oben erwähnt liefert GetVolumeInfo nur die Seriennummer der logischen Partition.
Welche untauglich ist da sie sich bei jeder Installation ändert.

Gruß Oliver

Muetze1 23. Okt 2006 21:33

Re: Problem beim auslesen der Festplatten Seriennummer
 
Zitat:

Zitat von dbdeath74
Ich denke es muss über S.M.A.R.T. gehen.

Ich kann dir versichern, dass S.M.A.R.T. die gleichen Rechte braucht, da es genauso ein Handle für das PhysicalDrive braucht.

negaH 24. Okt 2006 09:18

Re: Problem beim auslesen der Festplatten Seriennummer
 
Auch die anderen Tools, die den "dritten Weg" benutzen, benötigen Admin Rechte. Allerdings nur während des Setups der Anwendung wenn ein Treiber installiert wird. Ein Treiber wie GiveIO.sys oder ähnlichem. Denn der "dritte Weg" greift auf die IDE direkt und physikalisch auf die Ports der Laufwerke zu. Wurde also einmalig dieser Treiber installiert (nur unter NT nötig) dann kann später als normaler Benutzer die Funktionalität dieses Treibers benutzt werden, und ergo direkt auf die HD zugegriffen werden und finally somit direkt die HD Register ausgelsen werden, inklusive physikalsicher Serial Nummer.

Der "vierte Weg" für Dummies ist einfach in der Registry nachzuschauen. Am besten mal in der Registry die HD Serialnummer manuell ändern und du wirst sehen das viele der sogenannten "Hardware-Utilities" sich die Daten nur aus der Registry holen ;)

Gruß Hagen

Muetze1 24. Okt 2006 10:55

Re: Problem beim auslesen der Festplatten Seriennummer
 
Die nutzen einen Porttreiber bei IDE? Oh, das wäre doch mehr als kreuz-gefährlich, weil wie wollen sie anstehende bzw. gerade aktive Zugriffe des OS auf die Festplatte mitbekommen? Auch müssen sie sich die nötigen Zugriffe und Informationen für den PIC und DMA Controller holen bzw. über eine API ansprechen. Damit funken diese doch aber ganz schön Windows dazwischen. Das würde die Datensicherheit und Stabilität doch deutlich reduzieren - der Weg wäre mir als Firma/Entwickler einer Info-Software viel zu heikel...

dbdeath74 24. Okt 2006 11:53

Re: Problem beim auslesen der Festplatten Seriennummer
 
Hallo,

danke für eure Antworten :)

Die Methode die ich oben benutze ist ja über die S.M.A.R.T. features der Festplatte (und brauch leider admin rechte).

Die nächste Methode ist über WMI, geht ganz einfach, 5 Zeilen Code ... aber leider erst ab WinXP :(

Die dritte Methode die auch KEINE Admin rechte brauch geht direkt auf die Win API, soviel konnte ich herausfinden.
Aber ich habe leider nicht den Ansatz eines Codeschnippsels gefunden :(

@negaH:

Also HD-Tune braucht definitiv keine Admin rechte und wird nicht installiert. Probier es aus (HD Tune)
Und in der registry steht meines wissens nicht die wirkliche HDD Seriennummer, sondern nur die der logischen Laufwerke.
Ich lasse mich aber gerne eines besseren belehren, registry wäre optimal für mich da ich ja keinen kopierschutz bauen will und es nicht mit böswilligen Usern zu tun habe.

Aber vielleicht kommt ja noch ein WinAPI Guru vorbei der mir sagen kann wie man mit Hilfe der WinAPI vielleicht da ran kommen könnte.

Gruß Oliver

Muetze1 24. Okt 2006 12:56

Re: Problem beim auslesen der Festplatten Seriennummer
 
Zitat:

Zitat von dbdeath74
Und in der registry steht meines wissens nicht die wirkliche HDD Seriennummer, sondern nur die der logischen Laufwerke.

Nein, die Hardwaredaten werden dort mit abgelegt - u.a. auch die wichtigsten Daten des DEVICE INQUIRY bei den Laufwerken.

Vllt. könnte negaH nettwerweise einen kleinen Codeschnipsel posten um die Keys zu erreichen.

Luckie 24. Okt 2006 13:08

Re: Problem beim auslesen der Festplatten Seriennummer
 
Es würde reichen die Schlüssel zu nennen. ;)

dbdeath74 24. Okt 2006 15:16

Re: Problem beim auslesen der Festplatten Seriennummer
 
Zitat:

Zitat von Luckie
Es würde reichen die Schlüssel zu nennen. ;)

ja das würde reichen :)
ich habe die registry schon einmal nach meiner HDD Seriennummer durchsucht, also im Reintext hab ich sie nicht gefunden.

Gruß Oliver

TKC 24. Okt 2006 16:02

Re: Problem beim auslesen der Festplatten Seriennummer
 
schau mal hier

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\I DE

Muetze1 24. Okt 2006 16:26

Re: Problem beim auslesen der Festplatten Seriennummer
 
Zitat:

Zitat von ACE-ppc
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\I DE

Die hatte ich so halb auch im Sinn, habe sie aber nicht gepostet, da dort keine Seriennummer zu finden ist.

dbdeath74 26. Okt 2006 12:47

Re: Problem beim auslesen der Festplatten Seriennummer
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

ich habe jetzt eine Möglichkeit gefunden. Naja so halb ... *g
Ich habe eine Möglichkeit in c++ gefunden die funktioniert und kämpfe mit der Übersetzung :wall:

Hab leider nur rudimentäre c++ kenntnisse :cry:

Also die c++ Lösung gibt es hier:

diskid32, ist freeware und darf weiterverwendet werden.

Es wird im Prinzip auch die S.M.A.R.T. Werte ausgelesen wie ich es schon mache, nur das man es über eine Backdoor als angebliches scsi laufwerk anspricht und so windows austrickst *so habe ich das verstanden*

Falls sich jemand berufen fühlt mir bei der Übersetzung zu helfen :dp:

Es hapert im Moment an der Übersetzung der
Delphi-Quellcode:
STORAGE_PROPERTY_QUERY query;
Das ist ein selbstdefiniertes struct von ihm weiter oben das auf eine(für mich nicht verständliche) Weise von IOCTL_STORAGE_BASE erbt. Oder so *g

Ich würde mich freuen wenn mir jemand helfen könnte :)
Ich hänge mal den c++ code als attachment an und hier ist die fragliche Funktion
Code:
int ReadPhysicalDriveInNTWithZeroRights (void)
{
   int done = FALSE;
   int drive = 0;

   for (drive = 0; drive < MAX_IDE_DRIVES; drive++)
   {
      HANDLE hPhysicalDriveIOCTL = 0;

         //  Try to get a handle to PhysicalDrive IOCTL, report failure
         //  and exit if can't.
      char driveName [256];

      sprintf (driveName, "\\\\.\\PhysicalDrive%d", drive);

         //  Windows NT, Windows 2000, Windows XP - admin rights not required
      hPhysicalDriveIOCTL = CreateFile (driveName, 0,
                               FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
                               OPEN_EXISTING, 0, NULL);
      // if (hPhysicalDriveIOCTL == INVALID_HANDLE_VALUE)
      //    printf ("Unable to open physical drive %d, error code: 0x%lX\n",
      //            drive, GetLastError ());

      if (hPhysicalDriveIOCTL != INVALID_HANDLE_VALUE)
      {
       STORAGE_PROPERTY_QUERY query;
         DWORD cbBytesReturned = 0;
       char buffer [10000];

         memset ((void *) & query, 0, sizeof (query));
       query.PropertyId = StorageDeviceProperty;
       query.QueryType = PropertyStandardQuery;

       memset (buffer, 0, sizeof (buffer));

         if ( DeviceIoControl (hPhysicalDriveIOCTL, IOCTL_STORAGE_QUERY_PROPERTY,
                   & query,
                   sizeof (query),
               & buffer,
               sizeof (buffer),
                   & cbBytesReturned, NULL) )
         {         
          STORAGE_DEVICE_DESCRIPTOR * descrip = (STORAGE_DEVICE_DESCRIPTOR *) & buffer;
          char serialNumber [1000];
          char modelNumber [1000];

          strcpy (serialNumber,
                flipAndCodeBytes ( & buffer [descrip -> SerialNumberOffset]));
          strcpy (modelNumber, & buffer [descrip -> ProductIdOffset]);
          if (0 == HardDriveSerialNumber [0] &&
                  //  serial number must be alphanumeric
                     //  (but there can be leading spaces on IBM drives)
               (isalnum (serialNumber [0]) || isalnum (serialNumber [19])))
          {
            strcpy (HardDriveSerialNumber, serialNumber);
            strcpy (HardDriveModelNumber, modelNumber);
            done = TRUE;
          }
Gruß Oliver

TKC 26. Okt 2006 13:37

Re: Problem beim auslesen der Festplatten Seriennummer
 
Wie wärs denn damit ?
Delphi-Quellcode:
_STORAGE_PROPERTY_QUERY=record
PropertyId:STORAGE_PROPERTY_ID;
QueryType:STORAGE_QUERY_TYPE;
AdditionalParameters:Array[0..0] of UCHAR;
end;
STORAGE_PROPERTY_QUERY=_STORAGE_PROPERTY_QUERY;
PSTORAGE_PROPERTY_QUERY=^STORAGE_PROPERTY_QUERY;

dbdeath74 26. Okt 2006 14:12

Re: Problem beim auslesen der Festplatten Seriennummer
 
hmmm

Undefinierter Bezeichner 'STORAGE_PROPERTY_ID'
Undefinierter Bezeichner 'STORAGE_QUERY_TYPE'

was hast du da noch eingebunden ?

Ist das in der winioctl.h drin ?
Die hatte er bei c++ eingebunden, aber ich finde das equivalent in Delphi nicht :/

Gruß Oliver

TKC 26. Okt 2006 18:32

Re: Problem beim auslesen der Festplatten Seriennummer
 
ok.. hier der rest...
Delphi-Quellcode:
uses
  Windows;

const
  Method_Buffered            = 0;
  File_Any_Access            = 0;
  File_Device_Mass_Storage   = $0000002D;
  IOCTL_Storage_Base         = File_Device_Mass_Storage;
  MAX_IDE_DRIVES             = 16;

type

  PSTORAGE_BUS_TYPE = ^STORAGE_BUS_TYPE;
  STORAGE_BUS_TYPE = (BusTypeUnknown = $00, BusTypeScsi, BusTypeAtapi, BusTypeAta, BusType1394, BusTypeSsa, BusTypeFibre, BusTypeUsb, BusTypeRAID, BusTypeMaxReserved = $7F);

  PSTORAGE_QUERY_TYPE = ^STORAGE_QUERY_TYPE;
  STORAGE_QUERY_TYPE = (PropertyStandardQuery = 0, PropertyExistsQuery, PropertyMaskQuery, PropertyQueryMaxDefined);

  PSTORAGE_PROPERTY_ID = ^STORAGE_PROPERTY_ID;
  STORAGE_PROPERTY_ID = (StorageDeviceProperty = 0, StorageAdapterProperty);

  PSTORAGE_PROPERTY_QUERY = ^STORAGE_PROPERTY_QUERY;
  STORAGE_PROPERTY_QUERY = record
    PropertyId: STORAGE_PROPERTY_ID;
    QueryType: STORAGE_QUERY_TYPE;
    AdditionalParameters: array[0..0] of UCHAR;
  end;


  PSTORAGE_DEVICE_DESCRIPTOR = ^STORAGE_DEVICE_DESCRIPTOR;
  STORAGE_DEVICE_DESCRIPTOR = record
    Version: ULONG;
    Size: ULONG;
    DeviceType: UCHAR;
    DeviceTypeModifier: UCHAR;
    RemovableMedia: Boolean;
    CommandQueueing: Boolean;
    VendorIdOffset: ULONG;
    ProductIdOffset: ULONG;
    ProductRevisionOffset: ULONG;
    SerialNumberOffset: ULONG;
    BusType: STORAGE_BUS_TYPE;
    RawPropertiesLength: ULONG;
    RawDeviceProperties: array[0..0] of UCHAR;
  end;

dbdeath74 27. Okt 2006 15:32

Re: Problem beim auslesen der Festplatten Seriennummer
 
hmmm *kopfqualm* :wiejetzt:

So ganz verstehe ich nicht was der da treibt :(
Ich habe mal die Funktion mit deinen Änderungen versucht in Delphi zu übertragen.

Im Moment erstmal bis zum Aufruf von DeviceIoControl
Aber leider liefert der immer false.
Steigt vielleicht jemand mehr durch den c++ code von oben durch und sieht was ich falsch mache?

Gruß Oliver

Delphi-Quellcode:
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;

  PSTORAGE_BUS_TYPE = ^STORAGE_BUS_TYPE;
  STORAGE_BUS_TYPE = (BusTypeUnknown = $00, BusTypeScsi, BusTypeAtapi, BusTypeAta, BusType1394, BusTypeSsa, BusTypeFibre, BusTypeUsb, BusTypeRAID, BusTypeMaxReserved = $7F);

  PSTORAGE_QUERY_TYPE = ^STORAGE_QUERY_TYPE;
  STORAGE_QUERY_TYPE = (PropertyStandardQuery = 0, PropertyExistsQuery, PropertyMaskQuery, PropertyQueryMaxDefined);

  PSTORAGE_PROPERTY_ID = ^STORAGE_PROPERTY_ID;
  STORAGE_PROPERTY_ID = (StorageDeviceProperty = 0, StorageAdapterProperty);

  PSTORAGE_PROPERTY_QUERY = ^STORAGE_PROPERTY_QUERY;
  STORAGE_PROPERTY_QUERY = record
    PropertyId: STORAGE_PROPERTY_ID;
    QueryType: STORAGE_QUERY_TYPE;
    AdditionalParameters: array[0..0] of UCHAR;
  end;


  PSTORAGE_DEVICE_DESCRIPTOR = ^STORAGE_DEVICE_DESCRIPTOR;
  STORAGE_DEVICE_DESCRIPTOR = record
    Version: ULONG;
    Size: ULONG;
    DeviceType: UCHAR;
    DeviceTypeModifier: UCHAR;
    RemovableMedia: Boolean;
    CommandQueueing: Boolean;
    VendorIdOffset: ULONG;
    ProductIdOffset: ULONG;
    ProductRevisionOffset: ULONG;
    SerialNumberOffset: ULONG;
    BusType: STORAGE_BUS_TYPE;
    RawPropertiesLength: ULONG;
    RawDeviceProperties: array[0..0] of UCHAR;
  end;

  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. Must be 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;
     

const
  Method_Buffered            = 0;
  File_Any_Access            = 0;
  File_Device_Mass_Storage   = $0000002D;
  IOCTL_Storage_Base         = File_Device_Mass_Storage;
  MAX_IDE_DRIVES             = 16;

  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;
  query : STORAGE_PROPERTY_QUERY;
  IOCTL_STORAGE_QUERY_PROPERTY : cardinal;

begin
  IOCTL_STORAGE_QUERY_PROPERTY := CTL_CODE(IOCTL_STORAGE_BASE, $0500, METHOD_BUFFERED, FILE_ANY_ACCESS);
  Result := '';
  FillChar(Buffer,BufferSize,#0);
  if Win32Platform=VER_PLATFORM_WIN32_NT then
    begin // Windows NT, Windows 2000
      hDevice := CreateFile(
        '\\.\PhysicalDrive0',
        0, //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
        query.PropertyId := StorageDeviceProperty;
          query.QueryType := PropertyStandardQuery;

        if not DeviceIoControl( hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
          @query, sizeof (query), @Buffer, BufferSize,
          cbBytesReturned, nil ) then Exit;
      finally
        CloseHandle(hDevice);
      end;
    end;
end;

dbdeath74 31. Okt 2006 15:08

Re: Problem beim auslesen der Festplatten Seriennummer
 
Hallo,

gibt es denn keinen C++ Profi hier der sich des funktionierenden C++ codes mal annehmen könnte und ihn nach Delphi zu portieren? :love:
Ich komme damit nicht wirklich weiter :wiejetzt:

Gruß Oliver

DerDelphi 7. Dez 2006 11:06

Re: Problem beim auslesen der Festplatten Seriennummer
 
Hast du hier eine Lösung gefunden ? Würde das auch sehr gerne nutzen...

himitsu 16. Dez 2006 10:05

Re: Problem beim auslesen der Festplatten Seriennummer
 
Dazu sollte wohl nur mal erwähnt werden, daß man sich an die windows-/systemspezifischen Typen, Ausrichtungen, und Größen halten sollte, wenn man schon versucht derartiges zu machen.

hier nun eine korrekte Typendefinition (so wie sie von windows verwendet wird):
Delphi-Quellcode:
STORAGE_QUERY_TYPE = cardinal{PropertyStandardQuery = 0, PropertyExistsQuery = 1, PropertyMaskQuery = 2,
  PropertyQueryMaxDefined = 3};
STORAGE_PROPERTY_ID = cardinal{StorageDeviceProperty = 0, StorageAdapterProperty = 1};
STORAGE_PROPERTY_QUERY = packed record
  PropertyId: STORAGE_PROPERTY_ID;
  QueryType: STORAGE_QUERY_TYPE;
  AdditionalParameters: array[0..3] of UCHAR;
end;
Und hier noch eine zwar nicht ganz korrekte, aber dennoch Funtionierende:
In C++ sind STORAGE_QUERY_TYPE und STORAGE_PROPERTY_ID 4 Byte groß und nicht 1 Byte (so wie in Delphi).
Delphi-Quellcode:
STORAGE_QUERY_TYPE = (PropertyStandardQuery, PropertyExistsQuery, PropertyMaskQuery,
  PropertyQueryMaxDefined);
STORAGE_PROPERTY_ID = (StorageDeviceProperty, StorageAdapterProperty);
STORAGE_PROPERTY_QUERY = packed record
  PropertyId: STORAGE_PROPERTY_ID;
  _fill1: array[0..2] of byte;
  QueryType: STORAGE_QUERY_TYPE;
  _fill2: array[0..2] of byte;
  AdditionalParameters: array[0..3] of UCHAR;
end;

Delphi-Quellcode:
function GetIdeDiskSerialNumber: String;
  function CTL_CODE(DeviceType, Function_, Method, Access: cardinal): cardinal;
    begin result := (DeviceType shl 16) or (Access shl 14) or (Function_ shl 2) or Method; end;

  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;
    PSTORAGE_BUS_TYPE = ^STORAGE_BUS_TYPE;
    STORAGE_BUS_TYPE = (BusTypeUnknown = $00, BusTypeScsi, BusTypeAtapi, BusTypeAta,
      BusType1394, BusTypeSsa, BusTypeFibre, BusTypeUsb, BusTypeRAID, BusTypeMaxReserved = $7F);
    PSTORAGE_QUERY_TYPE = ^STORAGE_QUERY_TYPE;
    STORAGE_QUERY_TYPE = cardinal{PropertyStandardQuery = 0, PropertyExistsQuery = 1, PropertyMaskQuery = 2,
      PropertyQueryMaxDefined = 3};
    PSTORAGE_PROPERTY_ID = ^STORAGE_PROPERTY_ID;
    STORAGE_PROPERTY_ID = cardinal{StorageDeviceProperty = 0, StorageAdapterProperty = 1};
    PSTORAGE_PROPERTY_QUERY = ^STORAGE_PROPERTY_QUERY;
    STORAGE_PROPERTY_QUERY = packed record
      PropertyId: STORAGE_PROPERTY_ID;
      QueryType: STORAGE_QUERY_TYPE;
      AdditionalParameters: array[0..3] of UCHAR;
    end;
    PSTORAGE_DEVICE_DESCRIPTOR = ^STORAGE_DEVICE_DESCRIPTOR;
    STORAGE_DEVICE_DESCRIPTOR = record
      Version: ULONG;
      Size: ULONG;
      DeviceType: UCHAR;
      DeviceTypeModifier: UCHAR;
      RemovableMedia: Boolean;
      CommandQueueing: Boolean;
      VendorIdOffset: ULONG;
      ProductIdOffset: ULONG;
      ProductRevisionOffset: ULONG;
      SerialNumberOffset: ULONG;
      BusType: STORAGE_BUS_TYPE;
      RawPropertiesLength: ULONG;
      RawDeviceProperties: array[0..0] of UCHAR;
    end;
    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. Must be 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;

  const
    Method_Buffered = 0;
    File_Any_Access = 0;
    File_Device_Mass_Storage = $0000002D;
    IOCTL_Storage_Base = File_Device_Mass_Storage;
    MAX_IDE_DRIVES = 16;
    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;
    query : STORAGE_PROPERTY_QUERY;
    IOCTL_STORAGE_QUERY_PROPERTY : cardinal;

  begin
    IOCTL_STORAGE_QUERY_PROPERTY := CTL_CODE(IOCTL_STORAGE_BASE, $0500,
      METHOD_BUFFERED, FILE_ANY_ACCESS);
    Result := '';
    FillChar(Buffer,BufferSize,#0);
    if Win32Platform=VER_PLATFORM_WIN32_NT then begin // Windows NT, Windows 2000
      hDevice := CreateFile(
        '\\.\PhysicalDrive0',
        0, //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
        query.PropertyId := 0{StorageDeviceProperty};
        query.QueryType := 0{PropertyStandardQuery};
        if not DeviceIoControl( hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
          @query, sizeof (query), @Buffer, BufferSize,
          cbBytesReturned, nil ) then begin
          Form1.Label1.Caption := SysErrorMessage(GetLastError);
          Exit;
        end;
      finally
        CloseHandle(hDevice);
      end;
    end;
  end;

ach ja, für'n Anfang hätte man och ma versuchen können, sich die Fehlermeldung zu besorgen!
Delphi-Quellcode:
SysErrorMessage(GetLastError);
und bei der gegebenen Fehlermeldung ist wohl das Erste und Einfachste eine Vergößerung/Anpassung der Größer der Ein-/Ausgabepuffer. :zwinker:

Hanzmeierschulz 23. Dez 2006 14:40

Re: Problem beim auslesen der Festplatten Seriennummer
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi dbdeath74,
hab dir die Datei hddinfo.pas angehangen. Die Original-Version ist nicht von mir, habe aber diese so angepasst, dass sie nun auch unter NoAdmin-Rechten läuft (getestet mit Gast-Rechten) und ein paar Fehler behoben.

Delphi-Quellcode:
unit hddinfo;

interface

uses Windows, SysUtils, Classes;

const
  IOCTL_STORAGE_QUERY_PROPERTY = $2D1400;

type
THDDInfo = class (TObject)
private
  FDriveNumber: Byte;
  FFileHandle: Cardinal;
  FInfoAvailable: Boolean;
  FProductRevision: string;
  FProductId: string;
  FSerialNumber: string;
  FVendorId: string;
  procedure ReadInfo;
  procedure SetDriveNumber(const Value: Byte);
public
  constructor Create;
  property DriveNumber: Byte read FDriveNumber write SetDriveNumber;
  property VendorId: string read FVendorId;
  property ProductId: string read FProductId;
  property ProductRevision: string read FProductRevision;
  property SerialNumber: string read FSerialNumber;
  function SerialNumberInt: Cardinal;
  function SerialNumberText: string;
  function IsInfoAvailable: Boolean;
end;

implementation

type

STORAGE_PROPERTY_QUERY = packed record
  PropertyId: DWORD;
  QueryType: DWORD;
  AdditionalParameters: array[0..3] of Byte;
end;

STORAGE_DEVICE_DESCRIPTOR = packed record
  Version: ULONG;
  Size: ULONG;
  DeviceType: Byte;
  DeviceTypeModifier: Byte;
  RemovableMedia: Boolean;
  CommandQueueing: Boolean;
  VendorIdOffset: ULONG;
  ProductIdOffset: ULONG;
  ProductRevisionOffset: ULONG;
  SerialNumberOffset: ULONG;
  STORAGE_BUS_TYPE: DWORD;
  RawPropertiesLength: ULONG;
  RawDeviceProperties: array[0..511] of Byte;
end;

function ByteToChar(const B: Byte): Char;
begin
  Result := Chr(B + $30)
end;

function SerialNumberToCardinal (SerNum: String): Cardinal;
begin
  HexToBin(PChar(SerNum), PChar(@Result), SizeOf(Cardinal));
end;

function SerialNumberToString(SerNum: String): String;
var
  I, StrLen: Integer;
  Pair: string;
  B: Byte;
  Ch: Char absolute B;

begin
  Result := '';
  StrLen := Length(SerNum);

  if Odd(StrLen) then Exit;

  I := 1;

  while I < StrLen do
  begin
    Pair := Copy (SerNum, I, 2);
    HexToBin(PChar(Pair), PChar(@B), 1);
    Result := Result + Chr(B);
    Inc(I, 2);
  end;

  I := 1;

  while I < Length(Result) do
  begin
    Ch := Result[I];
    Result[I] := Result[I + 1];
    Result[I + 1] := Ch;
    Inc(I, 2);
  end;
end;

constructor THddInfo.Create;
begin
  inherited;

  SetDriveNumber(0);
end;

function THDDInfo.IsInfoAvailable: Boolean;
begin
  Result := FInfoAvailable
end;

procedure THDDInfo.ReadInfo;
type
  PCharArray = ^TCharArray;
  TCharArray = array[0..32767] of Char;

var
  Returned: Cardinal;
  Status: LongBool;
  PropQuery: STORAGE_PROPERTY_QUERY;
  DeviceDescriptor: STORAGE_DEVICE_DESCRIPTOR;
  PCh: PChar;

begin
  FInfoAvailable := False;
  FProductRevision := '';
  FProductId := '';
  FSerialNumber := '';
  FVendorId := '';

  try
    FFileHandle := CreateFile(
                     PChar('\\.\PhysicalDrive' + ByteToChar(FDriveNumber)),
                     0,
                     FILE_SHARE_READ or FILE_SHARE_WRITE,
                     nil,
                     OPEN_EXISTING,
                     0,
                     0
                   );

    if FFileHandle = INVALID_HANDLE_VALUE then RaiseLastOSError;

    ZeroMemory(@PropQuery, SizeOf(PropQuery));
    ZeroMemory(@DeviceDescriptor, SizeOf(DeviceDescriptor));

    DeviceDescriptor.Size := SizeOf(DeviceDescriptor);

    Status := DeviceIoControl(
                FFileHandle,
                IOCTL_STORAGE_QUERY_PROPERTY,
                @PropQuery,
                SizeOf(PropQuery),
                @DeviceDescriptor,
                DeviceDescriptor.Size,
                Returned,
                nil
              );

    if not Status then RaiseLastOSError;

    if DeviceDescriptor.VendorIdOffset <> 0 then
    begin
      PCh := @PCharArray(@DeviceDescriptor)^[DeviceDescriptor.VendorIdOffset];
      FVendorId := PCh;
    end;

    if DeviceDescriptor.ProductIdOffset <> 0 then
    begin
      PCh := @PCharArray(@DeviceDescriptor)^[DeviceDescriptor.ProductIdOffset];
      FProductId := PCh;
    end;

    if DeviceDescriptor.ProductRevisionOffset <> 0 then
    begin
      PCh := @PCharArray(@DeviceDescriptor)^[DeviceDescriptor.ProductRevisionOffset];
      FProductRevision := PCh;
    end;

    if DeviceDescriptor.SerialNumberOffset <> 0 then
    begin
      PCh := @PCharArray(@DeviceDescriptor)^[DeviceDescriptor.SerialNumberOffset];
      FSerialNumber := PCh;
    end;

    FInfoAvailable := True;
  finally
    if FFileHandle <> INVALID_HANDLE_VALUE then CloseHandle(FFileHandle);
  end;
end;

function THDDInfo.SerialNumberInt: Cardinal;
begin
  Result := 0;
  if ((IsInfoAvailable = True) and (FSerialNumber <> '')) then Result := SerialNumberToCardinal(FSerialNumber)
end;

function THDDInfo.SerialNumberText: string;
begin
  Result := '';
  if ((IsInfoAvailable = True) and (FSerialNumber <> '')) then Result := SerialNumberToString(FSerialNumber)
end;

procedure THDDInfo.SetDriveNumber(const Value: Byte);
begin
  FDriveNumber := Value;
  ReadInfo;
end;

end.

ich.online 27. Apr 2007 18:11

Re: Problem beim auslesen der Festplatten Seriennummer
 
Zitat:

Zitat von dbdeath74
Hallo,

ich schreibe gerade für uns ein Inventory Tool welches Hard- und Software der Geräte erfasst.

Hallo,

habe den Code mal eben in eine Unit kopiert. Auf den Notebook mit IDE funktioniert das. Auf meiner Wks mit Ultra320 kommt nur ein Leerstring zurück.

Gruß

K.-D.

quantum 27. Apr 2007 19:20

Re: Problem beim auslesen der Festplatten Seriennummer
 
Auf http://artsoft.nm.ru/ findest du die neuste Version von HDDInfo. Bei mir funktioniert diese Komponente hervorragend!

ich.online 27. Apr 2007 19:41

Re: Problem beim auslesen der Festplatten Seriennummer
 
Mehr gibt es nicht. Aber für den Kopierschutz reicht mir ja die Seriennummer.

gimAuto
IDE Primary Master
Type: Fixed
LBA sectors: 0
Cylinders: 0
Heads: 0
Tracks: 0
Sectors per track: 0
Size: 0 Mb
Controller buffer size: 0 Kb
ECC Code: 0
Model: FUJITSU MAP3367NC
Firmware Revision: 0108

gimByName
Device PhysicalDrive0:
Type: Fixed
Model: FUJITSU MAP3367NC
Firmware Revision: 0108
Serial Number: UPR7P3C00KEA

Beim Notebook mit IDE werden alle Details angezeigt.

Gruß
K.-D.

Zacherl 27. Apr 2007 22:04

Re: Problem beim auslesen der Festplatten Seriennummer
 
Wo wird denn hier ein Result zurückgegeben? Irgendwie scheine ich blind :D Wenn ich den Buffer ausgebe, kommt nur ein einziges Zeichen zu stande: (

Komisch irgendwie ..

kachwahed 14. Nov 2011 20:09

AW: Problem beim auslesen der Festplatten Seriennummer
 
Hello everybody :)
Because the first method (WithZeroRights) doesn't work for me, I wrote another for ReadIdeDriveAsScsiDriveInNT method:
Delphi-Quellcode:
unit HDScsiInfo;

interface

uses
  Windows, SysUtils;

const
  IDENTIFY_BUFFER_SIZE = 512;
  FILE_DEVICE_SCSI = $0000001b;
  IOCTL_SCSI_MINIPORT_IDENTIFY = ((FILE_DEVICE_SCSI shl 16) + $0501);
  IDE_ATA_IDENTIFY = $EC; //  Returns ID sector for ATA.
  IOCTL_SCSI_MINIPORT = $0004D008; //  see NTDDSCSI.H for definition

type
  TDiskData = array [0..256-1] of DWORD;
  TDriveInfo = record
    ControllerType: Integer; //0 - primary, 1 - secondary, 2 - Tertiary, 3 - Quaternary
    DriveMS: Integer; //0 - master, 1 - slave
    DriveModelNumber: String;
    DriveSerialNumber: String;
    DriveControllerRevisionNumber: String;
    ControllerBufferSizeOnDrive: Int64;
    DriveType: String; //fixed or removable or unknown
    DriveSizeBytes: Int64;
  end;

  THDScsiInfo = class (TObject)
  private
    FDriveNumber: Byte;
    FFileHandle: Cardinal;
    FInfoAvailable: Boolean;
    FProductRevision: string;
    FSerialNumber: string;
    FControllerType: Integer;
    FDriveMS: Integer;
    FDriveModelNumber: string;
    FControllerBufferSizeOnDrive: Int64;
    FDriveType: string;
    FDriveSizeBytes: Int64;
    procedure ReadInfo;
    procedure SetDriveNumber(const Value: Byte);
    procedure PrintIdeInfo(DiskData: TDiskData);
  public
    constructor Create;
    property DriveNumber: Byte read FDriveNumber write SetDriveNumber;
    property ProductRevision: string read FProductRevision;
    property SerialNumber: string read FSerialNumber;
    property ControllerType: Integer read FControllerType;
    property DriveMS: Integer read FDriveMS;
    property DriveModelNumber: string read FDriveModelNumber;
    property ControllerBufferSizeOnDrive: Int64 read FControllerBufferSizeOnDrive;
    property DriveType: string read FDriveType;
    property DriveSizeBytes: Int64 read FDriveSizeBytes;
    function IsInfoAvailable: Boolean;
  end;

implementation

type

  SRB_IO_CONTROL = record
   HeaderLength: Cardinal;
   Signature: array [0..8-1] of Byte;
   Timeout: Cardinal;
   ControlCode: Cardinal;
   ReturnCode: Cardinal;
   Length: Cardinal;
  end;
  PSRB_IO_CONTROL = ^SRB_IO_CONTROL;

  DRIVERSTATUS = record
   bDriverError: Byte;//  Error code from driver, or 0 if no error.
   bIDEStatus: Byte;//  Contents of IDE Error register.
                        //  Only valid when bDriverError is SMART_IDE_ERROR.
   bReserved: array [0..1] of Byte;//  Reserved for future expansion.
   dwReserved: array [0..1] of Longword;//  Reserved for future expansion.
  end;

  SENDCMDOUTPARAMS = record
   cBufferSize: Longword;//  Size of bBuffer in bytes
   DriverStatus: DRIVERSTATUS;//  Driver status structure.
   bBuffer: array [0..0] of Byte;//  Buffer of arbitrary length in which to store the data read from the                                                      // drive.
  end;
  IDEREGS = 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;
  SENDCMDINPARAMS = record
   cBufferSize: Longword;//  Buffer size in bytes
   irDriveRegs: IDEREGS;  //  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 Longword;//  For future use.
   bBuffer: array [0..0] of Byte;//  Input buffer.    //!TODO: this is array of single element
  end;
  PSENDCMDINPARAMS = ^SENDCMDINPARAMS;

  PSENDCMDOUTPARAMS = ^SENDCMDOUTPARAMS;
  IDSECTOR = record
   wGenConfig: Word;
   wNumCyls: Word;
   wReserved: Word;
   wNumHeads: Word;
   wBytesPerTrack: Word;
   wBytesPerSector: Word;
   wSectorsPerTrack: Word;
   wVendorUnique: array [0..3-1] of Word;
   sSerialNumber: array [0..20-1] of AnsiChar;
   wBufferType: Word;
   wBufferSize: Word;
   wECCSize: Word;
   sFirmwareRev: array [0..8-1] of AnsiChar;
   sModelNumber: array [0..40-1] of AnsiChar;
   wMoreVendorUnique: Word;
   wDoubleWordIO: Word;
   wCapabilities: Word;
   wReserved1: Word;
   wPIOTiming: Word;
   wDMATiming: Word;
   wBS: Word;
   wNumCurrentCyls: Word;
   wNumCurrentHeads: Word;
   wNumCurrentSectorsPerTrack: Word;
   ulCurrentSectorCapacity: Cardinal;
   wMultSectorStuff: Word;
   ulTotalAddressableSectors: Cardinal;
   wSingleWordDMA: Word;
   wMultiWordDMA: Word;
   bReserved: array [0..128-1] of Byte;
  end;
  PIDSECTOR = ^IDSECTOR;

  TArrayDriveInfo = array of TDriveInfo;

type
  DeviceQuery = record
   HeaderLength: Cardinal;
   Signature: array [0..8-1] of Byte;
   Timeout: Cardinal;
   ControlCode: Cardinal;
   ReturnCode: Cardinal;
   Length: Cardinal;
   cBufferSize: Longword;//  Buffer size in bytes
   irDriveRegs: IDEREGS;  //  Structure with drive register values.
   bDriveNumber: Byte;//  Physical drive number to send
   bReserved: array[0..2] of Byte;//  Reserved for future expansion.
   dwReserved: array [0..3] of Longword;//  For future use.
   bBuffer: array [0..0] of Byte;//  Input buffer.    //!TODO: this is array of single element
  end;

function ConvertToString (diskdata: TDiskData;
               firstIndex: Integer;
               lastIndex: Integer;
               buf: PAnsiChar): PAnsiChar;
var
   index: Integer;
   position: Integer;
begin
   position := 0;
      //  each integer has two characters stored in it backwards
   for index := firstIndex to lastIndex do begin
         //  get high byte for 1st character
      buf[position] := AnsiChar(Chr(diskdata [index] div 256));
      inc(position);
         //  get low byte for 2nd character
      buf [position] := AnsiChar(Chr(diskdata [index] mod 256));
      inc(position);
   end;
      //  end the string
   buf[position] := Chr(0);

      //  cut off the trailing blanks
   index := position - 1;
   while (index >0) do begin
//      if not IsSpace(AnsiChar(buf[index]))
      if (AnsiChar(buf[index]) <> ' ')
        then break;
      buf [index] := Chr(0);
      dec(index);
   end;

   Result := buf;
end;

constructor THDScsiInfo.Create;
begin
  inherited;
  SetDriveNumber(0);
end;

function THDScsiInfo.IsInfoAvailable: Boolean;
begin
  Result := FInfoAvailable
end;

procedure THDScsiInfo.PrintIdeInfo (DiskData: TDiskData);
var
  nSectors: Int64;
  serialNumber: array [0..1024-1] of AnsiChar;
  modelNumber: array [0..1024-1] of AnsiChar;
  revisionNumber: array [0..1024-1] of AnsiChar;
begin
      //  copy the hard drive serial number to the buffer
   ConvertToString (DiskData, 10, 19, @serialNumber);
   ConvertToString (DiskData, 27, 46, @modelNumber);
   ConvertToString (DiskData, 23, 26, @revisionNumber);
   FControllerType := FDriveNumber div 2;
   FDriveMS := FDriveNumber mod 2;
   FDriveModelNumber := modelNumber;
   FSerialNumber := serialNumber;
   FProductRevision := revisionNumber;
   FControllerBufferSizeOnDrive := DiskData [21] * 512;
   if ((DiskData [0] and $0080) <> 0)
      then FDriveType := 'Removable'
      else if ((DiskData [0] and $0040) <> 0)
          then FDriveType := 'Fixed'
          else FDriveType := 'Unknown';
//  calculate size based on 28 bit or 48 bit addressing
//  48 bit addressing is reflected by bit 10 of word 83
  if ((DiskData[83] and $400) <> 0) then begin
      nSectors := DiskData[103] * Int64(65536) * Int64(65536) * Int64(65536) +
                    DiskData[102] * Int64(65536) * Int64(65536) +
                    DiskData[101] * Int64(65536) +
                    DiskData[100];
  end else begin
        nSectors := DiskData [61] * 65536 + DiskData [60];
  end;
//  there are 512 bytes in a sector
  FDriveSizeBytes := nSectors * 512;
end;

procedure THDScsiInfo.ReadInfo;
type
  DataArry = array [0..256-1] of WORD;
  PDataArray = ^DataArry;
const
  SENDIDLENGTH = sizeof (SENDCMDOUTPARAMS) + IDENTIFY_BUFFER_SIZE;
var
  I: Integer;
  buffer: array [0..sizeof (SRB_IO_CONTROL) + SENDIDLENGTH - 1] of AnsiChar;
  dQuery: DeviceQuery;
  dummy: DWORD;
  pOut: PSENDCMDOUTPARAMS;
  pId: PIDSECTOR;
  DiskData: TDiskData;
  pIdSectorPtr: PWord;
begin
  FInfoAvailable := False;
  FFileHandle := CreateFile (PChar(Format('\\.\Scsi%d:', [FDriveNumber])),
                             GENERIC_READ or GENERIC_WRITE,
                             FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
                             OPEN_EXISTING, 0, 0);
  if (FFileHandle <> INVALID_HANDLE_VALUE) then begin
        ZeroMemory(@dQuery, SizeOf(dQuery));
        dQuery.HeaderLength := sizeof (SRB_IO_CONTROL);
        dQuery.Timeout := 10000;
        dQuery.Length := SENDIDLENGTH;
        dQuery.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY;
        StrLCopy(@dQuery.Signature, 'SCSIDISK', 8);
        dQuery.irDriveRegs.bCommandReg := IDE_ATA_IDENTIFY;
        dQuery.bDriveNumber := FDriveNumber;
        if (DeviceIoControl (FFileHandle, IOCTL_SCSI_MINIPORT,
                             @dQuery,
                             SizeOf(dQuery),
                             @buffer,
                             sizeof (SRB_IO_CONTROL) + SENDIDLENGTH,
                             dummy, nil))
        then begin
           pOut := PSENDCMDOUTPARAMS(buffer + sizeof (SRB_IO_CONTROL)); //!TOCHECK
           pId := PIDSECTOR(@pOut^.bBuffer[0]);
           if (pId^.sModelNumber[0] <> Chr(0) ) then begin
              pIdSectorPtr := PWord(pId);
              for I := 0 to 256-1 do
                 DiskData[I] := PDataArray(pIdSectorPtr)[I];
              PrintIdeInfo (DiskData);
              FInfoAvailable := True;
           end;

     end;
     CloseHandle(FFileHandle);
  end;
end;

procedure THDScsiInfo.SetDriveNumber(const Value: Byte);
begin
  FDriveNumber := Value;
  ReadInfo;
end;

end.
Sample usage:
Delphi-Quellcode:
procedure ReadIdeDriveAsScsiDriveInNT;
var
  DriveNumber: Byte;
  HDDInfo: THDScsiInfo;
begin
  HDDInfo := THDScsiInfo.Create();
  try
    for DriveNumber := 0 to MAX_IDE_DRIVES - 1 do
    try
      HDDInfo.DriveNumber := DriveNumber;
      if HDDInfo.IsInfoAvailable then begin
        Writeln('Available Drive: ', HDDInfo.DriveNumber);
        Writeln('ControllerType: ', HDDInfo.ControllerType);
        Writeln('DriveMS: ', HDDInfo.DriveMS);
        Writeln('DriveModelNumber: ', HDDInfo.DriveModelNumber);
        Writeln('ControllerBufferSizeOnDrive: ', HDDInfo.ControllerBufferSizeOnDrive);
        Writeln('DriveType: ', HDDInfo.DriveType);
        Writeln('DriveSizeBytes: ', HDDInfo.DriveSizeBytes);
        Writeln('ProductRevision: ', HDDInfo.ProductRevision);
        Writeln('SerialNumber: ', HDDInfo.SerialNumber);
      end;
    except
      on E: Exception do
        Writeln(Format('DriveNumber %d, %s: %s', [DriveNumber, E.ClassName, E.Message]));
    end;
  finally
    HDDInfo.Free;
  end;
end;

begin
  ReadIdeDriveAsScsiDriveInNT;
  Write('Press <Enter>');
end.
This works with my WD disk.
Sorry, I don't speak German :(

slemke76 26. Sep 2015 12:28

AW: Problem beim auslesen der Festplatten Seriennummer
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo zusammen,

ich habe die auf der vorherigen Seite verwendete Unif hddinfo.pas benutzt, da ich vor dem gleichen Problem stehe; funktioniert hat sie ad-hoc allerdings nicht.

Grund ist, dass PChar inzwischen PWideChar entspricht und somit die Adressen der Zeiger für das Lesen aus DeviceDescriptor nicht mehr passen.

Ich habe die Definitionen und PCh und TCharArray entsprechend angepasst und nu läuft die Unit wieder.

lg
Sebastian

Sir Rufo 26. Sep 2015 12:58

AW: Problem beim auslesen der Festplatten Seriennummer
 
So ist
Delphi-Quellcode:
PChar
definiert:
Delphi-Quellcode:
type
  PChar = {$IFDEF UNICODE}PWideChar{$ELSE}PAnsiChar{$ENDIF};
Wenn man es richtig macht, kann man so eine Unit auch generell nutzbar erstellen (unabhängig von Ansi/Unicode)

slemke76 26. Sep 2015 13:20

AW: Problem beim auslesen der Festplatten Seriennummer
 
Hi,

da bin ich bei dir ;-) Problem war bei mir, dass ich im ersten Moment nicht wusste / realisiert habe, wo dran das liegt, ich hatte erst einmal den DeviceIoControl Aufruf in Verdacht. Deswegen dachte ich, ich poste das mal, vlt. spart das jemanden irgenwann einmal Arbeit ;-)

lg
Sebastian


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:18 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz