2010年4月15日 星期四

Delphi 取得實體硬碟序號 (非分割區序號)

程式

//自訂型態
type   
  IDEREGS = record   
    bFeaturesReg: Byte;   
    bSectorCountReg: Byte;   
    bSectorNumberReg: Byte;   
    bCylLowReg: Byte;   
    bCylHighReg: Byte;   
    bDriveHeadReg: Byte;   
    bCommandReg: Byte;   
    bReserved: Byte;   
  end; 

DRIVERSTATUS = record bDriveError: Byte; bIDEStatus: Byte; bReserved: array[1..2] of Byte; dwReserved: array [1..2] of LongWord; end;

SENDCMDOUTPARAMS = record cBufferSize: LongWord; DStatus: DRIVERSTATUS; bBuffer: array[1..512] of Byte; end;

SENDCMDINPARAMS = record cBufferSize: LongWord; irDriveRegs: IDEREGS; bDriveNumber: Byte; bReserved: array[1..3] of Byte; dwReserved: array[1..4] of LongWord; end;

THdInfoType = (HD_MODEL_NUMBER, HD_SERIAL_NUMBER, HD_FIRMWARE_REVISION);

// API宣告  
function DeviceIoControl   
  (hDevice: LongWord;   
   dwIoControlCode: LongWord;   
   lpInBuffer: Pointer;   
   nInBufferSize: LongWord;   
   lpOutBuffer: Pointer;   
   nOutBufferSize: LongWord;   
   var lpBytesReturned: LongWord;   
   lpOverlapped: LongWord): LongWord; stdcall; external 'Kernel32';
// 取得硬碟序號  
function Get_HD_Info(DrvIdx: byte; HdInfoType: THdInfoType): String;   
var   
  ParaIn: SENDCMDINPARAMS;   
  ParaOut: SENDCMDOUTPARAMS;   
  Sno: String;   
  h, br: LongWord;   
  i, st, ed: Integer;   
  PlatForm: string;

  procedure GetPlatForm;  
  var OS: OSVERSIONINFO;   
  begin   
    OS.dwOSVersionInfoSize := SizeOf(OS);   
    GetVersionEx(OS);   
    PlatForm := 'UNK';   
    case OS.dwPlatformId of   
      VER_PLATFORM_WIN32S:   
        PlatForm := '32S';                      // Win32S   
      VER_PLATFORM_WIN32_WINDOWS:   
        begin   
          if OS.dwMinorVersion = 0 then   
            PlatForm := 'W95'                   // Win 95   
          else   
            PlatForm := 'W98'                   // Win 98   
        end;   
      VER_PLATFORM_WIN32_NT:   
        PlatForm := 'WNT';                      // Win NT/2000   
    end;   
  end;

begin  
  GetPlatForm;
  if Pos(PlatForm, 'WNT') > 0 then  
    h := CreateFile(PChar('\\.\PhysicalDrive' + IntToStr(DrvIdx)), GENERIC_READ + GENERIC_WRITE,   
                     FILE_SHARE_READ + FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)   
  else if Pos(PlatForm, 'W95,W98') > 0 then   
    h := CreateFileA('\\.\Smartvsd', 0, 0, 0, CREATE_NEW, 0, 0)   
  else   
    Raise Exception.Create('Platform must be Win95, Win98, WinNT');

  If h = 0 Then Exit;
  ZeroMemory(@ParaIn, SizeOf(ParaIn));  
  ZeroMemory(@ParaOut, SizeOf(ParaOut));
  with ParaIn do  
  begin   
    bDriveNumber := DrvIdx;   
    cBufferSize := 512;   
    With irDriveRegs do   
    begin   
      if (DrvIdx and 1) = 1 then   
        bDriveHeadReg := $B0   
      else   
        bDriveHeadReg := $A0;   
      bCommandReg := $EC;   
      bSectorCountReg := 1;   
      bSectorNumberReg := 1;   
    end;   
  end;

  DeviceIoControl(h, $7C088, @ParaIn, SizeOf(ParaIn), @ParaOut, SizeOf(ParaOut), br, 0);
  case HdInfoType of  
    HD_MODEL_NUMBER:   
      begin   
        st := 55;   
        ed := 94;   
      end;   
    HD_SERIAL_NUMBER:   
      begin   
        st := 21;   
        ed := 40;   
      end;   
    HD_FIRMWARE_REVISION:   
      begin   
        st := 47;   
        ed := 54;   
      end;   
  end;
  i := st;  
  while i <= ed do   
  begin   
    if ParaOut.bBuffer[i + 1] = 0 then   
      break;   
    Sno := Sno + Chr(ParaOut.bBuffer[i + 1]);   
    if ParaOut.bBuffer[i] > 0 then   
      Sno := Sno + Chr(ParaOut.bBuffer[i]);   
    i := i + 2;   
  end; 
  CloseHandle(h);
  Result := Trim(Sno);  
end;   

呼叫範例

Memo1.Lines.Add('型號:' + Get_HD_Info(0, HD_MODEL_NUMBER));  
Memo1.Lines.Add('序號:' + Get_HD_Info(0, HD_SERIAL_NUMBER));   
Memo1.Lines.Add('韌體版本:' + Get_HD_Info(0, HD_FIRMWARE_REVISION)); 

1 則留言:

貓老大 提到...

殘念!
此方法只能取得 IDE 或是 SATA 硬碟的實體序號,無法取得 SCSI 硬碟的實體序號