VAR
  Teller : INTEGER;
  Lus    : INTEGER;
BEGIN
    GetHardDiskNaam := '';
    Teller := 1;
    FOR Lus := 1 TO 18 DO
    BEGIN
      HardDiskNaam[Teller] := CHR( ( HardDiskGegevens[27+Lus] DIV 256 ));
      Inc(Teller);
      HardDiskNaam[Teller] := CHR( ( HardDiskGegevens[27+Lus] MOD 256 ));
      Inc(Teller);
    END;
    GetHardDiskNaam := HardDiskNaam;
END;
FUNCTION GetHardDiskSerieNummer : STRING;
VAR
  Teller : INTEGER;
  Lus    : INTEGER;
BEGIN
    GetHardDiskSerieNummer := '';
    Teller := 1;
    FOR Lus := 1 TO 8 DO
    BEGIN
      SerieNummer[Teller] := CHR( ( HardDiskGegevens[10+Lus] DIV 256 ));
      Inc(Teller);
      SerieNummer[Teller] := CHR( ( HardDiskGegevens[10+Lus] MOD 256 ));
      Inc(Teller);
    END;
    GetHardDiskSerieNummer := SerieNummer;
END;
FUNCTION GetHardDiskControlleNummer : STRING;
VAR
  Teller : INTEGER;
  Lus    : INTEGER;
BEGIN
    GetHardDiskControlleNummer := '';
    Teller := 1;
    FOR Lus := 1 TO 3 DO
    BEGIN
      ControlleNummer[Teller] := CHR( ( HardDiskGegevens[23+Lus] DIV 256 ));
      Inc(Teller);
      ControlleNummer[Teller] := CHR( ( HardDiskGegevens[23+Lus] MOD 256 ));
      Inc(Teller);
    END;
    GetHardDiskControlleNummer := ControlleNummer;
END;
PROCEDURE GetHardDiskGegevens;
VAR
  Lus    : INTEGER;
BEGIN
  WHILE ( Port[$1f7] <> $50) DO ;
  Port[$1F6] := $A0 ;
  Port[$1F7] := $EC ;
  WHILE ( Port[$1f7] <> $58 ) DO ;
  FOR Lus := 1 TO 256 DO
  BEGIN
    HardDiskGegevens[Lus] := Portw[$1F0] ;
  END;
END;
END.

