|
|
unit u_sys_sysinfo;
|
|
|
|
|
|
interface
|
|
|
uses
|
|
|
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
|
|
|
Dialogs, StdCtrls;
|
|
|
type
|
|
|
TcpuMSG = record
|
|
|
ID1 : string;
|
|
|
ID2 : String;
|
|
|
ID3 : String;
|
|
|
ID4 : String;
|
|
|
PValue : String;
|
|
|
FValue : String;
|
|
|
MValue : String;
|
|
|
SValue : String;
|
|
|
Vendor : String;
|
|
|
end;
|
|
|
function GetDisplayFrequency: Integer;
|
|
|
function GetIdeSerialNumber: pchar;
|
|
|
function GetCPUSpeed: Double;
|
|
|
function GetDisplayDevice:string;
|
|
|
function GetProcessorType:string;
|
|
|
function GetWindowsVersion: string;
|
|
|
function GetIdeDiskSerialNumber(var SerialNumber: string; var ModelNumber: string;
|
|
|
var FirmwareRev: string; var TotalAddressableSectors: ULong;
|
|
|
var SectorCapacity: ULong; var SectorsPerTrack: Word): Boolean; //得到硬盘物理号
|
|
|
function GetcpuMSG:TcpuMSG;
|
|
|
implementation
|
|
|
const
|
|
|
ID_BIT = $200000; // EFLAGS ID bit
|
|
|
type
|
|
|
TCPUID = array[1..4] of Longint;
|
|
|
TVendor = array [0..11] of char;
|
|
|
|
|
|
function GetCPUSpeed: Double;
|
|
|
const
|
|
|
DelayTime = 500; // 时间单位是毫秒
|
|
|
var
|
|
|
TimerHi, TimerLo: DWORD;
|
|
|
PriorityClass, Priority: Integer;
|
|
|
begin
|
|
|
PriorityClass := GetPriorityClass(GetCurrentProcess);
|
|
|
Priority := GetThreadPriority(GetCurrentThread);
|
|
|
SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS);
|
|
|
SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_TIME_CRITICAL);
|
|
|
Sleep(10);
|
|
|
asm
|
|
|
dw 310Fh // rdtsc
|
|
|
mov TimerLo, eax
|
|
|
mov TimerHi, edx
|
|
|
end;
|
|
|
Sleep(DelayTime);
|
|
|
asm
|
|
|
dw 310Fh // rdtsc
|
|
|
sub eax, TimerLo
|
|
|
sbb edx, TimerHi
|
|
|
mov TimerLo, eax
|
|
|
mov TimerHi, edx
|
|
|
end;
|
|
|
|
|
|
SetThreadPriority(GetCurrentThread, Priority);
|
|
|
SetPriorityClass(GetCurrentProcess, PriorityClass);
|
|
|
Result := TimerLo / (1000.0 * DelayTime);
|
|
|
end;
|
|
|
//*************
|
|
|
function GetCpuSpeed9: Comp;
|
|
|
var
|
|
|
t: DWORD;
|
|
|
mhi, mlo, nhi, nlo: DWORD;
|
|
|
t0, t1, chi, clo, shr32: Comp;
|
|
|
begin
|
|
|
shr32 := 65536;
|
|
|
shr32 := shr32 * 65536;
|
|
|
t := GetTickCount;
|
|
|
while t = GetTickCount do begin end;
|
|
|
asm
|
|
|
DB 0FH
|
|
|
DB 031H
|
|
|
mov mhi,edx
|
|
|
mov mlo,eax
|
|
|
end;
|
|
|
while GetTickCount < (t + 1000) do begin end;
|
|
|
asm
|
|
|
DB 0FH
|
|
|
DB 031H
|
|
|
mov nhi,edx
|
|
|
mov nlo,eax
|
|
|
end;
|
|
|
chi := mhi; if mhi < 0 then chi := chi + shr32;
|
|
|
clo := mlo; if mlo < 0 then clo := clo + shr32;
|
|
|
t0 := chi * shr32 + clo;
|
|
|
chi := nhi; if nhi < 0 then chi := chi + shr32;
|
|
|
clo := nlo; if nlo < 0 then clo := clo + shr32;
|
|
|
t1 := chi * shr32 + clo;
|
|
|
Result := (t1 - t0) / 1E6;
|
|
|
end;
|
|
|
function GetCPUSpeed1: Double;
|
|
|
const
|
|
|
DelayTime = 500; // measure time in ms
|
|
|
var
|
|
|
TimerHi, TimerLo: DWORD;
|
|
|
PriorityClass, Priority: Integer;
|
|
|
begin
|
|
|
PriorityClass := GetPriorityClass(GetCurrentProcess);
|
|
|
Priority := GetThreadPriority(GetCurrentThread);
|
|
|
|
|
|
SetPriorityClass(GetCurrentProcess, REALTIME_PRIORITY_CLASS);
|
|
|
SetThreadPriority(GetCurrentThread, THREAD_PRIORITY_TIME_CRITICAL);
|
|
|
|
|
|
Sleep(10);
|
|
|
asm
|
|
|
dw 310Fh // rdtsc
|
|
|
mov TimerLo, eax
|
|
|
mov TimerHi, edx
|
|
|
end;
|
|
|
Sleep(DelayTime);
|
|
|
asm
|
|
|
dw 310Fh // rdtsc
|
|
|
sub eax, TimerLo
|
|
|
sbb edx, TimerHi
|
|
|
mov TimerLo, eax
|
|
|
mov TimerHi, edx
|
|
|
end;
|
|
|
|
|
|
SetThreadPriority(GetCurrentThread, Priority);
|
|
|
SetPriorityClass(GetCurrentProcess, PriorityClass);
|
|
|
|
|
|
|
|
|
Result := TimerLo / (1000.0 * DelayTime);
|
|
|
end;
|
|
|
function RDTSC : Int64; assembler;
|
|
|
asm
|
|
|
db $0F, $31 // opcode for RDTSC
|
|
|
end;
|
|
|
|
|
|
function RDQPC : Int64;
|
|
|
begin
|
|
|
QueryPerformanceCounter(result);
|
|
|
end;
|
|
|
|
|
|
function CPUSpeed : Integer;
|
|
|
var
|
|
|
f,tsc,pc : Int64;
|
|
|
begin
|
|
|
if QueryPerformanceFrequency(f) then
|
|
|
begin
|
|
|
Sleep(0);
|
|
|
pc := RDQPC;
|
|
|
tsc := RDTSC;
|
|
|
Sleep(100);
|
|
|
pc := RDQPC-pc;
|
|
|
tsc := RDTSC-tsc;
|
|
|
result := round(tsc*f/(pc*1000000));
|
|
|
end
|
|
|
else
|
|
|
result := -1;
|
|
|
end;
|
|
|
//***************
|
|
|
//获取第一个IDE硬盘的序列号
|
|
|
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;
|
|
|
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 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;
|
|
|
|
|
|
// 更多关于 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应用程序
|
|
|
|
|
|
// 注意:
|
|
|
|
|
|
// WinNT/Win2000 - 你必须拥有对硬盘的读/写访问权限
|
|
|
|
|
|
// Win98
|
|
|
// SMARTVSD.VXD 必须安装到 \windows\system\iosubsys
|
|
|
// (不要忘记在复制后重新启动系统)
|
|
|
function GetDisplayFrequency: Integer;
|
|
|
var
|
|
|
DeviceMode: TDeviceMode;
|
|
|
// 这个函数返回的显示刷新率是以Hz为单位的
|
|
|
begin
|
|
|
EnumDisplaySettings(nil, Cardinal(-1), DeviceMode);
|
|
|
Result := DeviceMode.dmDisplayFrequency;
|
|
|
end;
|
|
|
function GetDisplayDevice: string;
|
|
|
var
|
|
|
lpDisplayDevice: TDisplayDevice;
|
|
|
dwFlags: DWORD;
|
|
|
cc: DWORD;
|
|
|
begin
|
|
|
lpDisplayDevice.cb := sizeof(lpDisplayDevice);
|
|
|
dwFlags := 0;
|
|
|
cc:= 0;
|
|
|
while EnumDisplayDevices(nil, cc, lpDisplayDevice , dwFlags) do
|
|
|
begin
|
|
|
Inc(cc);
|
|
|
if (lpDisplayDevice.DeviceName='\\.\Display1') or (lpDisplayDevice.DeviceName='\\.\DISPLAY1') then
|
|
|
Result :=lpDisplayDevice.DeviceString;
|
|
|
//ListBox1.Items.Add(lpDisplayDevice.DeviceString); {there is also additional information in lpDisplayDevice}
|
|
|
end;
|
|
|
end;
|
|
|
function GetProcessorType:string;
|
|
|
const
|
|
|
PROCESSOR_INTEL_386=386;
|
|
|
PROCESSOR_INTEL_486=486;
|
|
|
PROCESSOR_INTEL_PENTIUM=586;
|
|
|
PROCESSOR_INTEL_IA64=2200;
|
|
|
PROCESSOR_MIPS_R4000=4000;
|
|
|
PROCESSOR_ALPHA_21064=21064;
|
|
|
var
|
|
|
SysInfo: TSYSTEMINFO;
|
|
|
CPUName:string;
|
|
|
begin
|
|
|
GetSystemInfo(SysInfo);//获得CPU信息
|
|
|
case SysInfo.dwProcessorType of
|
|
|
PROCESSOR_INTEL_386:CPUName:=format('%d%s',[SysInfo.dwNumberofProcessors,'Intel 80386']);
|
|
|
PROCESSOR_INTEL_486:CPUName:=format('%d%s',[SysInfo.dwNumberofProcessors, 'Intel 80486']);
|
|
|
PROCESSOR_INTEL_PENTIUM:CPUName:=format('%d%s',[SysInfo.dwNumberOfProcessors, 'Intel Pentium']);
|
|
|
PROCESSOR_MIPS_R4000:CPUName:=format('%d%s',[SysInfo.dwNumberOfProcessors, 'MIPS R4000']);
|
|
|
PROCESSOR_ALPHA_21064:CPUName:=format('%d%s',[SysInfo.dwNumberOfProcessors, 'ALPHA 21064']);
|
|
|
end;
|
|
|
Result :=CPUName;
|
|
|
end;
|
|
|
function GetIdeDiskSerialNumber(var SerialNumber: string; var ModelNumber: string;
|
|
|
var FirmwareRev: string; var TotalAddressableSectors: ULong;
|
|
|
var SectorCapacity: ULong; var SectorsPerTrack: Word): Boolean; //得到硬盘物理号
|
|
|
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 := False;
|
|
|
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(SerialNumber, sSerialNumber, sizeof(sSerialNumber)); //硬盘生产序号
|
|
|
|
|
|
ChangeByteOrder(sModelNumber, sizeof(sModelNumber));
|
|
|
SetString(ModelNumber, sModelNumber, sizeof(sModelNumber)); //硬盘型号
|
|
|
|
|
|
ChangeByteOrder(sFirmwareRev, sizeof(sFirmwareRev));
|
|
|
SetString(FirmwareRev, sFirmwareRev, sizeof(sFirmwareRev)); //硬盘硬件版本
|
|
|
Result := True;
|
|
|
ChangeByteOrder(ulTotalAddressableSectors, sizeof(ulTotalAddressableSectors));
|
|
|
TotalAddressableSectors := ulTotalAddressableSectors; //硬盘ulTotalAddressableSectors参数
|
|
|
|
|
|
ChangeByteOrder(ulCurrentSectorCapacity, sizeof(ulCurrentSectorCapacity));
|
|
|
SectorCapacity := ulCurrentSectorCapacity; //硬盘wBytesPerSector参数
|
|
|
|
|
|
ChangeByteOrder(wNumCurrentSectorsPerTrack, sizeof(wNumCurrentSectorsPerTrack));
|
|
|
SectorsPerTrack := wNumCurrentSectorsPerTrack; //硬盘wSectorsPerTrack参数
|
|
|
end;
|
|
|
end;
|
|
|
function GetWindowsVersion: string;
|
|
|
var
|
|
|
// windows api structure
|
|
|
VersionInfo: TOSVersionInfo;
|
|
|
begin
|
|
|
// get size of the structure
|
|
|
VersionInfo.dwOSVersionInfoSize := SizeOf(VersionInfo);
|
|
|
// populate the struct using api call
|
|
|
GetVersionEx(VersionInfo);
|
|
|
// platformid gets the core platform
|
|
|
// major and minor versions also included.
|
|
|
with VersionInfo do
|
|
|
begin
|
|
|
case dwPlatformid of
|
|
|
0 : begin
|
|
|
result := 'Windows 3.11';
|
|
|
end; // end 0
|
|
|
|
|
|
1 : begin
|
|
|
case dwMinorVersion of
|
|
|
0 : result := 'Windows 95';
|
|
|
10: begin
|
|
|
if ( szCSDVersion[ 1 ] = 'A' ) then
|
|
|
Result :='Windows 98 SE'
|
|
|
else
|
|
|
Result := 'Windows 98';
|
|
|
end; // end 10
|
|
|
90 : result := 'Windows Millenium';
|
|
|
else
|
|
|
result := 'Unknown Version';
|
|
|
end; // end case
|
|
|
end; // end 1
|
|
|
|
|
|
2 : begin
|
|
|
case dwMajorVersion of
|
|
|
3 : result := 'Windows NT ' +
|
|
|
IntToStr(dwMajorVersion) + '.' +
|
|
|
IntToStr(dwMinorVersion);
|
|
|
4 : result := 'Windows NT ' +
|
|
|
IntToStr(dwMajorVersion) + '.' +
|
|
|
IntToStr(dwMinorVersion);
|
|
|
5 : begin
|
|
|
case dwMinorVersion of
|
|
|
0 : result := 'Windows 2000';
|
|
|
1 : result := 'Windows Whistler';
|
|
|
end; // end case
|
|
|
end; // end 5
|
|
|
else
|
|
|
result := 'Unknown Version';
|
|
|
end; // end case
|
|
|
// service packs apply to the NT/2000 platform
|
|
|
if szCSDVersion <> '' then
|
|
|
result := result + ' Service pack: ' + szCSDVersion;
|
|
|
end; // end 2
|
|
|
else
|
|
|
result := 'Unknown Platform';
|
|
|
end; // end case
|
|
|
// add build info.
|
|
|
result := result + ', Build: ' +
|
|
|
IntToStr(Loword(dwBuildNumber)) ;
|
|
|
end; // end version info
|
|
|
end; // GetWindowsVersion
|
|
|
function IsCPUID_Available : Boolean; register;
|
|
|
asm
|
|
|
PUSHFD {direct access to flags no possible, only via stack}
|
|
|
POP EAX {flags to EAX}
|
|
|
MOV EDX,EAX {save current flags}
|
|
|
XOR EAX,ID_BIT {not ID bit}
|
|
|
PUSH EAX {onto stack}
|
|
|
POPFD {from stack to flags, with not ID bit}
|
|
|
PUSHFD {back to stack}
|
|
|
POP EAX {get back to EAX}
|
|
|
XOR EAX,EDX {check if ID bit affected}
|
|
|
JZ @exit {no, CPUID not availavle}
|
|
|
MOV AL,True {Result=True}
|
|
|
@exit:
|
|
|
end;
|
|
|
|
|
|
function GetCPUID : TCPUID; assembler; register;
|
|
|
asm
|
|
|
PUSH EBX {Save affected register}
|
|
|
PUSH EDI
|
|
|
MOV EDI,EAX {@Resukt}
|
|
|
MOV EAX,1
|
|
|
DW $A20F {CPUID Command}
|
|
|
STOSD {CPUID[1]}
|
|
|
MOV EAX,EBX
|
|
|
STOSD {CPUID[2]}
|
|
|
MOV EAX,ECX
|
|
|
STOSD {CPUID[3]}
|
|
|
MOV EAX,EDX
|
|
|
STOSD {CPUID[4]}
|
|
|
POP EDI {Restore registers}
|
|
|
POP EBX
|
|
|
end;
|
|
|
|
|
|
function GetCPUVendor : TVendor; assembler; register;
|
|
|
asm
|
|
|
PUSH EBX {Save affected register}
|
|
|
PUSH EDI
|
|
|
MOV EDI,EAX {@Result (TVendor)}
|
|
|
MOV EAX,0
|
|
|
DW $A20F {CPUID Command}
|
|
|
MOV EAX,EBX
|
|
|
XCHG EBX,ECX {save ECX result}
|
|
|
MOV ECX,4
|
|
|
@1:
|
|
|
STOSB
|
|
|
SHR EAX,8
|
|
|
LOOP @1
|
|
|
MOV EAX,EDX
|
|
|
MOV ECX,4
|
|
|
@2:
|
|
|
STOSB
|
|
|
SHR EAX,8
|
|
|
LOOP @2
|
|
|
MOV EAX,EBX
|
|
|
MOV ECX,4
|
|
|
@3:
|
|
|
STOSB
|
|
|
SHR EAX,8
|
|
|
LOOP @3
|
|
|
POP EDI {Restore registers}
|
|
|
POP EBX
|
|
|
end;
|
|
|
function GetcpuMSG:TcpuMSG;
|
|
|
var
|
|
|
CPUID : TCPUID;
|
|
|
I : Integer;
|
|
|
S : TVendor;
|
|
|
cups:TcpuMSG ;
|
|
|
begin
|
|
|
for I := Low(CPUID) to High(CPUID) do CPUID[I] := -1;
|
|
|
if IsCPUID_Available then
|
|
|
begin
|
|
|
CPUID := GetCPUID;
|
|
|
cups.ID1 := IntToHex(CPUID[1],8);
|
|
|
cups.ID2 := IntToHex(CPUID[2],8);
|
|
|
cups.ID3 := IntToHex(CPUID[3],8);
|
|
|
cups.ID4 := IntToHex(CPUID[4],8);
|
|
|
cups.PValue:= IntToStr(CPUID[1] shr 12 and 3);
|
|
|
cups.FValue:= IntToStr(CPUID[1] shr 8 and $f);
|
|
|
cups.MValue:= IntToStr(CPUID[1] shr 4 and $f);
|
|
|
cups.SValue:= IntToStr(CPUID[1] and $f);
|
|
|
S := GetCPUVendor;
|
|
|
cups.Vendor:= S;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
cups.Vendor := 'CPUID not available';
|
|
|
end;
|
|
|
result :=cups;
|
|
|
end;
|
|
|
|
|
|
end.
|