http://www.csdn.net/cnshare/soft/4/4806.shtm

解决方案 »

  1.   

    转:
    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;
      

  2.   

    program IdeSN; 
      
      {$APPTYPE CONSOLE} 
      
      uses 
        Windows, 
        SysUtils; // only for Win32Platform and SysErrorMessage 
      
      //------------------------------------------------------------- 
      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 
            // 获取 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)); 
          end; 
      end; 
      
      
      //============================================================= 
      var s : String; 
          rc : DWORD; 
      begin 
        s := GetIdeDiskSerialNumber; 
        if s='' then 
          begin 
            rc := GetLastError; 
            if rc=0 then WriteLn('IDE drive is not support SMART feature') 
            else WriteLn(SysErrorMessage(rc)); 
          end 
        else WriteLn('Disk serial number: ''', s,''''); 
      end.