unit UnitCPU;<br><br>interface<br><br>uses<br>Windows, SysUtils;<br><br>// Call CollectCPUData to refresh information about CPU usage<br>procedure CollectCPUData;<br>// Call it to obtain the number of CPU's in the system<br>function GetCPUCount: integer;<br>// Call it to obtain the % of usage for given CPU<br>function GetCPUUsage(Index: integer): double;<br>// For Win9x only: call it to stop CPU usage monitoring and free system resources<br>procedure ReleaseCPUData;<br><br>implementation<br><br>type<br>PInt64 = ^TInt64;<br>TInt64 = int64;<br><br>type<br>TPERF_DATA_BLOCK = record<br> Signature: array[0..4 - 1] of WCHAR;<br> LittleEndian: DWORD;<br> Version: DWORD;<br> Revision: DWORD;<br> TotalByteLength: DWORD;<br> HeaderLength: DWORD;<br> NumObjectTypes: DWORD;<br> DefaultObject: longint;<br> SystemTime: TSystemTime;<br> Reserved: DWORD;<br> PerfTime: TInt64;<br> PerfFreq: TInt64;<br> PerfTime100nSec: TInt64;<br> SystemNameLength: DWORD;<br> SystemNameOffset: DWORD;<br>end;<br>PPERF_DATA_BLOCK = ^TPERF_DATA_BLOCK;<br><br>TPERF_OBJECT_TYPE = record<br> TotalByteLength: DWORD;<br> DefinitionLength: DWORD;<br> HeaderLength: DWORD;<br> ObjectNameTitleIndex: DWORD;<br> ObjectNameTitle: LPWSTR;<br> ObjectHelpTitleIndex: DWORD;<br> ObjectHelpTitle: LPWSTR;<br> DetailLevel: DWORD;<br> NumCounters: DWORD;<br> DefaultCounter: longint;<br> NumInstances: longint;<br> CodePage: DWORD;<br> PerfTime: TInt64;<br> PerfFreq: TInt64;<br>end;<br>PPERF_OBJECT_TYPE = ^TPERF_OBJECT_TYPE;<br><br>type<br>TPERF_COUNTER_DEFINITION = record<br> ByteLength: DWORD;<br> CounterNameTitleIndex: DWORD;<br> CounterNameTitle: LPWSTR;<br> CounterHelpTitleIndex: DWORD;<br> CounterHelpTitle: LPWSTR;<br> DefaultScale: longint;<br> DetailLevel: DWORD;<br> CounterType: DWORD;<br> CounterSize: DWORD;<br> CounterOffset: DWORD;<br>end;<br>PPERF_COUNTER_DEFINITION = ^TPERF_COUNTER_DEFINITION;<br><br>TPERF_COUNTER_BLOCK = record<br> ByteLength: DWORD;<br>end;<br>PPERF_COUNTER_BLOCK = ^TPERF_COUNTER_BLOCK;<br><br>TPERF_INSTANCE_DEFINITION = record<br> ByteLength: DWORD;<br> ParentObjectTitleIndex: DWORD;<br> ParentObjectInstance: DWORD;<br> UniqueID: longint;<br> NameOffset: DWORD;<br> NameLength: DWORD;<br>end;<br>PPERF_INSTANCE_DEFINITION = ^TPERF_INSTANCE_DEFINITION;<br><br>type<br>TInt64F = TInt64;<br><br>type<br>FInt64 = TInt64F;<br>Int64D = TInt64;<br>//------------------------------------------------------------------------------<br>const<br>Processor_IDX_Str = '238';<br>Processor_IDX = 238;<br>CPUUsageIDX = 6;<br><br>type<br>AInt64F = array[0..$FFFF] of TInt64F;<br>PAInt64F = ^AInt64F;<br><br>var<br>_PerfData: PPERF_DATA_BLOCK;<br>_BufferSize: integer;<br>_POT: PPERF_OBJECT_TYPE;<br>_PCD: PPerf_Counter_Definition;<br>_ProcessorsCount: integer;<br>_Counters: PAInt64F;<br>_PrevCounters: PAInt64F;<br>_SysTime: TInt64F;<br>_PrevSysTime: TInt64F;<br>_IsWinNT: boolean;<br>_W9xCollecting: boolean;<br>_W9xCpuUsage: DWORD;<br>_W9xCpuKey: HKEY;<br>//------------------------------------------------------------------------------<br>function GetCPUCount: integer;<br>begin<br>if _IsWinNT then<br>begin<br> if _ProcessorsCount < 0 then<br> CollectCPUData;<br> Result := _ProcessorsCount;<br>end else<br>begin<br> Result := 1;<br>end;<br>end;<br>//------------------------------------------------------------------------------<br>procedure ReleaseCPUData;<br>var<br>H: HKEY;<br>R: DWORD;<br>dwDataSize, dwType: DWORD;<br>begin<br>if _IsWinNT then<br> exit;<br>if not _W9xCollecting then<br> exit;<br>_W9xCollecting := False;<br>RegCloseKey(_W9xCpuKey);<br>R := RegOpenKeyEx(HKEY_DYN_DATA, 'PerfStats/StopStat', 0, KEY_ALL_ACCESS, H);<br>if R <> ERROR_SUCCESS then<br> exit;<br>dwDataSize := sizeof(DWORD);<br>RegQueryValueEx(H, 'KERNEL/CPUUsage', nil, @dwType, PBYTE(@_W9xCpuUsage),<br> @dwDataSize);<br>RegCloseKey(H);<br>end;<br>//------------------------------------------------------------------------------<br>function GetCPUUsage(Index: integer): double;<br>begin<br>if _IsWinNT then<br>begin<br> if _ProcessorsCount < 0 then<br> CollectCPUData;<br> if (Index >= _ProcessorsCount) or (Index < 0) then<br> raise Exception.Create('CPU index out of bounds');<br> if _PrevSysTime = _SysTime then<br> Result := 0<br> else<br> Result := 1 - (_Counters[index] - _PrevCounters[index]) / (_SysTime - _PrevSysTime);<br>end else<br>begin<br> if Index <> 0 then<br> raise Exception.Create('CPU index out of bounds');<br> if not _W9xCollecting then<br> CollectCPUData;<br> Result := _W9xCpuUsage / 100;<br>end;<br>end;<br><br>var<br>VI: TOSVERSIONINFO;<br>//------------------------------------------------------------------------------<br>procedure CollectCPUData;<br>var<br>BS: integer;<br>i: integer;<br>_PCB_Instance: PPERF_COUNTER_BLOCK;<br>_PID_Instance: PPERF_INSTANCE_DEFINITION;<br>ST: TFileTime;<br>var<br>H: HKEY;<br>R: DWORD;<br>dwDataSize, dwType: DWORD;<br>begin<br>if _IsWinNT then<br>begin<br> BS := _BufferSize;<br> while RegQueryValueEx(HKEY_PERFORMANCE_DATA, Processor_IDX_Str,<br> nil, nil, PByte(_PerfData), @BS) = ERROR_MORE_DATA do<br> begin<br> // Get a buffer that is big enough.<br> Inc(_BufferSize, $1000);<br> BS := _BufferSize;<br> ReallocMem(_PerfData, _BufferSize);<br> end;<br> // Locate the performance object<br> _POT := PPERF_OBJECT_TYPE(DWORD(_PerfData) + _PerfData.HeaderLength);<br> for i := 1 to _PerfData.NumObjectTypes do<br> begin<br> if _POT.ObjectNameTitleIndex = Processor_IDX then<br> Break;<br> _POT := PPERF_OBJECT_TYPE(DWORD(_POT) + _POT.TotalByteLength);<br> end;<br> // Check for success<br> if _POT.ObjectNameTitleIndex <> Processor_IDX then<br> raise Exception.Create(<br> 'Unable to locate the "Processor" performance object');<br> if _ProcessorsCount < 0 then<br> begin<br> _ProcessorsCount := _POT.NumInstances;<br> GetMem(_Counters, _ProcessorsCount * SizeOf(TInt64));<br> GetMem(_PrevCounters, _ProcessorsCount * SizeOf(TInt64));<br> end;<br> // Locate the "% CPU usage" counter definition<br> _PCD := PPERF_Counter_DEFINITION(DWORD(_POT) + _POT.HeaderLength);<br> for i := 1 to _POT.NumCounters do<br> begin<br> if _PCD.CounterNameTitleIndex = CPUUsageIDX then<br> break;<br> _PCD := PPERF_COUNTER_DEFINITION(DWORD(_PCD) + _PCD.ByteLength);<br> end;<br> // Check for success<br> if _PCD.CounterNameTitleIndex <> CPUUsageIDX then<br> raise Exception.Create(<br> 'Unable to locate the "% of CPU usage" performance counter');<br> // Collecting coutners<br> _PID_Instance := PPERF_INSTANCE_DEFINITION(DWORD(_POT) + _POT.DefinitionLength);<br> for i := 0 to _ProcessorsCount - 1 do<br> begin<br> _PCB_Instance := PPERF_COUNTER_BLOCK(DWORD(_PID_Instance) +<br> _PID_Instance.ByteLength);<br> _PrevCounters := _Counters;<br> _Counters := FInt64(PInt64(DWORD(_PCB_Instance) + _PCD.CounterOffset)^);<br> _PID_Instance := PPERF_INSTANCE_DEFINITION(DWORD(_PCB_Instance) +<br> _PCB_Instance.ByteLength);<br> end;<br> _PrevSysTime := _SysTime;<br> SystemTimeToFileTime(_PerfData.SystemTime, ST);<br> _SysTime := FInt64(TInt64(ST));<br>end else<br>begin<br> if not _W9xCollecting then<br> begin<br> R := RegOpenKeyEx(HKEY_DYN_DATA, 'PerfStats/StartStat',<br> 0, KEY_ALL_ACCESS, H);<br> if R <> ERROR_SUCCESS then<br> raise Exception.Create('Unable to start performance monitoring');<br> dwDataSize := sizeof(DWORD);<br> RegQueryValueEx(H, 'KERNEL/CPUUsage', nil, @dwType,<br> PBYTE(@_W9xCpuUsage), @dwDataSize);<br> RegCloseKey(H);<br> R := RegOpenKeyEx(HKEY_DYN_DATA, 'PerfStats/StatData',<br> 0, KEY_READ, _W9xCpuKey);<br> if R <> ERROR_SUCCESS then<br> raise Exception.Create('Unable to read performance data');<br> _W9xCollecting := True;<br> end;<br> dwDataSize := sizeof(DWORD);<br> RegQueryValueEx(_W9xCpuKey, 'KERNEL/CPUUsage', nil, @dwType,<br> PBYTE(@_W9xCpuUsage), @dwDataSize);<br>end;<br>end;<br><br>initialization<br>_ProcessorsCount := -1;<br>_BufferSize := $2000;<br>_PerfData := AllocMem(_BufferSize);<br>VI.dwOSVersionInfoSize := SizeOf(VI);<br>if not GetVersionEx(VI) then<br> raise Exception.Create('Can''t get the Windows version');<br>_IsWinNT := VI.dwPlatformId = VER_PLATFORM_WIN32_NT;<br><br>finalization<br>ReleaseCPUData;<br>FreeMem(_PerfData);<br>end.