w Delphi7, Jak mogę odzyskać unikalny numer seryjny dysku twardego?

Cześć Chcę odzyskać unikalny (sprzętowy) numer seryjny dysku twardego. Używam niektórych funkcji, ale w Windows Seven lub Vista nie działają poprawnie z powodu prawa administratora. Czy jest możliwe odzyskanie go bez uruchomienia jako Administrator?

Author: Sertac Akyuz, 2011-03-05

5 answers

Podążając za linkami w komentarzach do pytania Sertac, natknąłem się na to ciekawe pytanie C++ , Gdzie Fredou odpowiedział ładnym linkiem do przykładu codeproject pokazującego, jak to zrobić w.Net, który z kolei został oparty na linku do kodu Borland C++ i Artykuł.

Najfajniejsze jest to, że ten kod C++ działa również jako użytkownik nie-administrator!

Teraz potrzebujesz kogoś, kto pomoże Ci to przetłumaczyć Kod C++ do Delphi.

Edytuj: znalazłem jednostkę Delphi, która robi to za Ciebie.

Napisałem do niego przykładowe użycie:

program DiskDriveSerialConsoleProject;

{$APPTYPE CONSOLE}

uses
  Windows,
  SysUtils,
  hddinfo in 'hddinfo.pas';

const
  // Max number of drives assuming primary/secondary, master/slave topology
  MAX_IDE_DRIVES = 16;

procedure ReadPhysicalDriveInNTWithZeroRights ();
var
  DriveNumber: Byte;
  HDDInfo: THDDInfo;
begin
  HDDInfo := THDDInfo.Create();
  try
    for DriveNumber := 0 to MAX_IDE_DRIVES - 1 do
    try
      HDDInfo.DriveNumber := DriveNumber;
      if HDDInfo.IsInfoAvailable then
      begin
        Writeln('VendorId: ', HDDInfo.VendorId);
        Writeln('ProductId: ', HDDInfo.ProductId);
        Writeln('ProductRevision: ', HDDInfo.ProductRevision);
        Writeln('SerialNumber: ', HDDInfo.SerialNumber);
        Writeln('SerialNumberInt: ', HDDInfo.SerialNumberInt);
        Writeln('SerialNumberText: ', HDDInfo.SerialNumberText);
      end;
    except
      on E: Exception do
        Writeln(Format('DriveNumber %d, %s: %s', [DriveNumber, E.ClassName, E.Message]));
    end;
  finally
    HDDInfo.Free;
  end;
end;

begin
  ReadPhysicalDriveInNTWithZeroRights;
  Write('Press <Enter>');
  Readln;
end.

Jednostka z http://www.delphipraxis.net/564756-post28.html

// http://www.delphipraxis.net/564756-post28.html

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.

Edytuj: konfiguracje RAID wymagają specjalnych postanowień.

Na przykład, mam system RAID z wieloma macierzami RAID 5; wyświetla się tylko pierwsza i nie pokazuje numerów seryjnych dysku, ale serial Numer Tablicy RAID:

VendorId: AMCC
ProductId: 9550SXU-16ML
ProductRevision: 3.08
SerialNumber: 006508296D6A2A00DE82
SerialNumberInt: 688416000

--jeroen

 20
Author: Jeroen Wiert Pluimers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:27:45

Możesz użyć WMI (Windows Management Instrumentation) aby uzyskać informacje dotyczące sprzętu windows.

Istnieją dwie klasy wmi, które eksponują właściwość o nazwie SerialNumber, która przechowuje the Number allocated by the manufacturer to identify the physical media. te klasy są Win32_DiskDrive oraz Win32_PhysicalMedia.aby uzyskać dostęp do właściwości SerialNumber tych klas, musisz znać DeviceId dysku, który jest czymś takim \\.\PHYSICALDRIVE0. Innym sposobem jest użycie klasy asocjacji, która łączy Dysk fizyczny z dyskiem logicznym (C,D,E)

Więc musisz znaleźć to link poprzedni, aby uzyskać numer seryjny. Sekwencja do znalezienia tego związku jest taka.

Win32_DiskPartition -> Win32_LogicalDiskToPartition -> Win32_DiskDrive

Uwaga 1 : właściwość SerialNumber dla klasy Win32_DiskDrive nie istnieje w systemach Windows Server 2003, Windows XP, Windows 2000 i Windows NT 4.0, więc sposób, w jaki mówisz o użyciu systemu Windows Vista lub Windows 7, będzie dla Ciebie odpowiedni.

Uwaga 2 : kod nie wymaga konta administratora uciekaj.

Sprawdź ten kod

{$APPTYPE CONSOLE}

uses
  SysUtils,
  ActiveX,
  ComObj,
  Variants;

function GetDiskSerial(const Drive:AnsiChar):string;
var
  FSWbemLocator  : OLEVariant;
  objWMIService  : OLEVariant;
  colDiskDrives  : OLEVariant;
  colLogicalDisks: OLEVariant;
  colPartitions  : OLEVariant;
  objDiskDrive   : OLEVariant;
  objPartition   : OLEVariant;
  objLogicalDisk : OLEVariant;
  oEnumDiskDrive : IEnumvariant;
  oEnumPartition : IEnumvariant;
  oEnumLogical   : IEnumvariant;
  iValue         : LongWord;
  DeviceID       : string;
