下面这个函数相信很多人都看过:
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));  
    end;  
end;  

解决方案 »

  1.   

    问题:
    当硬盘在 IDE Primary master 时,该函数不用作任何改动就能正常运行(98、2K、XP下通过)取得硬盘序列号(98下要将system下的smartvsd.vxd先复制到Windows/system下的IOSUBSYS目录下,重新启动后才可以使用)但当硬盘在其它端口时 IDE Primary slave(IDE Secondary master/slave),函数不能取得硬盘序列号后来研究了一下,发现有两个地方是硬盘接口的参数:
    1.
          hDevice := CreateFile( '\\.\Scsi0:',  
            GENERIC_READ or GENERIC_WRITE,  
            FILE_SHARE_READ or FILE_SHARE_WRITE,  
            nil, OPEN_EXISTING, 0, 0 );
    //win2000中,当硬盘在 IDE Primary master/slave 时应为Scsi0
    //当硬盘在 IDE Secondary master/slave 时应为Scsi1
    2.
    bDriveNumber
    //win2000中,当硬盘在 IDE Primary master/slave 时应为 0
    //当硬盘在 IDE Secondary master/slave 时应为 1上面在win2000里测试通过,但在98下不知道该如何更改参数(适应上面说的四种情况)?有实际做过的能不能给予提示,非常感谢!!!
      

  2.   

    多谢上面两位。如果你们没有出现什么问题,可能是你们的硬盘本身接在ide primary口上并设置为了master(一般情况下都是如此),改一下ide插槽或硬盘跳线试一下没有?
      

  3.   

    Win98?唉
    早就放弃它了可能是PhysicalDriver0这样吧现在都以2000为基本平台了
      

  4.   

    http://www.2ccc.com/article.asp?articleid=55
      

  5.   

    http://community.csdn.net/Expert/topic/3236/3236372.xml?temp=.8338434
    以前有好多。。
    有个叫三尺不立之弓的朋友写过个 demo 你找找
      

  6.   

    crossbow 这位兄台,你问问吧
      

  7.   

    ly_liuyang(Liu Yang):
    我可以放弃Win98,但不能放弃使用Win98的用户呀
    PhysicalDriver0这样是不行的,我在Win2000里试了,是Scsi0/Scsi1,对应master/slave,但98里不知道这样设置boytomato(深爱一人叫颖的女孩!):那些函数与此函数都差不多呀98里怎么设置CreateFile函数的文件名?
      

  8.   

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

  9.   

    nTemp1,nTemp2:longint;
    ............................
    begin
      ntemp1:=GetHDserialNumber;
      

  10.   

    win2000中(测试通过):
    IDE Primary master时,  文件名为Scsi0,bDriveNumber为0
    IDE Primary slave 时,  文件名为Scsi0,bDriveNumber为1
    IDE Secondary master时,文件名为Scsi1,bDriveNumber为0
    IDE Secondary slave 时,文件名为Scsi1,bDriveNumber为1win98中,
    IDE Primary master时,文件名为SMARTVSD,bDriveNumber为0测试通过
    但其它三种情况下,文件名为SMARTVSD,bDriveNumber为0时不能通过,不知道参数怎么设置PhysicalDrive0是不行的,2000里都不行!
      

  11.   

    crossbow(【带三尺剑立不世之功】):那用什么方法呢?
      

  12.   

    呵呵
    我公司的项目都放弃Win98用户了:)
      

  13.   

    研究一下DeviceIoControl函数,看看是不是能够找到解决办法
    还有,如果cmos中设置不用S.M.A.R.T控制硬盘,则smartvsd就不能管理该硬盘。
      

  14.   

    看来是问题多多:
    1.取硬盘序列号:有的硬盘没有序列号(如三星),且没有在各种操作系统(98/2K/XP)下的通用的获取方法
    2.CPU序列号:有的CPU就没有序号
    3.主板序列号:有的主板也没有序号
    4.网卡序列号:很多机器不装网卡,也不行哎,不知道计算机里那个部件的序列号是唯一的,并且有通用的获取方法?(用于软件注册)
      

  15.   

    根据这种情况,我的做法是:硬盘序列号+CPU序列号+主板序列号,三种组合到一起的都没有序列号的情况应该很少,如果某一个没有序列号,就给一个默认的值。
      

  16.   

    Dlwxn(流云):这倒是个好建议,但CPU序列号、主板序列号有没有通用的获取方法呢?