本帖最后由 xsmuhtar 于 2010-10-06 18:16:19 编辑

解决方案 »

  1.   

    unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;type
      TForm1 = class(TForm)
        Edit1: TEdit;
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
    begin
    end;//获得硬盘序列号
    function GetIdeSerialNumber: pchar;
    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
        // 驱动器返回的错误代码,无错则返回0
        bDriverError: Byte;
        // IDE出错寄存器的内容,只有当bDriverError 为 SMART_IDE_ERROR 时有效
        bIDEStatus: Byte;
        bReserved: array[0..1] of Byte;
        dwReserved: array[0..1] of DWORD;
      end;
      TSendCmdOutParams = packed record
        // bBuffer的大小
        cBufferSize: DWORD;
        // 驱动器状态
        DriverStatus: TDriverStatus;
        // 用于保存从驱动器读出的数据的缓冲区,实际长度由cBufferSize决定
        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 := ''; // 如果出错则返回空串
    if SysUtils.Win32Platform = VER_PLATFORM_WIN32_NT then begin // Windows NT, Windows 2000
    // 提示! 改变名称可适用于其它驱动器,如第二个驱动器: '\\.\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 Exit;
    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;procedure TForm1.Button2Click(Sender: TObject);
    begin
        Edit1.Text := strpas(GetIdeSerialNumber);
    end;end.
      

  2.   

    function   GetIdeDiskSerialNumber()   :   String; 
    type 
        TSrbIoControl   =   packed   record 
            HeaderLength   :   ULONG; 
            Signature   :   Array[0..7]   of   Char; 
            Timeout   :   ULONG; 
            ControlCode   :   ULONG; 
            ReturnCode   :   ULONG; 
            Length   :   ULONG; 
        end; 
        SRB_IO_CONTROL   =   TSrbIoControl; 
        PSrbIoControl   =   ^TSrbIoControl;     TIDERegs   =   packed   record 
            bFeaturesReg   :   Byte;   //   Used   for   specifying   SMART   "commands ". 
            bSectorCountReg   :   Byte;   //   IDE   sector   count   register 
            bSectorNumberReg   :   Byte;   //   IDE   sector   number   register 
            bCylLowReg   :   Byte;   //   IDE   low   order   cylinder   value 
            bCylHighReg   :   Byte;   //   IDE   high   order   cylinder   value 
            bDriveHeadReg   :   Byte;   //   IDE   drive/head   register 
            bCommandReg   :   Byte;   //   Actual   IDE   command. 
            bReserved   :   Byte;   //   reserved.   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;     TIdSector   =   packed   record 
            wGenConfig   :   Word; 
            wNumCyls   :   Word; 
            wReserved   :   Word; 
            wNumHeads   :   Word; 
            wBytesPerTrack   :   Word; 
            wBytesPerSector   :   Word; 
            wSectorsPerTrack   :   Word; 
            wVendorUnique   :   Array[0..2]   of   Word; 
            sSerialNumber   :   Array[0..19]   of   Char; 
            wBufferType   :   Word; 
            wBufferSize   :   Word; 
            wECCSize   :   Word; 
            sFirmwareRev   :   Array[0..7]   of   Char; 
            sModelNumber   :   Array[0..39]   of   Char; 
            wMoreVendorUnique   :   Word; 
            wDoubleWordIO   :   Word; 
            wCapabilities   :   Word; 
            wReserved1   :   Word; 
            wPIOTiming   :   Word; 
            wDMATiming   :   Word; 
            wBS   :   Word; 
            wNumCurrentCyls   :   Word; 
            wNumCurrentHeads   :   Word; 
            wNumCurrentSectorsPerTrack   :   Word; 
            ulCurrentSectorCapacity   :   ULONG; 
            wMultSectorStuff   :   Word; 
            ulTotalAddressableSectors   :   ULONG; 
            wSingleWordDMA   :   Word; 
            wMultiWordDMA   :   Word; 
            bReserved   :   Array[0..127]   of   Byte; 
        end; 
        PIdSector   =   ^TIdSector; const 
        IDE_ID_FUNCTION   =   $EC; 
        IDENTIFY_BUFFER_SIZE   =   512; 
        DFP_RECEIVE_DRIVE_DATA   =   $0007c088; 
        IOCTL_SCSI_MINIPORT   =   $0004d008; 
        IOCTL_SCSI_MINIPORT_IDENTIFY   =   $001b0501; 
        DataSize   =   sizeof(TSendCmdInParams)-1+IDENTIFY_BUFFER_SIZE; 
        BufferSize   =   SizeOf(SRB_IO_CONTROL)+DataSize; 
        W9xBufferSize   =   IDENTIFY_BUFFER_SIZE+16; 
    var 
        hDevice   :   THandle; 
        cbBytesReturned   :   DWORD; 
        pInData   :   PSendCmdInParams; 
        pOutData   :   Pointer;   //   PSendCmdOutParams 
        Buffer   :   Array[0..BufferSize-1]   of   Byte; 
        srbControl   :   TSrbIoControl   absolute   Buffer; procedure   ChangeByteOrder(   var   Data;   Size   :   Integer   ); 
    var   ptr   :   PChar; 
        i   :   Integer; 
        c   :   Char; 
    begin 
        ptr   :=   @Data; 
        for   i   :=   0   to   (Size   shr   1)-1   do 
        begin 
            c   :=   ptr^; 
            ptr^   :=   (ptr+1)^; 
            (ptr+1)^   :=   c; 
            Inc(ptr,2); 
        end; 
    end; begin 
        Result   :=   ' '; 
        FillChar(Buffer,BufferSize,#0); 
        if   Win32Platform=VER_PLATFORM_WIN32_NT   then 
        begin   //   Windows   NT,   Windows   2000 
    //   Get   SCSI   port   handle 
            hDevice   :=   CreateFile(   '\\.\Scsi0: ',   GENERIC_READ   or   GENERIC_WRITE, 
                              FILE_SHARE_READ   or   FILE_SHARE_WRITE,   nil,   OPEN_EXISTING,   0,   0   ); 
            if   hDevice=INVALID_HANDLE_VALUE   then   Exit; 
            try 
                srbControl.HeaderLength   :=   SizeOf(SRB_IO_CONTROL); 
                System.Move( 'SCSIDISK ',srbControl.Signature,8); 
                srbControl.Timeout   :=   2; 
                srbControl.Length   :=   DataSize; 
                srbControl.ControlCode   :=   IOCTL_SCSI_MINIPORT_IDENTIFY; 
                pInData   :=   PSendCmdInParams(PChar(@Buffer) 
                +SizeOf(SRB_IO_CONTROL)); 
                pOutData   :=   pInData; 
                with   pInData^   do 
                begin 
                    cBufferSize   :=   IDENTIFY_BUFFER_SIZE; 
                    bDriveNumber   :=   0; 
                    with   irDriveRegs   do 
                    begin 
                        bFeaturesReg   :=   0; 
                        bSectorCountReg   :=   1; 
                        bSectorNumberReg   :=   1; 
                        bCylLowReg   :=   0; 
                        bCylHighReg   :=   0; 
                        bDriveHeadReg   :=   $A0; 
                        bCommandReg   :=   IDE_ID_FUNCTION; 
                    end; 
                end; 
                if   not   DeviceIoControl(   hDevice,   IOCTL_SCSI_MINIPORT, 
                                @Buffer,   BufferSize,   @Buffer,   BufferSize, 
                                cbBytesReturned,   nil   )   then 
                    Exit; 
            finally 
                CloseHandle(hDevice); 
            end; 
        end 
        else 
        begin   //   Windows   95   OSR2,   Windows   98 
            hDevice   :=   CreateFile(   '\\.\SMARTVSD ',   0,   0,   nil,   CREATE_NEW,   0,   0   ); 
            if   hDevice=INVALID_HANDLE_VALUE   then   Exit; 
            try 
                pInData   :=   PSendCmdInParams(@Buffer); 
                pOutData   :=   @pInData^.bBuffer; 
                with   pInData^   do 
                begin 
                    cBufferSize   :=   IDENTIFY_BUFFER_SIZE; 
                    bDriveNumber   :=   0; 
                    with   irDriveRegs   do 
                    begin 
                        bFeaturesReg   :=   0; 
                        bSectorCountReg   :=   1; 
                        bSectorNumberReg   :=   1; 
                        bCylLowReg   :=   0; 
                        bCylHighReg   :=   0; 
                        bDriveHeadReg   :=   $A0; 
                        bCommandReg   :=   IDE_ID_FUNCTION; 
                    end; 
                end; 
                if   not   DeviceIoControl(   hDevice,   DFP_RECEIVE_DRIVE_DATA, 
                                pInData,   SizeOf(TSendCmdInParams)-1,   pOutData, 
                                W9xBufferSize,   cbBytesReturned,   nil   )   then 
                    Exit; 
            finally 
                CloseHandle(hDevice); 
            end; 
        end; 
        with   PIdSector(PChar(pOutData)+16)^   do 
        begin 
            ChangeByteOrder(sSerialNumber,Sizeof(sSerialNumber)); 
            SetString(Result,sSerialNumber,Sizeof(sSerialNumber)); 
            Result   :=   Trim(Result); 
        end; 
    end; 
      

  3.   

    之前看見過網上有一段牛人發的DISKSN.PAS文件,可支持IDE、SCSI、SATA多種格式http://www.docin.com/p-5408843.html
      

  4.   

    不過我一直使用的是MSI GUI和MiTeC組件聯合,可獲取不同型號的電腦硬件設備信息,效果還理想
      

  5.   

    这个比较困难,普通的IDE、SATA还比较容易实现,但是SCSI和SAS卡硬盘,我弄了很久都读不出来
      

  6.   

    测试结果 RAID 0硬盘序列号取不出
      

  7.   

    楼上写的方法不能用Delphi 2010 不能用,读不出来硬盘物理序列号,delphi的低版本可以。这些方法最新的delphi 2010,或者delphi.net里如何实现?如果你们说的这个价格少的话,我可以给你们加钱。
      

  8.   

    本人从DOS时代就研究这个了,可以这样告诉楼主:全部的要求都要达到基本上是不可能的,但是常见硬盘获取序列号还是比较容易的。一、硬盘物理序列号的由来:
        IDE接口的硬盘有一个标准,就是其中指定位置有512字节存放硬盘本身的信息,其中20个字节(SerialNumber部分)就是硬盘物理序列号,每个硬盘都应该不一样的。可见只有IDE或兼容的硬盘才有这个东东(SATA一般是兼容的),SCSI和SAS的就是没有这个东东的,也许他们有自己类似的东东,但是目前没有这方面的资料,也没有人宣称能获取这种硬盘的序列号。所以指望适合所有硬盘是不现实的!
    二、获取这512字节或序列号的方法:
        由一可以知道,获取序列号的一般方法就是读取这512个字节并加以截取和转换。如果学习过接口与通信或微机原理之类的课程,就知道PC上实际是通过往某些端口写入和读取来实现的,DOS下面就是这样获取序列号的。windows 9X开始,不能直接访问硬件了,所以windows 9x中一般需要使用Vxd技术实现对端口的访问,而NT系列的则又需要使用其他方法才能访问端口,5、6楼的方法就是这样的,注意程序中应当先判断用的是哪种windows。
        另外一个方法是使用微软的wmi,但是wmi也有些问题:1、早期windows没有这个东东,需要单独安装;2、2000、XP、2003的wmi和vista、windows7的wmi有区别,实际上wmi中有两种方法,结果的格式也是有区别的,所以仍然需要判断是何种windows。所以单独使用wmi也不是完美的方法。
        可能有人觉得不需要使用wmi,其实我这里提到它是因为在vista或WIN7下面,传统方法需要关闭UAC才能得到正确结果,这个问题楼主可能还没有考虑过但是却不能忽略。比较完美的方案应该是在5、6楼的方法中增加判断vista和win7的代码,如果是这两种则采用wmi来获取。
    三、关于有些IDE兼容的硬盘不能获取序列号
        有资料说是它们就没有序列号或者说是空白的,但是根据本人的经验来看,还没有碰到过这样的硬盘,主要问题出在有些硬盘的序列号的20个字节是空格前导的,有些程序中没有考虑到此种情况,导致取出的序列号是空的。
    四、关于delphi2010不能获取序列号
        实际上传统方法是牵涉到对字节进行操作的,而在delphi2009开始引入了对unicode的支持,所以char不再等同于byte,如果使用delphi2009及以后的版本照搬5、6楼的代码不会成功的,因为那些代码认为char等同于byte!只要根据这个进行简单的修改就可用于delphi2009和2010了。
        
      

  9.   

    很古老的资料了,终于在大富翁翻出来了,关于IDE硬盘参数的格式
     
    -------------------------------------------------------------------------------
    0170-0177 ---- HDC 2 (2nd Fixed Disk Controller)   same as 01Fx (ISA, EISA)-------------------------------------------------------------------------------
    01F0-01F7 ---- HDC 1 (1st Fixed Disk Controller)   same as 017x (ISA, EISA)01F0 r/w data register01F1 r error register
    diagnostic mode errors:
     bit 7-3 reserved
     bit 2-1 = 001 no error detected
     = 010 formatter device error
     = 011 sector buffer error
     = 100 ECC circuitry error
     = 101 controlling microprocessor error
     operation mode:
      bit 7  = 1  bad block detected
     = 0  block OK
      bit 6  = 1  uncorrectable ECC error
     = 0  no error
      bit 5       reserved
      bit 4  = 1  ID found
     = 0  ID not found
      bit 3       reserved
      bit 2  = 1  command completed
     = 0  command aborted
      bit 1  = 1  track 000 not found
     = 0  track 000 found
      bit 0  = 1  DAM not found
     = 0  DAM found (CP-3022 always 0)01F1 w WPC/4  (Write Precompensation Cylinder divided by 4)01F2 r/w sector count
    01F3 r/w sector number
    01F4 r/w cylinder low
    01F5 r/w cylinder high01F6 r/w drive/head
     bit 7  = 1
     bit 6  = 0
     bit 5  = 1
     bit 4  = 0  drive 0 select
     = 1  drive 1 select
     bit 3-0      head select bits01F7 r status register
     bit 7 = 1  controller is executing a command
     bit 6 = 1  drive is ready
     bit 5 = 1  write fault
     bit 4 = 1  seek complete
     bit 3 = 1  sector buffer requires servicing
     bit 2 = 1  disk data read successfully corrected
     bit 1 = 1  index - set to 1 each disk revolution
     bit 0 = 1  previous command ended in an error01F7 w command register
    commands:
     98 E5  check power mode (IDE)
     90  execute drive diagnostics
     50  format track
     EC  identify drive  (IDE)
     97 E3  idle (IDE)
     95 E1  idle immediatete (IDE)
     91  initialize drive parameters
     1x  recalibrate
     E4  read buffer (IDE)
     C8  read DMA with retry (IDE)
     C9  read DMA without retry (IDE)
     C4  read multiplec  (IDE)
     20  read sectors with retry
     21  read sectors without retry
     22  read long with retry
     23  read long without retry
     40  read verify sectors with retry
     41  read verify sectors without retry
     7x  seek
     EF  set features (IDE)
     C6  set multiple mode (IDE)
     99 E6  set sleep mode  (IDE)
     96 E2  standby (IDE)
     94 E0  standby immediate (IDE)
     E8  write buffer (IDE)
     CA  write DMA with retry (IDE)
     CB  write DMA with retry (IDE)
     C5  write multiple  (IDE)
     E9  write same (IDE)
     30  write sectors with retry
     31  write sectors without retry
     32  write long with retry
     33  write long without retry
     3C  write verify (IDE)
     9A  vendor unique (IDE)
     C0-C3  vendor unique (IDE)
     8x  vendor unique (IDE)
     F0-F4  EATA standard (IDE)
     F5-FF  vendor unique (IDE)
    -------------------------------------------------------------------------------
      

  10.   

    我试过了好多个硬盘序列号的代码,delphi 7 可以正常使用,但delphi 2009和delphi 2010力不能正常的读取序列号 这些代码如何转换成delphi 2010的代码了,
    我看又有一些代码,和dll 文件 在delphi 2010上不能正常使用的,这些代码如何转换成delphi2010的代码呢?
      

  11.   

    delphi调用wmi 获取好像很简单
      

  12.   

    http://download.csdn.net/detail/dongcijie/5249516不过不支持raid阵列读取。