begin;
  Result:='';
  FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator');
  objWMIService := FSWbemLocator.ConnectServer('localhost', 'root\CIMV2', '', ''); //Connect to the WMI
  colDiskDrives := objWMIService.ExecQuery('SELECT * FROM Win32_DiskDrive','WQL',0);
  oEnumDiskDrive:= IUnknown(colDiskDrives._NewEnum) as IEnumVariant;
  while oEnumDiskDrive.Next(1, objDiskDrive, iValue) = 0 do
  begin
   DeviceID        := StringReplace(objDiskDrive.DeviceID,'\','\\',[rfReplaceAll]); //Escape the `\` chars in the DeviceID value because the '\' is a reserved character in WMI.
   colPartitions   := objWMIService.ExecQuery(Format('ASSOCIATORS OF {Win32_DiskDrive.DeviceID="%s"} WHERE AssocClass = Win32_DiskDriveToDiskPartition',[DeviceID]));//link the Win32_DiskDrive class with the Win32_DiskDriveToDiskPartition class
   oEnumPartition  := IUnknown(colPartitions._NewEnum) as IEnumVariant;
    while oEnumPartition.Next(1, objPartition, iValue) = 0 do
     begin
        colLogicalDisks := objWMIService.ExecQuery('ASSOCIATORS OF {Win32_DiskPartition.DeviceID="'+objPartition.DeviceID+'"} WHERE AssocClass = Win32_LogicalDiskToPartition'); //link the Win32_DiskPartition class with theWin32_LogicalDiskToPartition class.
        oEnumLogical  := IUnknown(colLogicalDisks._NewEnum) as IEnumVariant;
          while oEnumLogical.Next(1, objLogicalDisk, iValue) = 0 do
          begin
            if objLogicalDisk.DeviceID=(Drive+':')  then //compare the device id
            begin
                Result:=objDiskDrive.SerialNumber;
                Exit;
            end;
           objLogicalDisk:=Unassigned;
          end;
        objPartition:=Unassigned;
     end;
  end;
end;


begin
 try
    CoInitialize(nil);
    try
      Writeln(GetDiskSerial('C'));
      Readln;
    finally
    CoUninitialize;
    end;
 except
    on E:Exception do
    begin
        Writeln(E.Classname, ':', E.Message);
        Readln;
    end;
  end;
end.
 6
Author: RRUZ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-03-06 21:40:11

Oto kolejny diskid32 tłumaczenie z C++ do Delphi Victor Derevyanko

Projekt: http://code.google.com/p/dvsrc/

Ponieważ pierwsza metoda (Zzerorights) nie działa dla mnie, napisałem kolejną dla metody ReadIdeDriveAsScsiDriveInNT:

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.

Przykładowe użycie:

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.
To działa świetnie z moim dyskiem WD.
 1
Author: Kachwahed,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-14 19:49:17

Znalazłem ten kod, jest naprawiony i działa dobrze ze mną na windows 7 64

Https://code.google.com/p/dvsrc/downloads/detail?name=20120116DiskId32Port_fixed.7z&can=2&q=

And this his all work

Https://code.google.com/p/dvsrc/downloads/list

 1
Author: wahm sarab,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-27 11:00:07

Publikowanie tego wyłącznie dla kompletności, i ewentualnie zadowolić zainteresowanych lub fanatyków hardware.

Nie mam kompilatora Pascala do testowania tych procedur na obecnych systemach Windows, ale wiem, że ten kod działał w erze DOS. Może nadal działa z okna wiersza polecenia.

Kod Pascala:

uses
  Dos, Crt;

type
  SerNoType = record
    case Integer of
      0: (SerNo1, SerNo2: Word);
      1: (SerNo: Longint);
  end;

  DiskSerNoInfoType = record
    Infolevel: Word;
    VolSerNo: SerNoType;
    VolLabel: array[1..11] of Char;
    FileSys: array[1..8] of Char;
  end;

function HexDigit(N: Byte): Char;
begin
  if N < 10 then
    HexDigit := Chr(Ord('0') + N)
  else
    HexDigit := Chr(Ord('A') + (N - 10));
end;

function GetVolSerialNo(DriveNo: Byte): String;
var
  ReturnArray: DiskSerNoInfoType;
  Regs: Registers;
begin
  with Regs do
  begin
    AX := $440d;
    BL := DriveNo;
    CH := $08;
    CL := $66;
    DS := Seg(ReturnArray);
    DX := Ofs(ReturnArray);
    Intr($21, Regs);
    if (Flags and FCarry) <> 0 then
      GetVolSerialNo := ''
    else
      with ReturnArray.VolSerNo do
        GetVolSerialNo :=
          HexDigit(Hi(SerNo2) div 16) + HexDigit(Hi(SerNo2) mod 16) +
          HexDigit(Lo(SerNo2) div 16) + HexDigit(Lo(SerNo2) mod 16) +
          HexDigit(Hi(SerNo1) div 16) + HexDigit(Hi(SerNo1) mod 16) +
          HexDigit(Lo(SerNo1) div 16) + HexDigit(Lo(SerNo1) mod 16);
  end;
end;

procedure PutVolSerialNo(DriveNo: Byte; SerialNo: Longint);
var
  ReturnArray: DiskSerNoInfoType;
  Regs: Registers;
begin
  with Regs do
  begin
    AX := $440d;
    BL := DriveNo;
    CH := $08;
    CL := $66;
    DS := Seg(ReturnArray);
    DX := Ofs(ReturnArray);
    Intr($21, Regs);
    if (Flags and FCarry) = 0 then
    begin
      ReturnArray.VolSerNo.SerNo := SerialNo;
      AH := $69;
      BL := DriveNo;
      AL := $01;
      DS := Seg(ReturnArray);
      DX := Ofs(ReturnArray);
      Intr($21, Regs);
    end;
  end;
end;

Prosimy o aktualizację tej odpowiedzi, aby działała (o ile to w ogóle możliwe) w Delphi.

 0
Author: NGLN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-15 22:35:51