一个console程序;<br>在Win9x下需要有 smartvsd.vxd,把他从/windows/system/拷贝到<br>/windows/system/iosubsys/重启 <br><br>program IdeSN; <br><br>{$APPTYPE CONSOLE} <br><br>uses <br> Windows, <br> SysUtils; // only for Win32Platform and SysErrorMessage <br><br>//------------------------------------------------------------- <br>function GetIdeDiskSerialNumber : String; <br>type <br> TSrbIoControl = packed record <br> HeaderLength : ULONG; <br> Signature : Array[0..7] of Char; <br> Timeout : ULONG; <br> ControlCode : ULONG; <br> ReturnCode : ULONG; <br> Length : ULONG; <br> end; <br> SRB_IO_CONTROL = TSrbIoControl; <br> PSrbIoControl = ^TSrbIoControl; <br><br> TIDERegs = packed record <br> bFeaturesReg : Byte; // Used for specifying SMART "commands". <br> bSectorCountReg : Byte; // IDE sector count register <br> bSectorNumberReg : Byte; // IDE sector number register <br> bCylLowReg : Byte; // IDE low order cylinder value <br> bCylHighReg : Byte; // IDE high order cylinder value <br> bDriveHeadReg : Byte; // IDE drive/head register <br> bCommandReg : Byte; // Actual IDE command. <br> bReserved : Byte; // reserved. Must be zero. <br> end; <br> IDEREGS = TIDERegs; <br> PIDERegs = ^TIDERegs; <br><br> TSendCmdInParams = packed record <br> cBufferSize : DWORD; <br> irDriveRegs : TIDERegs; <br> bDriveNumber : Byte; <br> bReserved : Array[0..2] of Byte; <br> dwReserved : Array[0..3] of DWORD; <br> bBuffer : Array[0..0] of Byte; <br> end; <br> SENDCMDINPARAMS = TSendCmdInParams; <br> PSendCmdInParams = ^TSendCmdInParams; <br><br> TIdSector = packed record <br> wGenConfig : Word; <br> wNumCyls : Word; <br> wReserved : Word; <br> wNumHeads : Word; <br> wBytesPerTrack : Word; <br> wBytesPerSector : Word; <br> wSectorsPerTrack : Word; <br> wVendorUnique : Array[0..2] of Word; <br> sSerialNumber : Array[0..19] of Char; <br> wBufferType : Word; <br> wBufferSize : Word; <br> wECCSize : Word; <br> sFirmwareRev : Array[0..7] of Char; <br> sModelNumber : Array[0..39] of Char; <br> wMoreVendorUnique : Word; <br> wDoubleWordIO : Word; <br> wCapabilities : Word; <br> wReserved1 : Word; <br> wPIOTiming : Word; <br> wDMATiming : Word; <br> wBS : Word; <br> wNumCurrentCyls : Word; <br> wNumCurrentHeads : Word; <br> wNumCurrentSectorsPerTrack : Word; <br> ulCurrentSectorCapacity : ULONG; <br> wMultSectorStuff : Word; <br> ulTotalAddressableSectors : ULONG; <br> wSingleWordDMA : Word; <br> wMultiWordDMA : Word; <br> bReserved : Array[0..127] of Byte; <br> end; <br> PIdSector = ^TIdSector; <br><br>const <br> IDE_ID_FUNCTION = $EC; <br> IDENTIFY_BUFFER_SIZE = 512; <br> DFP_RECEIVE_DRIVE_DATA = $0007c088; <br> IOCTL_SCSI_MINIPORT = $0004d008; <br> IOCTL_SCSI_MINIPORT_IDENTIFY = $001b0501; <br> DataSize = sizeof(TSendCmdInParams)-1+IDENTIFY_BUFFER_SIZE; <br> BufferSize = SizeOf(SRB_IO_CONTROL)+DataSize; <br> W9xBufferSize = IDENTIFY_BUFFER_SIZE+16; <br>var <br> hDevice : THandle; <br> cbBytesReturned : DWORD; <br> pInData : PSendCmdInParams; <br> pOutData : Pointer; // PSendCmdOutParams <br> Buffer : Array[0..BufferSize-1] of Byte; <br> srbControl : TSrbIoControl absolute Buffer; <br><br> procedure ChangeByteOrder( var Data; Size : Integer ); <br> var ptr : PChar; <br> i : Integer; <br> c : Char; <br> begin <br> ptr := @Data; <br> for i := 0 to (Size shr 1)-1 do <br> begin <br> c := ptr^; <br> ptr^ := (ptr+1)^; <br> (ptr+1)^ := c; <br> Inc(ptr,2); <br> end; <br> end; <br><br>begin <br> Result := ''; <br> FillChar(Buffer,BufferSize,#0); <br> if Win32Platform=VER_PLATFORM_WIN32_NT then <br> begin // Windows NT, Windows 2000 <br> // Get SCSI port handle <br> hDevice := CreateFile( '//./Scsi0:', <br> GENERIC_READ or GENERIC_WRITE, <br> FILE_SHARE_READ or FILE_SHARE_WRITE, <br> nil, OPEN_EXISTING, 0, 0 ); <br> if hDevice=INVALID_HANDLE_VALUE then Exit; <br> try <br> srbControl.HeaderLength := SizeOf(SRB_IO_CONTROL); <br> System.Move('SCSIDISK',srbControl.Signature,8); <br> srbControl.Timeout := 2; <br> srbControl.Length := DataSize; <br> srbControl.ControlCode := IOCTL_SCSI_MINIPORT_IDENTIFY; <br> pInData := PSendCmdInParams(PChar(@Buffer) <br> +SizeOf(SRB_IO_CONTROL)); <br> pOutData := pInData; <br> with pInData^ do <br> begin <br> cBufferSize := IDENTIFY_BUFFER_SIZE; <br> bDriveNumber := 0; <br> with irDriveRegs do <br> begin <br> bFeaturesReg := 0; <br> bSectorCountReg := 1; <br> bSectorNumberReg := 1; <br> bCylLowReg := 0; <br> bCylHighReg := 0; <br> bDriveHeadReg := $A0; <br> bCommandReg := IDE_ID_FUNCTION; <br> end; <br> end; <br> if not DeviceIoControl( hDevice, IOCTL_SCSI_MINIPORT, <br> @Buffer, BufferSize, @Buffer, BufferSize, <br> cbBytesReturned, nil ) then Exit; <br> finally <br> CloseHandle(hDevice); <br> end; <br> end <br> else <br> begin // Windows 95 OSR2, Windows 98 <br> hDevice := CreateFile( '//./SMARTVSD', 0, 0, nil, <br> CREATE_NEW, 0, 0 ); <br> if hDevice=INVALID_HANDLE_VALUE then Exit; <br> try <br> pInData := PSendCmdInParams(@Buffer); <br> pOutData := @pInData^.bBuffer; <br> with pInData^ do <br> begin <br> cBufferSize := IDENTIFY_BUFFER_SIZE; <br> bDriveNumber := 0; <br> with irDriveRegs do <br> begin <br> bFeaturesReg := 0; <br> bSectorCountReg := 1; <br> bSectorNumberReg := 1; <br> bCylLowReg := 0; <br> bCylHighReg := 0; <br> bDriveHeadReg := $A0; <br> bCommandReg := IDE_ID_FUNCTION; <br> end; <br> end; <br> if not DeviceIoControl( hDevice, DFP_RECEIVE_DRIVE_DATA, <br> pInData, SizeOf(TSendCmdInParams)-1, pOutData, <br> W9xBufferSize, cbBytesReturned, nil ) then Exit; <br> finally <br> CloseHandle(hDevice); <br> end; <br> end; <br> with PIdSector(PChar(pOutData)+16)^ do <br> begin <br> ChangeByteOrder(sSerialNumber,SizeOf(sSerialNumber)); <br> SetString(Result,sSerialNumber,SizeOf(sSerialNumber)); <br> end; <br>end; <br><br><br>//============================================================= <br>var s : String; <br> rc : DWORD; <br>begin <br> s := GetIdeDiskSerialNumber; <br> if s='' then <br> begin <br> rc := GetLastError; <br> if rc=0 then WriteLn('IDE drive is not support SMART feature') <br> else WriteLn(SysErrorMessage(rc)); <br> end <br> else WriteLn('Disk serial number: ''', s,''''); <br>end.<br>