解决方案 »

  1.   

    http://www.csdn.net/Expert/TopicView1.asp?id=677819
      

  2.   

    function GetHDSerialNumber: LongInt;
    {$IFDEF WIN32}
    var
      pdw : pDWord;
      mc, fl : dword;
    {$ENDIF}
    begin
      {$IfDef WIN32}
      New(pdw);
      GetVolumeInformation(nil,nil,0,pdw,mc,fl,nil,0);
      Result := pdw^;
      dispose(pdw);
      {$ELSE}
      Result := GetWinFlags;
      {$ENDIF}
    end;
      

  3.   

    我不大懂,可是我想应该可以从注册表里找到吧,windows优化大师不就实现了吗
      

  4.   

    没有这么复杂吧用这个函数就好了。
    硬盘
    function GetHDSerialNumber: LongInt;
    {$IFDEF WIN32}
    var
      pdw : pDWord;
      mc, fl : dword;
    {$ENDIF}
    begin
      {$IfDef WIN32}
      New(pdw);
      GetVolumeInformation(nil,nil,0,pdw,mc,fl,nil,0);
      Result := pdw^;
      dispose(pdw);
      {$ELSE}
      Result := GetWinFlags;
      {$ENDIF}
    end;
      

  5.   

    WinNT/Win2000 下你必须拥有对硬盘的读/写访问权限
      

  6.   

    这是一篇资料:
    使用S.M.A.R.T. Ioctl API获取IDE硬盘序列号     
    (http://www.tommstudio.com)  --------------------------------------------------------------------------------
    通过它你可以获取型号名称, firmware revision,序列号以及其它有关IDE硬盘的信息. 
    回答:
    相关构件:
    IdeInfo.zip
    许多FAQ中推荐使用GetVolumeInformation来获取硬盘序列号。但是那获取的是卷的序列号,而不是硬盘的序列号。卷 的序列号是在分区格式化时生成或修改。一些公司使用复制工具来为全部新计算机安装软件----通过将一个硬盘复制到 其它硬盘,当然,所有这些计算机上卷的信息(包括序列号)都是相同的。我建议另外的一个方法:获取真正硬盘的序列号。
    不幸的是,下列代码只能工作在IDE硬盘上。
    //获取第一个IDE硬盘的序列号 
    function GetIdeSerialNumber : SerialNumber; 
    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; 
    ptr : PChar; 
    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 // Windows NT, Windows 2000 
    begin 
    // 提示! 改变名称可适用于其它驱动器,如第二个驱动器: '\\.\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; // 更多关于 S.M.A.R.T. ioctl 的信息可查看:
    // http://www.microsoft.com/hwdev/download/respec/iocltapi.rtf // MSDN库中也有一些简单的例子
    // Windows Development -> Win32 Device Driver Kit -> 
    // SAMPLE: SmartApp.exe Accesses SMART stats in IDE drives // 还可以查看 http://www.mtgroup.ru/~alexk 
    // IdeInfo.zip - 一个简单的使用了S.M.A.R.T. Ioctl API的Delphi应用程序// Win98 
    // SMARTVSD.VXD 必须安装到 \windows\system\iosubsys 
    // (不要忘记在复制后重新启动系统) 
     
     
      

  7.   

    VC编写的DLL,带VC源程序和Delphi调用范例,可以获得9X NT 2000下的硬盘序列号,支持IDE以及SCSI硬盘:
    http://www.applevb.com/lib/diskio.rar
    VC源程序:
    http://www.applevb.com/DiskID.rar
      

  8.   

    Unit HardDisk; 
    INTERFACE 
    FUNCTION  GetHardDiskNaam  : STRING; 
    FUNCTION  GetHardDiskSerieNummer        : STRING; 
    FUNCTION  GetHardDiskControlleNummer    : STRING; 
    PROCEDURE GetHardDiskGegevens; 
    CONST 
      CodeerTabel : ARRAY[0..24] OF BYTE = 
    (3,1,2,1,4,1,3,2,6,4,6,5,1,2,6,4,2,6,3,4,6,2,4,1,2); 
    TYPE 
      CharArray = ARRAY[0..24] OF CHAR; 
    VAR 
      HardDiskGegevens : ARRAY[1..256] OF INTEGER; 
      HardDiskNaam  : CharArray; 
      SerieNummer  : CharArray; 
      ControlleNummer : CharArray; 
      C_HardDiskNaam: STRING; 
      C_HardDiskSerieNummer : STRING; 
      C_HardDiskControlleNummer : STRING; 
      C_LicentieNaam: STRING; 
    IMPLEMENTATION 
    FUNCTION GetHardDiskNaam : STRING; 
    VAR 
      Teller : INTEGER; 
      Lus : INTEGER; 
    BEGIN 
        GetHardDiskNaam := ''; 
        Teller := 1; 
        FOR Lus := 1 TO 18 DO 
        BEGIN 
          HardDiskNaam[Teller] := CHR( ( HardDiskGegevens[27+Lus] DIV 256 )); 
          Inc(Teller); 
          HardDiskNaam[Teller] := CHR( ( HardDiskGegevens[27+Lus] MOD 256 )); 
          Inc(Teller); 
        END; 
        GetHardDiskNaam := HardDiskNaam; 
    END; 
    FUNCTION GetHardDiskSerieNummer : STRING; 
    VAR 
      Teller : INTEGER; 
      Lus : INTEGER; 
    BEGIN 
        GetHardDiskSerieNummer := ''; 
        Teller := 1; 
        FOR Lus := 1 TO 8 DO 
        BEGIN 
          SerieNummer[Teller] := CHR( ( HardDiskGegevens[10+Lus] DIV 256 )); 
          Inc(Teller); 
          SerieNummer[Teller] := CHR( ( HardDiskGegevens[10+Lus] MOD 256 )); 
          Inc(Teller); 
        END; 
        GetHardDiskSerieNummer := SerieNummer; 
    END; 
    FUNCTION GetHardDiskControlleNummer : STRING; 
    VAR 
      Teller : INTEGER; 
      Lus    : INTEGER; 
    BEGIN 
        GetHardDiskControlleNummer := ''; 
        Teller := 1; 
        FOR Lus := 1 TO 3 DO 
        BEGIN 
          ControlleNummer[Teller] := CHR( ( HardDiskGegevens[23+Lus] DIV 256 )); 
          Inc(Teller); 
          ControlleNummer[Teller] := CHR( ( HardDiskGegevens[23+Lus] MOD 256 )); 
          Inc(Teller); 
        END; 
        GetHardDiskControlleNummer := ControlleNummer; 
    END; 
    PROCEDURE GetHardDiskGegevens; 
    VAR 
      Lus    : INTEGER; 
    BEGIN 
      WHILE ( Port[$1f7] <> $50) DO ; 
      Port[$1F6] := $A0 ; 
      Port[$1F7] := $EC ; 
      WHILE ( Port[$1f7] <> $58 ) DO ; 
      FOR Lus := 1 TO 256 DO 
      BEGIN 
        HardDiskGegevens[Lus] := Portw[$1F0] ; 
      END; 
    END; 
    END. 
      

  9.   

    unit Unit1; interface uses   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,   StdCtrls; type   TForm1 = class(TForm)     Button1: TButton;     Label0: TLabel;     Label1: TLabel;     Label2: TLabel;     Label3: TLabel;     Label4: TLabel;     procedure Button1Click(Sender: TObject);   private     { Private declarations }   public     { Public declarations }   end; const   hookexceptionno = 5;   ErrNo : integer =0; var   pw : array [0..255] of WORD;//    pw[256];   idtr_1 : array [0..5] of byte; //保存中断描述符表寄存器   oldexceptionhook : dword;      //保存原先的中断入口地址   IdeBase : word;   SelectDisk: integer; var   Form1: TForm1; implementation {$R *.DFM} function  inp(rdx:word) : byte; asm     mov dx, rdx     in al, dx end; function inpw(rdx: word) : word; asm     mov dx, rdx     in  ax, dx end; procedure outp(ral : byte; rdx : word); asm     mov dx, rdx     mov al, ral     out dx, al end; function WaitIde:byte; var   al:byte; begin   repeat     al:=inp(IdeBase+7);   until (al<$80) or (al=$a0); //$a0可能就没有硬盘   WaitIde := al; end; procedure ReadIDE; var   al : byte;   i : integer; begin   WaitIde;   outp(SelectDisk,IdeBase+6);   al := WaitIde;   if ((al and $50) <>$50) then   begin     ErrNo:=1;     exit;   end;   outp(SelectDisk,IdeBase+6);   outp($EC,IdeBase+7);   al := WaitIde;   if ((al and $58)<>$58) then   begin     ErrNo:=2;     exit;   end;   for i:=0 to 255 do   begin     pw[i] := inpw(IdeBase);   end; end; // 新的中断处理程序 procedure ReadIt; assembler; asm     push eax     push ebx     push ecx     push edx     push esi     push edi     // 在这里写读程序     call ReadIDE     pop edi     pop esi     pop edx     pop ecx     pop ebx     pop eax     iretd end; procedure GetSerialNo; assembler; begin   asm     push eax     // 获取修改的中断的中断描述符(中断门)地址     sidt idtr_1     mov eax,dword ptr idtr_1+02h     add eax,hookexceptionno*08h+04h     // 保存原先的中断入口地址     cli     push ecx     mov ecx,dword ptr [eax]     mov cx,word ptr [eax-04h]     mov dword ptr oldexceptionhook,ecx     pop ecx     // 设置修改的中断入口地址为新的中断处理程序入口地址     push ebx     lea ebx,ReadIt     mov word ptr [eax-04h],bx     shr ebx,10h     mov word ptr [eax+02h],bx     pop ebx     // 执行中断,转到ring 0(与cih 病毒原理相似!)     push ebx     int hookexceptionno     pop ebx     // 恢复原先的中断入口地址     push ecx     mov ecx,dword ptr oldexceptionhook     mov word ptr [eax-04h],cx     shr ecx,10h     mov word ptr [eax+02h],cx     pop ecx     // 结束     sti     pop eax     ret   end; end; procedure GetPN(DriveNo: integer; var s:string); var   i : integer; begin //  asm int 3 end;   ErrNo:=0;   fillchar(pw,sizeof(pw),0);   s:='';   case DriveNo of       //设置基址     0,1:IdeBase:= $1f0;     2,3:IdeBase:= $170;   end;   case DriveNo of       //指定主从     0,2:SelectDisk:=$A0;     1,3:SelectDisk:=$B0;   end;   GetSerialNo;   if ErrNo<>0 then     exit;       //读错误   if (pw[0]=0) then     s := '没有序列号:('   else     for i:=10 to 20 do     begin       s := s+ char(pw[i] shr 8) + char(pw[i] and $ff);     end; end; procedure TForm1.Button1Click(Sender: TObject); var   s:string;   i:integer; begin   for i:=0 to 3 do   begin     GetPN(i, s);     if (s<>'') then     case i of       0:  Label1.Caption := 'IDE1 主盘' +s;       1:  Label2.Caption := 'IDE1 从盘' +s;       2:  Label3.Caption := 'IDE2 主盘' +s;       3:  Label3.Caption := 'IDE2 从盘' +s;     end;   end; end; end.