Componentes.Terceros.jcl/official/1.96/source/common/JclSysInfo.pas

5436 lines
180 KiB
ObjectPascal

{**************************************************************************************************}
{ }
{ Project JEDI Code Library (JCL) }
{ }
{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
{ you may not use this file except in compliance with the License. You may obtain a copy of the }
{ License at http://www.mozilla.org/MPL/ }
{ }
{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
{ ANY KIND, either express or implied. See the License for the specific language governing rights }
{ and limitations under the License. }
{ }
{ The Original Code is JclSysInfo.pas. }
{ }
{ The Initial Developer of the Original Code is Marcel van Brakel. }
{ Portions created by Marcel van Brakel are Copyright (C) Marcel van Brakel. All rights reserved. }
{ }
{ Contributors: }
{ Alexander Radchenko }
{ André Snepvangers (asnepvangers) }
{ Azret Botash }
{ Bryan Coutch }
{ Carl Clark }
{ Eric S. Fisher }
{ Florent Ouchet (outchy) }
{ James Azarja }
{ Jean-Fabien Connault }
{ John C Molyneux }
{ Marcel van Brakel }
{ Matthias Thoma (mthoma) }
{ Mike Lischke }
{ Nick Hodges }
{ Olivier Sannier (obones) }
{ Peter Friese }
{ Peter Thörnquist (peter3) }
{ Petr Vones (pvones) }
{ Rik Barker }
{ Robert Marquardt (marquardt) }
{ Robert Rossmair (rrossmair) }
{ Scott Price }
{ Tom Hahn (tomhahn) }
{ Wim de Cleen }
{ }
{**************************************************************************************************}
{ }
{ This unit contains routines and classes to retrieve various pieces of system information. }
{ Examples are the location of standard folders, settings of environment variables, processor }
{ details and the Windows version. }
{ }
{**************************************************************************************************}
// Last modified: $Date: 2005/12/12 21:54:09 $
// For history see end of file
// Windows NT 4 and earlier do not support GetSystemPowerStatus (while introduced
// in NT4 - it is a stub there - implemented in Windows 2000 and later.
unit JclSysInfo;
{$I jcl.inc}
interface
uses
{$IFDEF HAS_UNIT_TYPES}
Types,
{$ENDIF HAS_UNIT_TYPES}
{$IFDEF HAS_UNIT_LIBC}
Libc,
{$ENDIF HAS_UNIT_LIBC}
{$IFDEF CLR}
System.IO, System.Configuration, System.Diagnostics, System.Collections,
System.Net, System.ComponentModel,
{$ELSE ~CLR}
{$IFDEF MSWINDOWS}
Windows,
{$IFNDEF FPC}
ShlObj,
{$ENDIF ~FPC}
{$ENDIF MSWINDOWS}
{$ENDIF ~CLR}
Classes,
JclResources;
// Environment Variables
{$IFDEF MSWINDOWS}
type
TEnvironmentOption = (eoLocalMachine, eoCurrentUser, eoAdditional);
TEnvironmentOptions = set of TEnvironmentOption;
{$ENDIF MSWINDOWS}
{$IFDEF CLR}
type
DWORD = LongWord;
{$ENDIF CLR}
function DelEnvironmentVar(const Name: string): Boolean;
function ExpandEnvironmentVar(var Value: string): Boolean;
function GetEnvironmentVar(const Name: string; var Value: string): Boolean; overload;
function GetEnvironmentVar(const Name: string; var Value: string; Expand: Boolean): Boolean; overload;
function GetEnvironmentVars(const Vars: TStrings): Boolean; overload;
function GetEnvironmentVars(const Vars: TStrings; Expand: Boolean): Boolean; overload;
function SetEnvironmentVar(const Name, Value: string): Boolean;
{$IFNDEF CLR}
{$IFDEF MSWINDOWS}
function CreateEnvironmentBlock(const Options: TEnvironmentOptions; const AdditionalVars: TStrings): PChar;
procedure DestroyEnvironmentBlock(var Env: PChar);
procedure SetGlobalEnvironmentVariable(VariableName, VariableContent: string);
{$ENDIF MSWINDOWS}
{$ENDIF ~CLR}
// Common Folder Locations
{$IFNDEF CLR}
{$IFDEF MSWINDOWS}
function GetCommonFilesFolder: string;
{$ENDIF MSWINDOWS}
{$ENDIF ~CLR}
function GetCurrentFolder: string;
{$IFDEF MSWINDOWS}
function GetProgramFilesFolder: string;
{$IFNDEF CLR}
function GetWindowsFolder: string;
{$ENDIF ~CLR}
function GetWindowsSystemFolder: string;
function GetWindowsTempFolder: string;
function GetDesktopFolder: string;
function GetProgramsFolder: string;
{$ENDIF MSWINDOWS}
function GetPersonalFolder: string;
{$IFDEF MSWINDOWS}
function GetFavoritesFolder: string;
function GetStartupFolder: string;
function GetRecentFolder: string;
function GetSendToFolder: string;
function GetStartmenuFolder: string;
function GetDesktopDirectoryFolder: string;
{$IFNDEF CLR}
function GetNethoodFolder: string;
function GetFontsFolder: string;
function GetCommonStartmenuFolder: string;
function GetCommonStartupFolder: string;
function GetPrinthoodFolder: string;
function GetProfileFolder: string;
{$ENDIF ~CLR}
function GetCommonProgramsFolder: string;
function GetCommonDesktopdirectoryFolder: string;
function GetCommonAppdataFolder: string;
function GetAppdataFolder: string;
function GetCommonFavoritesFolder: string;
function GetTemplatesFolder: string;
function GetInternetCacheFolder: string;
function GetCookiesFolder: string;
function GetHistoryFolder: string;
{$IFNDEF CLR}
// Advanced Power Management (APM)
type
TAPMLineStatus = (alsOffline, alsOnline, alsUnknown);
TAPMBatteryFlag = (abfHigh, abfLow, abfCritical, abfCharging, abfNoBattery, abfUnknown);
TAPMBatteryFlags = set of TAPMBatteryFlag;
function GetAPMLineStatus: TAPMLineStatus;
function GetAPMBatteryFlag: TAPMBatteryFlag;
function GetAPMBatteryFlags: TAPMBatteryFlags;
function GetAPMBatteryLifePercent: Integer;
function GetAPMBatteryLifeTime: DWORD;
function GetAPMBatteryFullLifeTime: DWORD;
// Identification
type
TFileSystemFlag =
(
fsCaseSensitive, // The file system supports case-sensitive file names.
fsCasePreservedNames, // The file system preserves the case of file names when it places a name on disk.
fsSupportsUnicodeOnDisk, // The file system supports Unicode in file names as they appear on disk.
fsPersistentACLs, // The file system preserves and enforces ACLs. For example, NTFS preserves and enforces ACLs, and FAT does not.
fsSupportsFileCompression, // The file system supports file-based compression.
fsSupportsVolumeQuotas, // The file system supports disk quotas.
fsSupportsSparseFiles, // The file system supports sparse files.
fsSupportsReparsePoints, // The file system supports reparse points.
fsSupportsRemoteStorage, // ?
fsVolumeIsCompressed, // The specified volume is a compressed volume; for example, a DoubleSpace volume.
fsSupportsObjectIds, // The file system supports object identifiers.
fsSupportsEncryption, // The file system supports the Encrypted File System (EFS).
fsSupportsNamedStreams, // The file system supports named streams.
fsVolumeIsReadOnly // The specified volume is read-only.
// Windows 2000/NT and Windows Me/98/95: This value is not supported.
);
TFileSystemFlags = set of TFileSystemFlag;
function GetVolumeName(const Drive: string): string;
function GetVolumeSerialNumber(const Drive: string): string;
function GetVolumeFileSystem(const Drive: string): string;
function GetVolumeFileSystemFlags(const Volume: string): TFileSystemFlags;
{$ENDIF ~CLR}
{$ENDIF MSWINDOWS}
function GetIPAddress(const HostName: string): string;
{$IFDEF UNIX}
procedure GetIpAddresses(Results: TStrings);
{$ENDIF UNIX}
function GetLocalComputerName: string;
{$IFNDEF CLR}
function GetLocalUserName: string;
{$IFDEF MSWINDOWS}
function GetUserDomainName(const CurUser: string): string;
{$ENDIF MSWINDOWS}
function GetDomainName: string;
{$IFDEF MSWINDOWS}
function GetRegisteredCompany: string;
function GetRegisteredOwner: string;
function GetBIOSName: string;
function GetBIOSCopyright: string;
function GetBIOSExtendedInfo: string;
function GetBIOSDate: TDateTime;
{$ENDIF MSWINDOWS}
// Processes, Tasks and Modules
type
TJclTerminateAppResult = (taError, taClean, taKill);
{$ENDIF ~CLR}
function RunningProcessesList(const List: TStrings; FullPath: Boolean = True): Boolean;
{$IFDEF MSWINDOWS}
{$IFNDEF CLR}
function LoadedModulesList(const List: TStrings; ProcessID: DWORD; HandlesOnly: Boolean = False): Boolean;
function GetTasksList(const List: TStrings): Boolean;
function ModuleFromAddr(const Addr: Pointer): HMODULE;
{$IFNDEF FPC}
function IsSystemModule(const Module: HMODULE): Boolean;
{$ENDIF ~FPC}
function IsMainAppWindow(Wnd: THandle): Boolean;
function IsWindowResponding(Wnd: THandle; Timeout: Integer): Boolean;
function GetWindowIcon(Wnd: THandle; LargeIcon: Boolean): HICON;
function GetWindowCaption(Wnd: THandle): string;
function TerminateTask(Wnd: THandle; Timeout: Integer): TJclTerminateAppResult;
function TerminateApp(ProcessID: DWORD; Timeout: Integer): TJclTerminateAppResult;
{$ENDIF ~CLR}
{$ENDIF MSWINDOWS}
{$IFNDEF CLR}
{$IFDEF MSWINDOWS}
{.$IFNDEF FPC}
function GetPidFromProcessName(const ProcessName: string): DWORD;
function GetProcessNameFromWnd(Wnd: THandle): string;
function GetProcessNameFromPid(PID: DWORD): string;
function GetMainAppWndFromPid(PID: DWORD): THandle;
{.$ENDIF ~FPC}
function GetShellProcessName: string;
{.$IFNDEF FPC}
function GetShellProcessHandle: THandle;
{.$ENDIF ~FPC}
// Version Information
type
TWindowsVersion =
(wvUnknown, wvWin95, wvWin95OSR2, wvWin98, wvWin98SE, wvWinME,
wvWinNT31, wvWinNT35, wvWinNT351, wvWinNT4, wvWin2000, wvWinXP,
wvWin2003, wvWinXP64, wvWin2003R2, wvWinVista, wvWinLonghorn);
TNtProductType =
(ptUnknown, ptWorkStation, ptServer, ptAdvancedServer,
ptPersonal, ptProfessional, ptDatacenterServer, ptEnterprise, ptWebEdition);
TProcessorArchitecture =
(paUnknown, // unknown processor
pax8632, // x86 32 bit processors (some P4, Celeron, Athlon and older)
pax8664, // x86 64 bit processors (latest P4, Celeron and Athlon64)
paIA64); // Itanium processors
var
{ in case of additions, don't forget to update initialization section! }
IsWin95: Boolean = False;
IsWin95OSR2: Boolean = False;
IsWin98: Boolean = False;
IsWin98SE: Boolean = False;
IsWinME: Boolean = False;
IsWinNT: Boolean = False;
IsWinNT3: Boolean = False;
IsWinNT31: Boolean = False;
IsWinNT35: Boolean = False;
IsWinNT351: Boolean = False;
IsWinNT4: Boolean = False;
IsWin2K: Boolean = False;
IsWinXP: Boolean = False;
IsWin2003: Boolean = False;
IsWinXP64: Boolean = False;
IsWin2003R2: Boolean = False;
IsWinVista: Boolean = False;
IsWinLonghorn: Boolean = False;
const
PROCESSOR_ARCHITECTURE_INTEL = 0;
{$EXTERNALSYM PROCESSOR_ARCHITECTURE_INTEL}
PROCESSOR_ARCHITECTURE_AMD64 = 9;
{$EXTERNALSYM PROCESSOR_ARCHITECTURE_AMD64}
PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 = 10;
{$EXTERNALSYM PROCESSOR_ARCHITECTURE_IA32_ON_WIN64}
PROCESSOR_ARCHITECTURE_IA64 = 6;
{$EXTERNALSYM PROCESSOR_ARCHITECTURE_IA64}
function GetWindowsVersion: TWindowsVersion;
function NtProductType: TNtProductType;
function GetWindowsVersionString: string;
function NtProductTypeString: string;
function GetWindowsServicePackVersion: Integer;
function GetWindowsServicePackVersionString: string;
function GetOpenGLVersion(const Win: THandle; out Version, Vendor: AnsiString): Boolean;
function GetNativeSystemInfo(var SystemInfo: TSystemInfo): Boolean;
function GetProcessorArchitecture: TProcessorArchitecture;
function IsWindows64: Boolean;
{$ENDIF MSWINDOWS}
function GetOSVersionString: string;
// Hardware
{$IFDEF MSWINDOWS}
function GetMacAddresses(const Machine: string; const Addresses: TStrings): Integer;
{$ENDIF MSWINDOWS}
function ReadTimeStampCounter: Int64;
type
TTLBInformation = (tiEntries, tiAssociativity);
TCacheInformation = (ciLineSize {in Bytes}, ciLinesPerTag, ciAssociativity, ciSize);
TIntelSpecific = record
L2Cache: Cardinal;
CacheDescriptors: array [0..15] of Byte;
BrandID: Byte;
ExFeatures: Cardinal;
Ex64Features: Cardinal;
end;
TCyrixSpecific = record
L1CacheInfo: array [0..3] of Byte;
TLBInfo: array [0..3] of Byte;
end;
TAMDSpecific = record
ExFeatures: Cardinal;
MByteDataTLB: array [TTLBInformation] of Byte;
MByteInstructionTLB: array [TTLBInformation] of Byte;
KByteDataTLB: array [TTLBInformation] of Byte;
KByteInstructionTLB: array [TTLBInformation] of Byte;
L1DataCache: array [TCacheInformation] of Byte;
L1InstructionCache: array [TCacheInformation] of Byte;
L2MByteDataTLB: array [TTLBInformation] of Byte; // L2 TLB for 2-MByte and 4-MByte pages
L2MByteInstructionTLB: array [TTLBInformation] of Byte; // L2 TLB for 2-MByte and 4-MByte pages
L2KByteDataTLB: array [TTLBInformation] of Byte; // L2 TLB for 4-KByte pages
L2KByteInstructionTLB: array [TTLBInformation] of Byte; // L2 TLB for 4-KByte pages
L2Cache: Cardinal;
AdvancedPowerManagement: Cardinal;
PhysicalAddressSize: Byte;
VirtualAddressSize: Byte;
end;
TVIASpecific = record
ExFeatures: Cardinal;
DataTLB: array [TTLBInformation] of Byte;
InstructionTLB: array [TTLBInformation] of Byte;
L1DataCache: array [TCacheInformation] of Byte;
L1InstructionCache: array [TCacheInformation] of Byte;
L2DataCache: Cardinal;
end;
TTransmetaSpecific = record
ExFeatures: Cardinal;
DataTLB: array [TTLBInformation] of Byte;
CodeTLB: array [TTLBInformation] of Byte;
L1DataCache: array [TCacheInformation] of Byte;
L1CodeCache: array [TCacheInformation] of Byte;
L2Cache: Cardinal;
RevisionABCD: Cardinal;
RevisionXXXX: Cardinal;
Frequency: Cardinal;
CodeMorphingABCD: Cardinal;
CodeMorphingXXXX: Cardinal;
TransmetaFeatures: Cardinal;
TransmetaInformations: array [0..64] of Char;
CurrentVoltage: Cardinal;
CurrentFrequency: Cardinal;
CurrentPerformance: Cardinal;
end;
TCacheFamily = (
cfInstructionTLB, cfDataTLB,
cfL1InstructionCache, cfL1DataCache,
cfL2Cache, cfL3Cache, cfTrace, cfOther);
TCacheInfo = record
D: Byte;
Family: TCacheFamily;
Size: Cardinal;
WaysOfAssoc: Byte;
LineSize: Byte; // for Normal Cache
LinePerSector: Byte; // for L3 Normal Cache
Entries: Cardinal; // for TLB
I: string;
end;
TFreqInfo = record
RawFreq: Cardinal;
NormFreq: Cardinal;
InCycles: Cardinal;
ExTicks: Cardinal;
end;
const
CPU_TYPE_INTEL = 1;
CPU_TYPE_CYRIX = 2;
CPU_TYPE_AMD = 3;
CPU_TYPE_TRANSMETA = 4;
CPU_TYPE_VIA = 5;
type
TCpuInfo = record
HasInstruction: Boolean;
MMX: Boolean;
ExMMX: Boolean;
_3DNow: Boolean;
Ex3DNow: Boolean;
SSE: Byte; // SSE version 0 = no SSE, 1 = SSE, 2 = SSE2, 3 = SSE3
IsFDIVOK: Boolean;
Is64Bits: Boolean;
HasCacheInfo: Boolean;
HasExtendedInfo: Boolean;
PType: Byte;
Family: Byte;
ExtendedFamily: Byte;
Model: Byte;
ExtendedModel: Byte;
Stepping: Byte;
Features: Cardinal;
FrequencyInfo: TFreqInfo;
VendorIDString: array [0..11] of Char;
Manufacturer: array [0..9] of Char;
CpuName: array [0..47] of Char;
L1DataCacheSize: Cardinal; // in kByte
L1DataCacheLineSize: Byte; // in Byte
L1DataCacheAssociativity: Byte;
L1InstructionCacheSize: Cardinal; // in kByte
L1InstructionCacheLineSize: Byte; // in Byte
L1InstructionCacheAssociativity: Byte;
L2CacheSize: Cardinal; // in kByte
L2CacheLineSize: Byte; // in Byte
L2CacheAssociativity: Byte;
L3CacheSize: Cardinal; // in kByte
L3CacheLineSize: Byte; // in Byte
L3CacheAssociativity: Byte;
L3LinesPerSector: Byte;
// todo: TLB
case CpuType: Byte of
CPU_TYPE_INTEL: (IntelSpecific: TIntelSpecific;);
CPU_TYPE_CYRIX: (CyrixSpecific: TCyrixSpecific;);
CPU_TYPE_AMD: (AMDSpecific: TAMDSpecific;);
CPU_TYPE_TRANSMETA: (TransmetaSpecific: TTransmetaSpecific;);
CPU_TYPE_VIA: (ViaSpecific: TViaSpecific;);
end;
const
VendorIDIntel: array [0..11] of Char = 'GenuineIntel';
VendorIDCyrix: array [0..11] of Char = 'CyrixInstead';
VendorIDAMD: array [0..11] of Char = 'AuthenticAMD';
VendorIDTransmeta: array [0..11] of Char = 'GenuineTMx86';
VendorIDVIA: array [0..11] of Char = 'CentaurHauls';
// Constants to be used with Feature Flag set of a CPU
// eg. IF (Features and FPU_FLAG = FPU_FLAG) THEN CPU has Floating-Point unit on
// chip. However, Intel claims that in future models, a zero in the feature
// flags will mean that the chip has that feature, however, the following flags
// will work for any production 80x86 chip or clone.
// eg. IF (Features and FPU_FLAG = 0) then CPU has Floating-Point unit on chip.
const
{ 32 bits in a DWord Value }
BIT_0 = $00000001;
BIT_1 = $00000002;
BIT_2 = $00000004;
BIT_3 = $00000008;
BIT_4 = $00000010;
BIT_5 = $00000020;
BIT_6 = $00000040;
BIT_7 = $00000080;
BIT_8 = $00000100;
BIT_9 = $00000200;
BIT_10 = $00000400;
BIT_11 = $00000800;
BIT_12 = $00001000;
BIT_13 = $00002000;
BIT_14 = $00004000;
BIT_15 = $00008000;
BIT_16 = $00010000;
BIT_17 = $00020000;
BIT_18 = $00040000;
BIT_19 = $00080000;
BIT_20 = $00100000;
BIT_21 = $00200000;
BIT_22 = $00400000;
BIT_23 = $00800000;
BIT_24 = $01000000;
BIT_25 = $02000000;
BIT_26 = $04000000;
BIT_27 = $08000000;
BIT_28 = $10000000;
BIT_29 = $20000000;
BIT_30 = $40000000;
BIT_31 = DWORD($80000000);
{ Standard Feature Flags }
FPU_FLAG = BIT_0; // Floating-Point unit on chip
VME_FLAG = BIT_1; // Virtual Mode Extention
DE_FLAG = BIT_2; // Debugging Extention
PSE_FLAG = BIT_3; // Page Size Extention
TSC_FLAG = BIT_4; // Time Stamp Counter
MSR_FLAG = BIT_5; // Model Specific Registers
PAE_FLAG = BIT_6; // Physical Address Extention
MCE_FLAG = BIT_7; // Machine Check Exception
CX8_FLAG = BIT_8; // CMPXCHG8 Instruction
APIC_FLAG = BIT_9; // Software-accessible local APIC on Chip
BIT_10_FLAG = BIT_10; // Reserved, do not count on value
SEP_FLAG = BIT_11; // Fast System Call
MTRR_FLAG = BIT_12; // Memory Type Range Registers
PGE_FLAG = BIT_13; // Page Global Enable
MCA_FLAG = BIT_14; // Machine Check Architecture
CMOV_FLAG = BIT_15; // Conditional Move Instruction
PAT_FLAG = BIT_16; // Page Attribute Table
PSE36_FLAG = BIT_17; // 36-bit Page Size Extention
PSN_FLAG = BIT_18; // Processor serial number is present and enabled
CLFLSH_FLAG = BIT_19; // CLFLUSH intruction
BIT_20_FLAG = BIT_20; // Reserved, do not count on value
DS_FLAG = BIT_21; // Debug store
ACPI_FLAG = BIT_22; // Thermal monitor and clock control
MMX_FLAG = BIT_23; // MMX technology
FXSR_FLAG = BIT_24; // Fast Floating Point Save and Restore
SSE_FLAG = BIT_25; // Streaming SIMD Extensions
SSE2_FLAG = BIT_26; // Streaming SIMD Extensions 2
SS_FLAG = BIT_27; // Self snoop
HTT_FLAG = BIT_28; // Hyper-threading technology
TM_FLAG = BIT_29; // Thermal monitor
BIT_30_FLAG = BIT_30; // Reserved, do not count on value
PBE_FLAG = BIT_31; // Pending Break Enable
{ Standard Intel Feature Flags }
INTEL_FPU = BIT_0; // Floating-Point unit on chip
INTEL_VME = BIT_1; // Virtual Mode Extention
INTEL_DE = BIT_2; // Debugging Extention
INTEL_PSE = BIT_3; // Page Size Extention
INTEL_TSC = BIT_4; // Time Stamp Counter
INTEL_MSR = BIT_5; // Model Specific Registers
INTEL_PAE = BIT_6; // Physical Address Extention
INTEL_MCE = BIT_7; // Machine Check Exception
INTEL_CX8 = BIT_8; // CMPXCHG8 Instruction
INTEL_APIC = BIT_9; // Software-accessible local APIC on Chip
INTEL_BIT_10 = BIT_10; // Reserved, do not count on value
INTEL_SEP = BIT_11; // Fast System Call
INTEL_MTRR = BIT_12; // Memory Type Range Registers
INTEL_PGE = BIT_13; // Page Global Enable
INTEL_MCA = BIT_14; // Machine Check Architecture
INTEL_CMOV = BIT_15; // Conditional Move Instruction
INTEL_PAT = BIT_16; // Page Attribute Table
INTEL_PSE36 = BIT_17; // 36-bit Page Size Extention
INTEL_PSN = BIT_18; // Processor serial number is present and enabled
INTEL_CLFLSH = BIT_19; // CLFLUSH intruction
INTEL_BIT_20 = BIT_20; // Reserved, do not count on value
INTEL_DS = BIT_21; // Debug store
INTEL_ACPI = BIT_22; // Thermal monitor and clock control
INTEL_MMX = BIT_23; // MMX technology
INTEL_FXSR = BIT_24; // Fast Floating Point Save and Restore
INTEL_SSE = BIT_25; // Streaming SIMD Extensions
INTEL_SSE2 = BIT_26; // Streaming SIMD Extensions 2
INTEL_SS = BIT_27; // Self snoop
INTEL_HTT = BIT_28; // Hyper-threading technology
INTEL_TM = BIT_29; // Thermal monitor
INTEL_BIT_30 = BIT_30; // Reserved, do not count on value
INTEL_PBE = BIT_31; // Pending Break Enable
{ Extended Intel Feature Flags }
EINTEL_SSE3 = BIT_0; // Streaming SIMD Extensions 3
EINTEL_BIT_1 = BIT_1; // Reserved, do not count on value
EINTEL_BIT_2 = BIT_2; // Reserved, do not count on value
EINTEL_MONITOR = BIT_3; // Monitor/MWAIT
EINTEL_DSCPL = BIT_4; // CPL Qualified debug Store
EINTEL_BIT_5 = BIT_5; // Reserved, do not count on value
EINTEL_BIT_6 = BIT_6; // Reserved, do not count on value
EINTEL_EST = BIT_7; // Enhanced Intel Speedstep technology
EINTEL_TM2 = BIT_8; // Thermal monitor 2
EINTEL_BIT_9 = BIT_9; // Reserved, do not count on value
EINTEL_CNXTID = BIT_10; // L1 Context ID
EINTEL_BIT_11 = BIT_11; // Reserved, do not count on value
EINTEL_BIT_12 = BIT_12; // Reserved, do not count on value
EINTEL_BIT_13 = BIT_13; // Reserved, do not count on value
EINTEL_XTPR = BIT_14; // Send Task Priority messages
EINTEL_BIT_15 = BIT_15; // Reserved, do not count on value
EINTEL_BIT_16 = BIT_16; // Reserved, do not count on value
EINTEL_BIT_17 = BIT_17; // Reserved, do not count on value
EINTEL_BIT_18 = BIT_18; // Reserved, do not count on value
EINTEL_BIT_19 = BIT_19; // Reserved, do not count on value
EINTEL_BIT_20 = BIT_20; // Reserved, do not count on value
EINTEL_BIT_21 = BIT_21; // Reserved, do not count on value
EINTEL_BIT_22 = BIT_22; // Reserved, do not count on value
EINTEL_BIT_23 = BIT_23; // Reserved, do not count on value
EINTEL_BIT_24 = BIT_24; // Reserved, do not count on value
EINTEL_BIT_25 = BIT_25; // Reserved, do not count on value
EINTEL_BIT_26 = BIT_26; // Reserved, do not count on value
EINTEL_BIT_27 = BIT_27; // Reserved, do not count on value
EINTEL_BIT_28 = BIT_28; // Reserved, do not count on value
EINTEL_BIT_29 = BIT_29; // Reserved, do not count on value
EINTEL_BIT_30 = BIT_30; // Reserved, do not count on value
EINTEL_BIT_31 = BIT_31; // Reserved, do not count on value
{ Extended Intel 64 Bits Feature Flags }
EINTEL64_BIT_0 = BIT_0; // Reserved, do not count on value
EINTEL64_BIT_1 = BIT_1; // Reserved, do not count on value
EINTEL64_BIT_2 = BIT_2; // Reserved, do not count on value
EINTEL64_BIT_3 = BIT_3; // Reserved, do not count on value
EINTEL64_BIT_4 = BIT_4; // Reserved, do not count on value
EINTEL64_BIT_5 = BIT_5; // Reserved, do not count on value
EINTEL64_BIT_6 = BIT_6; // Reserved, do not count on value
EINTEL64_BIT_7 = BIT_7; // Reserved, do not count on value
EINTEL64_BIT_8 = BIT_8; // Reserved, do not count on value
EINTEL64_BIT_9 = BIT_9; // Reserved, do not count on value
EINTEL64_BIT_10 = BIT_10; // Reserved, do not count on value
EINTEL64_SYS = BIT_11; // 64 Bit - SYSCALL SYSRET
EINTEL64_BIT_12 = BIT_12; // Reserved, do not count on value
EINTEL64_BIT_13 = BIT_13; // Reserved, do not count on value
EINTEL64_BIT_14 = BIT_14; // Reserved, do not count on value
EINTEL64_BIT_15 = BIT_15; // Reserved, do not count on value
EINTEL64_BIT_16 = BIT_16; // Reserved, do not count on value
EINTEL64_BIT_17 = BIT_17; // Reserved, do not count on value
EINTEL64_BIT_18 = BIT_18; // Reserved, do not count on value
EINTEL64_BIT_19 = BIT_19; // Reserved, do not count on value
EINTEL64_BIT_20 = BIT_20; // Reserved, do not count on value
EINTEL64_BIT_21 = BIT_21; // Reserved, do not count on value
EINTEL64_BIT_22 = BIT_22; // Reserved, do not count on value
EINTEL64_BIT_23 = BIT_23; // Reserved, do not count on value
EINTEL64_BIT_24 = BIT_24; // Reserved, do not count on value
EINTEL64_BIT_25 = BIT_25; // Reserved, do not count on value
EINTEL64_BIT_26 = BIT_26; // Reserved, do not count on value
EINTEL64_BIT_27 = BIT_27; // Reserved, do not count on value
EINTEL64_BIT_28 = BIT_28; // Reserved, do not count on value
EINTEL64_EM64T = BIT_29; // Intel® Extended Memory 64 Technology
EINTEL64_BIT_30 = BIT_30; // Reserved, do not count on value
EINTEL64_BIT_31 = BIT_31; // Reserved, do not count on value
{ AMD Standard Feature Flags }
AMD_FPU = BIT_0; // Floating-Point unit on chip
AMD_VME = BIT_1; // Virtual Mode Extention
AMD_DE = BIT_2; // Debugging Extention
AMD_PSE = BIT_3; // Page Size Extention
AMD_TSC = BIT_4; // Time Stamp Counter
AMD_MSR = BIT_5; // Model Specific Registers
AMD_PAE = BIT_6; // Physical address Extensions
AMD_MCE = BIT_7; // Machine Check Exception
AMD_CX8 = BIT_8; // CMPXCHG8 Instruction
AMD_APIC = BIT_9; // Software-accessible local APIC on Chip
AMD_BIT_10 = BIT_10; // Reserved, do not count on value
AMD_SEP_BIT = BIT_11; // SYSENTER and SYSEXIT instructions
AMD_MTRR = BIT_12; // Memory Type Range Registers
AMD_PGE = BIT_13; // Page Global Enable
AMD_MCA = BIT_14; // Machine Check Architecture
AMD_CMOV = BIT_15; // Conditional Move Instruction
AMD_PAT = BIT_16; // Page Attribute Table
AMD_PSE2 = BIT_17; // Page Size Extensions
AMD_BIT_18 = BIT_18; // Reserved, do not count on value
AMD_CLFLSH = BIT_19; // CLFLUSH instruction
AMD_BIT_20 = BIT_20; // Reserved, do not count on value
AMD_BIT_21 = BIT_21; // Reserved, do not count on value
AMD_BIT_22 = BIT_22; // Reserved, do not count on value
AMD_MMX = BIT_23; // MMX technology
AMD_FX = BIT_24; // FXSAVE and FXSTORE instructions
AMD_SSE = BIT_25; // SSE Extensions
AMD_SSE2 = BIT_26; // SSE2 Extensions
AMD_BIT_27 = BIT_27; // Reserved, do not count on value
AMD_BIT_28 = BIT_28; // Reserved, do not count on value
AMD_BIT_29 = BIT_29; // Reserved, do not count on value
AMD_BIT_30 = BIT_30; // Reserved, do not count on value
AMD_BIT_31 = BIT_31; // Reserved, do not count on value
{ AMD Enhanced Feature Flags }
EAMD_FPU = BIT_0; // Floating-Point unit on chip
EAMD_VME = BIT_1; // Virtual Mode Extention
EAMD_DE = BIT_2; // Debugging Extention
EAMD_PSE = BIT_3; // Page Size Extention
EAMD_TSC = BIT_4; // Time Stamp Counter
EAMD_MSR = BIT_5; // Model Specific Registers
EAMD_PAE = BIT_6; // Physical-address extensions
EAMD_MCE = BIT_7; // Machine Check Exception
EAMD_CX8 = BIT_8; // CMPXCHG8 Instruction
EAMD_APIC = BIT_9; // Advanced Programmable Interrupt Controler
EAMD_BIT_10 = BIT_10; // Reserved, do not count on value
EAMD_SEP = BIT_11; // Fast System Call
EAMD_MTRR = BIT_12; // Memory-Type Range Registers
EAMD_PGE = BIT_13; // Page Global Enable
EAMD_MCA = BIT_14; // Machine Check Architecture
EAMD_CMOV = BIT_15; // Conditional Move Intructions
EAMD_PAT = BIT_16; // Page Attributes Table
EAMD_PSE2 = BIT_17; // Page Size Extensions
EAMD_BIT_18 = BIT_18; // Reserved, do not count on value
EAMD_BIT_19 = BIT_19; // Reserved, do not count on value
EAMD_NEPP = BIT_20; // No-Execute Page Protection
EAMD_BIT_21 = BIT_21; // Reserved, do not count on value
EAMD_EXMMX = BIT_22; // AMD Extensions to MMX technology
EAMD_MMX = BIT_23; // MMX technology
EAMD_FX = BIT_24; // FXSAVE and FXSTORE instructions
EAMD_FFX = BIT_25; // Fast FXSAVE and FXSTORE instructions
EAMD_BIT_26 = BIT_26; // Reserved, do not count on value
EAMD_BIT_27 = BIT_27; // Reserved, do not count on value
EAMD_BIT_28 = BIT_28; // Reserved, do not count on value
EAMD_LONG = BIT_29; // Long Mode (64-bit Core)
EAMD_EX3DNOW = BIT_30; // AMD Extensions to 3DNow! intructions
EAMD_3DNOW = BIT_31; // AMD 3DNOW! Technology
{ AMD Power Management Features Flags }
PAMD_TEMPSENSOR = $00000001; // Temperature Sensor
PAMD_FREQUENCYID = $00000002; // Frequency ID Control
PAMD_VOLTAGEID = $00000004; // Voltage ID Control
PAMD_THERMALTRIP = $00000008; // Thermal Trip
PAMD_THERMALMONITOR = $00000010; // Thermal Monitoring
PAMD_SOFTTHERMCONTROL = $00000020; // Software Thermal Control
{ AMD TLB and L1 Associativity constants }
AMD_ASSOC_RESERVED = 0;
AMD_ASSOC_DIRECT = 1;
// 2 to 254 = direct value to the associativity
AMD_ASSOC_FULLY = 255;
{ AMD L2 Cache Associativity constants }
AMD_L2_ASSOC_DISABLED = 0;
AMD_L2_ASSOC_DIRECT = 1;
AMD_L2_ASSOC_2WAY = 2;
AMD_L2_ASSOC_4WAY = 4;
AMD_L2_ASSOC_8WAY = 6;
AMD_L2_ASSOC_16WAY = 8;
AMD_L2_ASSOC_FULLY = 15;
{ VIA Standard Feature Flags }
VIA_FPU = BIT_0; // FPU present
VIA_VME = BIT_1; // Virtual Mode Extension
VIA_DE = BIT_2; // Debugging extensions
VIA_PSE = BIT_3; // Page Size Extensions (4MB)
VIA_TSC = BIT_4; // Time Stamp Counter
VIA_MSR = BIT_5; // Model Specific Registers
VIA_PAE = BIT_6; // Physical Address Extension
VIA_MCE = BIT_7; // Machine Check Exception
VIA_CX8 = BIT_8; // CMPXCHG8B instruction
VIA_APIC = BIT_9; // APIC supported
VIA_BIT_10 = BIT_10; // Reserved, do not count on value
VIA_SEP = BIT_11; // Fast System Call
VIA_MTRR = BIT_12; // Memory Range Registers
VIA_PTE = BIT_13; // PTE Global Bit
VIA_MCA = BIT_14; // Machine Check Architecture
VIA_CMOVE = BIT_15; // Conditional Move
VIA_PAT = BIT_16; // Page Attribute Table
VIA_PSE2 = BIT_17; // 36-bit Page Size Extension
VIA_SNUM = BIT_18; // Processor serial number
VIA_BIT_19 = BIT_19; // Reserved, do not count on value
VIA_BIT_20 = BIT_20; // Reserved, do not count on value
VIA_BIT_21 = BIT_21; // Reserved, do not count on value
VIA_BIT_22 = BIT_22; // Reserved, do not count on value
VIA_MMX = BIT_23; // MMX
VIA_FX = BIT_24; // FXSAVE and FXSTORE instructions
VIA_SSE = BIT_25; // Streaming SIMD Extension
VIA_BIT_26 = BIT_26; // Reserved, do not count on value
VIA_BIT_27 = BIT_27; // Reserved, do not count on value
VIA_BIT_28 = BIT_28; // Reserved, do not count on value
VIA_BIT_29 = BIT_29; // Reserved, do not count on value
VIA_BIT_30 = BIT_30; // Reserved, do not count on value
VIA_3DNOW = BIT_31; // 3DNow! Technology
{ VIA Extended Feature Flags }
EVIA_AIS = BIT_0; // Alternate Instruction Set
EVIA_AISE = BIT_1; // Alternate Instruction Set Enabled
EVIA_NO_RNG = BIT_2; // NO Random Number Generator
EVIA_RNGE = BIT_3; // Random Number Generator Enabled
EVIA_MSR = BIT_4; // Longhaul MSR 0x110A available
EVIA_FEMMS = BIT_5; // FEMMS instruction Present
EVIA_NO_ACE = BIT_6; // Advanced Cryptography Engine NOT Present
EVIA_ACEE = BIT_7; // ACE Enabled
EVIA_BIT_8 = BIT_8; // Reserved, do not count on value
EVIA_BIT_9 = BIT_9; // Reserved, do not count on value
EVIA_BIT_10 = BIT_10; // Reserved, do not count on value
EVIA_BIT_11 = BIT_11; // Reserved, do not count on value
EVIA_BIT_12 = BIT_12; // Reserved, do not count on value
EVIA_BIT_13 = BIT_13; // Reserved, do not count on value
EVIA_BIT_14 = BIT_14; // Reserved, do not count on value
EVIA_BIT_15 = BIT_15; // Reserved, do not count on value
EVIA_BIT_16 = BIT_16; // Reserved, do not count on value
EVIA_BIT_17 = BIT_17; // Reserved, do not count on value
EVIA_BIT_18 = BIT_18; // Reserved, do not count on value
EVIA_BIT_19 = BIT_19; // Reserved, do not count on value
EVIA_BIT_20 = BIT_20; // Reserved, do not count on value
EVIA_BIT_21 = BIT_21; // Reserved, do not count on value
EVIA_BIT_22 = BIT_22; // Reserved, do not count on value
EVIA_BIT_23 = BIT_23; // Reserved, do not count on value
EVIA_BIT_24 = BIT_24; // Reserved, do not count on value
EVIA_BIT_25 = BIT_25; // Reserved, do not count on value
EVIA_BIT_26 = BIT_26; // Reserved, do not count on value
EVIA_BIT_27 = BIT_27; // Reserved, do not count on value
EVIA_BIT_28 = BIT_28; // Reserved, do not count on value
EVIA_BIT_29 = BIT_29; // Reserved, do not count on value
EVIA_BIT_30 = BIT_30; // Reserved, do not count on value
EVIA_BIT_31 = BIT_31; // Reserved, do not count on value
{ Cyrix Standard Feature Flags }
CYRIX_FPU = BIT_0; // Floating-Point unit on chip
CYRIX_VME = BIT_1; // Virtual Mode Extention
CYRIX_DE = BIT_2; // Debugging Extention
CYRIX_PSE = BIT_3; // Page Size Extention
CYRIX_TSC = BIT_4; // Time Stamp Counter
CYRIX_MSR = BIT_5; // Model Specific Registers
CYRIX_PAE = BIT_6; // Physical Address Extention
CYRIX_MCE = BIT_7; // Machine Check Exception
CYRIX_CX8 = BIT_8; // CMPXCHG8 Instruction
CYRIX_APIC = BIT_9; // Software-accessible local APIC on Chip
CYRIX_BIT_10 = BIT_10; // Reserved, do not count on value
CYRIX_BIT_11 = BIT_11; // Reserved, do not count on value
CYRIX_MTRR = BIT_12; // Memory Type Range Registers
CYRIX_PGE = BIT_13; // Page Global Enable
CYRIX_MCA = BIT_14; // Machine Check Architecture
CYRIX_CMOV = BIT_15; // Conditional Move Instruction
CYRIX_BIT_16 = BIT_16; // Reserved, do not count on value
CYRIX_BIT_17 = BIT_17; // Reserved, do not count on value
CYRIX_BIT_18 = BIT_18; // Reserved, do not count on value
CYRIX_BIT_19 = BIT_19; // Reserved, do not count on value
CYRIX_BIT_20 = BIT_20; // Reserved, do not count on value
CYRIX_BIT_21 = BIT_21; // Reserved, do not count on value
CYRIX_BIT_22 = BIT_22; // Reserved, do not count on value
CYRIX_MMX = BIT_23; // MMX technology
CYRIX_BIT_24 = BIT_24; // Reserved, do not count on value
CYRIX_BIT_25 = BIT_25; // Reserved, do not count on value
CYRIX_BIT_26 = BIT_26; // Reserved, do not count on value
CYRIX_BIT_27 = BIT_27; // Reserved, do not count on value
CYRIX_BIT_28 = BIT_28; // Reserved, do not count on value
CYRIX_BIT_29 = BIT_29; // Reserved, do not count on value
CYRIX_BIT_30 = BIT_30; // Reserved, do not count on value
CYRIX_BIT_31 = BIT_31; // Reserved, do not count on value
{ Cyrix Enhanced Feature Flags }
ECYRIX_FPU = BIT_0; // Floating-Point unit on chip
ECYRIX_VME = BIT_1; // Virtual Mode Extention
ECYRIX_DE = BIT_2; // Debugging Extention
ECYRIX_PSE = BIT_3; // Page Size Extention
ECYRIX_TSC = BIT_4; // Time Stamp Counter
ECYRIX_MSR = BIT_5; // Model Specific Registers
ECYRIX_PAE = BIT_6; // Physical Address Extention
ECYRIX_MCE = BIT_7; // Machine Check Exception
ECYRIX_CX8 = BIT_8; // CMPXCHG8 Instruction
ECYRIX_APIC = BIT_9; // Software-accessible local APIC on Chip
ECYRIX_SEP = BIT_10; // Fast System Call
ECYRIX_BIT_11 = BIT_11; // Reserved, do not count on value
ECYRIX_MTRR = BIT_12; // Memory Type Range Registers
ECYRIX_PGE = BIT_13; // Page Global Enable
ECYRIX_MCA = BIT_14; // Machine Check Architecture
ECYRIX_ICMOV = BIT_15; // Integer Conditional Move Instruction
ECYRIX_FCMOV = BIT_16; // Floating Point Conditional Move Instruction
ECYRIX_BIT_17 = BIT_17; // Reserved, do not count on value
ECYRIX_BIT_18 = BIT_18; // Reserved, do not count on value
ECYRIX_BIT_19 = BIT_19; // Reserved, do not count on value
ECYRIX_BIT_20 = BIT_20; // Reserved, do not count on value
ECYRIX_BIT_21 = BIT_21; // Reserved, do not count on value
ECYRIX_BIT_22 = BIT_22; // Reserved, do not count on value
ECYRIX_MMX = BIT_23; // MMX technology
ECYRIX_EMMX = BIT_24; // Extended MMX Technology
ECYRIX_BIT_25 = BIT_25; // Reserved, do not count on value
ECYRIX_BIT_26 = BIT_26; // Reserved, do not count on value
ECYRIX_BIT_27 = BIT_27; // Reserved, do not count on value
ECYRIX_BIT_28 = BIT_28; // Reserved, do not count on value
ECYRIX_BIT_29 = BIT_29; // Reserved, do not count on value
ECYRIX_BIT_30 = BIT_30; // Reserved, do not count on value
ECYRIX_BIT_31 = BIT_31; // Reserved, do not count on value
{ Transmeta Features }
TRANSMETA_FPU = BIT_0; // Floating-Point unit on chip
TRANSMETA_VME = BIT_1; // Virtual Mode Extention
TRANSMETA_DE = BIT_2; // Debugging Extention
TRANSMETA_PSE = BIT_3; // Page Size Extention
TRANSMETA_TSC = BIT_4; // Time Stamp Counter
TRANSMETA_MSR = BIT_5; // Model Specific Registers
TRANSMETA_BIT_6 = BIT_6; // Reserved, do not count on value
TRANSMETA_BIT_7 = BIT_7; // Reserved, do not count on value
TRANSMETA_CX8 = BIT_8; // CMPXCHG8 Instruction
TRANSMETA_BIT_9 = BIT_9; // Reserved, do not count on value
TRANSMETA_BIT_10 = BIT_10; // Reserved, do not count on value
TRANSMETA_SEP = BIT_11; // Fast system Call Extensions
TRANSMETA_BIT_12 = BIT_12; // Reserved, do not count on value
TRANSMETA_BIT_13 = BIT_13; // Reserved, do not count on value
TRANSMETA_BIT_14 = BIT_14; // Reserved, do not count on value
TRANSMETA_CMOV = BIT_15; // Conditional Move Instruction
TRANSMETA_BIT_16 = BIT_16; // Reserved, do not count on value
TRANSMETA_BIT_17 = BIT_17; // Reserved, do not count on value
TRANSMETA_PSN = BIT_18; // Processor Serial Number
TRANSMETA_BIT_19 = BIT_19; // Reserved, do not count on value
TRANSMETA_BIT_20 = BIT_20; // Reserved, do not count on value
TRANSMETA_BIT_21 = BIT_21; // Reserved, do not count on value
TRANSMETA_BIT_22 = BIT_22; // Reserved, do not count on value
TRANSMETA_MMX = BIT_23; // MMX technology
TRANSMETA_BIT_24 = BIT_24; // Reserved, do not count on value
TRANSMETA_BIT_25 = BIT_25; // Reserved, do not count on value
TRANSMETA_BIT_26 = BIT_26; // Reserved, do not count on value
TRANSMETA_BIT_27 = BIT_27; // Reserved, do not count on value
TRANSMETA_BIT_28 = BIT_28; // Reserved, do not count on value
TRANSMETA_BIT_29 = BIT_29; // Reserved, do not count on value
TRANSMETA_BIT_30 = BIT_30; // Reserved, do not count on value
TRANSMETA_BIT_31 = BIT_31; // Reserved, do not count on value
{ Extended Transmeta Features }
ETRANSMETA_FPU = BIT_0; // Floating-Point unit on chip
ETRANSMETA_VME = BIT_1; // Virtual Mode Extention
ETRANSMETA_DE = BIT_2; // Debugging Extention
ETRANSMETA_PSE = BIT_3; // Page Size Extention
ETRANSMETA_TSC = BIT_4; // Time Stamp Counter
ETRANSMETA_MSR = BIT_5; // Model Specific Registers
ETRANSMETA_BIT_6 = BIT_6; // Reserved, do not count on value
ETRANSMETA_BIT_7 = BIT_7; // Reserved, do not count on value
ETRANSMETA_CX8 = BIT_8; // CMPXCHG8 Instruction
ETRANSMETA_BIT_9 = BIT_9; // Reserved, do not count on value
ETRANSMETA_BIT_10 = BIT_10; // Reserved, do not count on value
ETRANSMETA_BIT_11 = BIT_11; // Reserved, do not count on value
ETRANSMETA_BIT_12 = BIT_12; // Reserved, do not count on value
ETRANSMETA_BIT_13 = BIT_13; // Reserved, do not count on value
ETRANSMETA_BIT_14 = BIT_14; // Reserved, do not count on value
ETRANSMETA_CMOV = BIT_15; // Conditional Move Instruction
ETRANSMETA_FCMOV = BIT_16; // Float Conditional Move Instruction
ETRANSMETA_BIT_17 = BIT_17; // Reserved, do not count on value
ETRANSMETA_BIT_18 = BIT_18; // Reserved, do not count on value
ETRANSMETA_BIT_19 = BIT_19; // Reserved, do not count on value
ETRANSMETA_BIT_20 = BIT_20; // Reserved, do not count on value
ETRANSMETA_BIT_21 = BIT_21; // Reserved, do not count on value
ETRANSMETA_BIT_22 = BIT_22; // Reserved, do not count on value
ETRANSMETA_MMX = BIT_23; // MMX technology
ETRANSMETA_BIT_24 = BIT_24; // Reserved, do not count on value
ETRANSMETA_BIT_25 = BIT_25; // Reserved, do not count on value
ETRANSMETA_BIT_26 = BIT_26; // Reserved, do not count on value
ETRANSMETA_BIT_27 = BIT_27; // Reserved, do not count on value
ETRANSMETA_BIT_28 = BIT_28; // Reserved, do not count on value
ETRANSMETA_BIT_29 = BIT_29; // Reserved, do not count on value
ETRANSMETA_BIT_30 = BIT_30; // Reserved, do not count on value
ETRANSMETA_BIT_31 = BIT_31; // Reserved, do not count on value
{ Transmeta Specific Features }
STRANSMETA_RECOVERY = BIT_0; // Recovery Mode
STRANSMETA_LONGRUN = BIT_1; // Long Run
STRANSMETA_BIT_2 = BIT_2; // Debugging Extention
STRANSMETA_LRTI = BIT_3; // Long Run Table Interface
STRANSMETA_BIT_4 = BIT_4; // Reserved, do not count on value
STRANSMETA_BIT_5 = BIT_5; // Reserved, do not count on value
STRANSMETA_BIT_6 = BIT_6; // Reserved, do not count on value
STRANSMETA_PTTI1 = BIT_7; // Persistent Translation Technology 1.x
STRANSMETA_PTTI2 = BIT_8; // Persistent Translation Technology 2.0
STRANSMETA_BIT_9 = BIT_9; // Reserved, do not count on value
STRANSMETA_BIT_10 = BIT_10; // Reserved, do not count on value
STRANSMETA_BIT_11 = BIT_11; // Reserved, do not count on value
STRANSMETA_BIT_12 = BIT_12; // Reserved, do not count on value
STRANSMETA_BIT_13 = BIT_13; // Reserved, do not count on value
STRANSMETA_BIT_14 = BIT_14; // Reserved, do not count on value
STRANSMETA_BIT_15 = BIT_15; // Reserved, do not count on value
STRANSMETA_BIT_16 = BIT_16; // Reserved, do not count on value
STRANSMETA_BIT_17 = BIT_17; // Reserved, do not count on value
STRANSMETA_BIT_18 = BIT_18; // Reserved, do not count on value
STRANSMETA_BIT_19 = BIT_19; // Reserved, do not count on value
STRANSMETA_BIT_20 = BIT_20; // Reserved, do not count on value
STRANSMETA_BIT_21 = BIT_21; // Reserved, do not count on value
STRANSMETA_BIT_22 = BIT_22; // Reserved, do not count on value
STRANSMETA_BIT_23 = BIT_23; // Reserved, do not count on value
STRANSMETA_BIT_24 = BIT_24; // Reserved, do not count on value
STRANSMETA_BIT_25 = BIT_25; // Reserved, do not count on value
STRANSMETA_BIT_26 = BIT_26; // Reserved, do not count on value
STRANSMETA_BIT_27 = BIT_27; // Reserved, do not count on value
STRANSMETA_BIT_28 = BIT_28; // Reserved, do not count on value
STRANSMETA_BIT_29 = BIT_29; // Reserved, do not count on value
STRANSMETA_BIT_30 = BIT_30; // Reserved, do not count on value
STRANSMETA_BIT_31 = BIT_31; // Reserved, do not count on value
{ Constants of bits of the MXCSR register - Intel and AMD processors that support SSE instructions}
MXCSR_IE = BIT_0; // Invalid Operation flag
MXCSR_DE = BIT_1; // Denormal flag
MXCSR_ZE = BIT_2; // Divide by Zero flag
MXCSR_OE = BIT_3; // Overflow flag
MXCSR_UE = BIT_4; // Underflow flag
MXCSR_PE = BIT_5; // Precision flag
MXCSR_DAZ = BIT_6; // Denormal are Zero flag
MXCSR_IM = BIT_7; // Invalid Operation mask
MXCSR_DM = BIT_8; // Denormal mask
MXCSR_ZM = BIT_9; // Divide by Zero mask
MXCSR_OM = BIT_10; // Overflow mask
MXCSR_UM = BIT_11; // Underflow mask
MXCSR_PM = BIT_12; // Precision mask
MXCSR_RC1 = BIT_13; // Rounding control, bit 1
MXCSR_RC2 = BIT_14; // Rounding control, bit 2
MXCSR_RC = MXCSR_RC1 or MXCSR_RC2; // Rounding control
MXCSR_FZ = BIT_15; // Flush to Zero
const
IntelCacheDescription: array [0..50] of TCacheInfo = (
(D: $00; Family: cfOther; I: RsIntelCacheDescr00),
(D: $01; Family: cfInstructionTLB; Size: 4; WaysOfAssoc: 4; Entries: 32; I: RsIntelCacheDescr01), // Instruction TLB: 4 KByte Pages, 4-way set associative, 32 entries
(D: $02; Family: cfInstructionTLB; Size: 4096; WaysOfAssoc: 4; Entries: 2; I: RsIntelCacheDescr02), // Instruction TLB: 4 MByte Pages, 4-way set associative, 2 entries
(D: $03; Family: cfDataTLB; Size: 4; WaysOfAssoc: 4; Entries: 64; I: RsIntelCacheDescr03), // Data TLB: 4KByte Pages, 4-way set associative, 64 entries
(D: $04; Family: cfDataTLB; Size: 4096; WaysOfAssoc: 4; Entries: 8; I: RsIntelCacheDescr04), // Data TLB: 4MByte Pages, 4-way set associative, 8 entries
(D: $06; Family: cfL1InstructionCache; Size: 8; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr06), // 1st-level instruction cache: 8 KBytes, 4-way set associative, 32 byte line size
(D: $08; Family: cfL1InstructionCache; Size: 16; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr08), // 1st-level instruction cache: 16 KBytes, 4-way set associative, 32 byte line size
(D: $0A; Family: cfL1DataCache; Size: 8; WaysOfAssoc: 2; LineSize: 32; I: RsIntelCacheDescr0A), // 1st-level data cache: 8 KBytes, 2-way set associative, 32 byte line size
(D: $0C; Family: cfL1DataCache; Size: 16; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr0C), // 1st-level data cache: 16 KBytes, 4-way set associative, 32 byte line size
(D: $22; Family: cfL3Cache; Size: 512; WaysOfAssoc: 4; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr22), // 3rd-level cache: 512 KBytes, 4-way set associative, 64 byte line size, 2 lines per sector
(D: $23; Family: cfL3Cache; Size: 1024; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr23), // 3rd-level cache: 1 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector
(D: $25; Family: cfL3Cache; Size: 2048; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr25), // 3rd-level cache: 2 MBytes, 8-way set associative, 64 byte line size, 2 lines per sector
(D: $29; Family: cfL3Cache; Size: 4096; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr29), // 3rd-level cache: 4M Bytes, 8-way set associative, 64 byte line size, 2 lines per sector
(D: $2C; Family: cfL1DataCache; Size: 32; WaysOfAssoc: 8; LineSize: 64; I: RsIntelCacheDescr2C), // 1st-level data cache: 32K Bytes, 8-way set associative, 64 byte line size
(D: $30; Family: cfL1InstructionCache; Size: 32; WaysOfAssoc: 8; LineSize: 64; I: RsIntelCacheDescr30), // 1st-level instruction cache: 32K Bytes, 8-way set associative, 64 byte line size
(D: $40; Family: cfOther; I: RsIntelCacheDescr40), // No 2nd-level cache or, if processor contains a valid 2nd-level cache, no 3rd-level cache
(D: $41; Family: cfL2Cache; Size: 128; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr41), // 2nd-level cache: 128 KBytes, 4-way set associative, 32 byte line size
(D: $42; Family: cfL2Cache; Size: 256; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr42), // 2nd-level cache: 256 KBytes, 4-way set associative, 32 byte line size
(D: $43; Family: cfL2Cache; Size: 512; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr43), // 2nd-level cache: 512 KBytes, 4-way set associative, 32 byte line size
(D: $44; Family: cfL2Cache; Size: 1024; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr44), // 2nd-level cache: 1 MByte, 4-way set associative, 32 byte line size
(D: $45; Family: cfL2Cache; Size: 2048; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr45), // 2nd-level cache: 2 MByte, 4-way set associative, 32 byte line size
(D: $50; Family: cfInstructionTLB; Size: 4096; Entries: 64; I: RsIntelCacheDescr50), // Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 64 entries
(D: $51; Family: cfInstructionTLB; Size: 4096; Entries: 128; I: RsIntelCacheDescr51), // Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 128 entries
(D: $52; Family: cfInstructionTLB; Size: 4096; Entries: 256; I: RsIntelCacheDescr52), // Instruction TLB: 4 KByte and 2-MByte or 4-MByte pages, 256 entries
(D: $5B; Family: cfDataTLB; Size: 4096; Entries: 64; I: RsIntelCacheDescr5B), // Data TLB: 4 KByte and 4 MByte pages, 64 entries
(D: $5C; Family: cfDataTLB; Size: 4096; Entries: 128; I: RsIntelCacheDescr5C), // Data TLB: 4 KByte and 4 MByte pages,128 entries
(D: $5D; Family: cfDataTLB; Size: 4096; Entries: 256; I: RsIntelCacheDescr5D), // Data TLB: 4 KByte and 4 MByte pages,256 entries
(D: $60; Family: cfL1DataCache; Size: 16; WaysOfAssoc: 8; LineSize: 64; I: RsIntelCacheDescr60), // 1st-level data cache: 16 KByte, 8-way set associative, 64 byte line size
(D: $66; Family: cfL1DataCache; Size: 8; WaysOfAssoc: 4; LineSize: 64; I: RsIntelCacheDescr66), // 1st-level data cache: 8 KByte, 4-way set associative, 64 byte line size
(D: $67; Family: cfL1DataCache; Size: 16; WaysOfAssoc: 4; LineSize: 64; I: RsIntelCacheDescr67), // 1st-level data cache: 16 KByte, 4-way set associative, 64 byte line size
(D: $68; Family: cfL1DataCache; Size: 32; WaysOfAssoc: 4; LineSize: 64; I: RsIntelCacheDescr68), // 1st-level data cache: 32 KByte, 4-way set associative, 64 byte line size
(D: $70; Family: cfTrace; Size: 12; WaysOfAssoc: 8; I: RsIntelCacheDescr70), // Trace cache: 12 K-µop, 8-way set associative
(D: $71; Family: cfTrace; Size: 16; WaysOfAssoc: 8; I: RsIntelCacheDescr71), // Trace cache: 16 K-µop, 8-way set associative
(D: $72; Family: cfTrace; Size: 32; WaysOfAssoc: 8; I: RsIntelCacheDescr72), // Trace cache: 32 K-µop, 8-way set associative
(D: $78; Family: cfL2Cache; Size: 1024; WaysOfAssoc: 4; LineSize: 64; I: RsIntelCacheDescr78), // 2nd-level cache: 1 MByte, 4-way set associative, 64byte line size
(D: $79; Family: cfL2Cache; Size: 128; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr79), // 2nd-level cache: 128 KByte, 8-way set associative, 64 byte line size, 2 lines per sector
(D: $7A; Family: cfL2Cache; Size: 256; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr7A), // 2nd-level cache: 256 KByte, 8-way set associative, 64 byte line size, 2 lines per sector
(D: $7B; Family: cfL2Cache; Size: 512; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr7B), // 2nd-level cache: 512 KByte, 8-way set associative, 64 byte line size, 2 lines per sector
(D: $7C; Family: cfL2Cache; Size: 1024; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr7C), // 2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size, 2 lines per sector
(D: $7D; Family: cfL2Cache; Size: 2048; WaysOfAssoc: 8; LineSize: 64; I: RsIntelCacheDescr7D), // 2nd-level cache: 2 MByte, 8-way set associative, 64byte line size
(D: $7F; Family: cfL2Cache; Size: 512; WaysOfAssoc: 2; LineSize: 64; I: RsIntelCacheDescr7F), // 2nd-level cache: 512 KByte, 2-way set associative, 64-byte line size
(D: $82; Family: cfL2Cache; Size: 256; WaysOfAssoc: 8; LineSize: 32; I: RsIntelCacheDescr82), // 2nd-level cache: 256 KByte, 8-way set associative, 32 byte line size
(D: $83; Family: cfL2Cache; Size: 512; WaysOfAssoc: 8; LineSize: 32; I: RsIntelCacheDescr83), // 2nd-level cache: 512 KByte, 8-way set associative, 32 byte line size
(D: $84; Family: cfL2Cache; Size: 1024; WaysOfAssoc: 8; LineSize: 32; I: RsIntelCacheDescr84), // 2nd-level cache: 1 MByte, 8-way set associative, 32 byte line size
(D: $85; Family: cfL2Cache; Size: 2048; WaysOfAssoc: 8; LineSize: 32; I: RsIntelCacheDescr85), // 2nd-level cache: 2 MByte, 8-way set associative, 32 byte line size
(D: $86; Family: cfL2Cache; Size: 512; WaysOfAssoc: 4; LineSize: 64; I: RsIntelCacheDescr86), // 2nd-level cache: 512 KByte, 4-way set associative, 64 byte line size
(D: $87; Family: cfL2Cache; Size: 1024; WaysOfAssoc: 8; LineSize: 64; I: RsIntelCacheDescr87), // 2nd-level cache: 1 MByte, 8-way set associative, 64 byte line size
(D: $B0; Family: cfInstructionTLB; Size: 4; WaysOfAssoc: 4; Entries: 128; I: RsIntelCacheDescrB0), // Instruction TLB: 4 KByte Pages, 4-way set associative, 128 entries
(D: $B3; Family: cfDataTLB; Size: 4; WaysOfAssoc: 4; Entries: 128; I: RsIntelCacheDescrB3), // Data TLB: 4 KByte Pages, 4-way set associative, 128 entries
(D: $F0; Family: cfOther; I: RsIntelCacheDescrF0), // 64-Byte Prefetching
(D: $F1; Family: cfOther; I: RsIntelCacheDescrF1) // 128-Byte Prefetching
);
procedure GetCpuInfo(var CpuInfo: TCpuInfo);
function GetIntelCacheDescription(const D: Byte): string;
function RoundFrequency(const Frequency: Integer): Integer;
{$IFDEF MSWINDOWS}
function GetCPUSpeed(var CpuSpeed: TFreqInfo): Boolean;
{$ENDIF MSWINDOWS}
function CPUID: TCpuInfo;
function TestFDIVInstruction: Boolean;
// Memory Information
{$IFDEF MSWINDOWS}
function GetMaxAppAddress: Cardinal;
function GetMinAppAddress: Cardinal;
{$ENDIF MSWINDOWS}
function GetMemoryLoad: Byte;
function GetSwapFileSize: Cardinal;
function GetSwapFileUsage: Byte;
function GetTotalPhysicalMemory: Cardinal;
function GetFreePhysicalMemory: Cardinal;
{$IFDEF MSWINDOWS}
function GetTotalPageFileMemory: Cardinal;
function GetFreePageFileMemory: Cardinal;
function GetTotalVirtualMemory: Cardinal;
function GetFreeVirtualMemory: Cardinal;
{$ENDIF MSWINDOWS}
// Alloc granularity
procedure RoundToAllocGranularity64(var Value: Int64; Up: Boolean);
procedure RoundToAllocGranularityPtr(var Value: Pointer; Up: Boolean);
{$IFDEF MSWINDOWS}
// Keyboard Information
function GetKeyState(const VirtualKey: Cardinal): Boolean;
function GetNumLockKeyState: Boolean;
function GetScrollLockKeyState: Boolean;
function GetCapsLockKeyState: Boolean;
// Windows 95/98/Me system resources information
type
TFreeSysResKind = (rtSystem, rtGdi, rtUser);
TFreeSystemResources = record
SystemRes: Integer;
GdiRes: Integer;
UserRes: Integer;
end;
function IsSystemResourcesMeterPresent: Boolean;
function GetFreeSystemResources(const ResourceType: TFreeSysResKind): Integer; overload;
function GetFreeSystemResources: TFreeSystemResources; overload;
{$ENDIF MSWINDOWS}
// Public global variables
var
ProcessorCount: Cardinal = 0;
AllocGranularity: Cardinal = 0;
PageSize: Cardinal = 0;
{$ENDIF ~CLR}
implementation
uses
SysUtils,
{$IFNDEF CLR}
{$IFDEF MSWINDOWS}
Messages, Winsock, Snmp,
{$IFDEF FPC}
ActiveX, JwaTlHelp32, JwaPsApi,
{$ELSE ~FPC}
TLHelp32, PsApi,
JclShell,
{$ENDIF ~FPC}
JclRegistry, JclWin32,
{$ENDIF MSWINDOWS}
Jcl8087, JclIniFiles,
{$ENDIF ~CLR}
JclBase, JclFileUtils, JclStrings;
{$IFDEF FPC}
{$I JclSysInfo.fpc}
{$ENDIF FPC}
//=== Environment ============================================================
function DelEnvironmentVar(const Name: string): Boolean;
begin
{$IFDEF CLR}
System.Environment.GetEnvironmentVariables.Remove(Name);
Result := True;
{$ELSE ~CLR}
{$IFDEF UNIX}
UnSetEnv(PChar(Name));
Result := True;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
Result := SetEnvironmentVariable(PChar(Name), nil);
{$ENDIF MSWINDOWS}
{$ENDIF ~CLR}
end;
function ExpandEnvironmentVar(var Value: string): Boolean;
{$IFDEF CLR}
begin
Value := System.Environment.ExpandEnvironmentVariables(Value);
Result := True;
end;
{$ELSE ~CLR}
{$IFDEF UNIX}
begin
Result := True;
end;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
var
R: Integer;
Expanded: string;
begin
SetLength(Expanded, 1);
R := ExpandEnvironmentStrings(PChar(Value), PChar(Expanded), 0);
SetLength(Expanded, R);
Result := ExpandEnvironmentStrings(PChar(Value), PChar(Expanded), R) <> 0;
if Result then
begin
StrResetLength(Expanded);
Value := Expanded;
end;
end;
{$ENDIF MSWINDOWS}
{$ENDIF ~CLR}
{$IFDEF UNIX}
function GetEnvironmentVar(const Name: string; var Value: string): Boolean;
begin
Value := getenv(PChar(Name));
Result := Value <> '';
end;
function GetEnvironmentVar(const Name: string; var Value: string; Expand: Boolean): Boolean;
begin
Result := GetEnvironmentVar(Name, Value); // Expand is there just for x-platform compatibility
end;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
function GetEnvironmentVar(const Name: string; var Value: string): Boolean;
begin
{$IFDEF CLR}
Value := System.Environment.GetEnvironmentVariable(Name);
Result := TObject(Value) <> nil;
{$ELSE ~CLR}
Result := GetEnvironmentVar(Name, Value, True);
{$ENDIF ~CLR}
end;
function GetEnvironmentVar(const Name: string; var Value: string; Expand: Boolean): Boolean;
{$IFDEF CLR}
begin
Result := GetEnvironmentVar(Name, Value);
if Expand then
ExpandEnvironmentVar(Value);
end;
{$ELSE ~CLR}
var
R: DWORD;
begin
R := Windows.GetEnvironmentVariable(PChar(Name), nil, 0);
SetLength(Value, R);
R := Windows.GetEnvironmentVariable(PChar(Name), PChar(Value), R);
Result := R <> 0;
if not Result then
Value := ''
else
begin
SetLength(Value, R);
if Expand then
ExpandEnvironmentVar(Value);
end;
end;
{$ENDIF ~CLR}
{$ENDIF MSWINDOWS}
{$IFDEF KYLIX}
function GetEnvironmentVars(const Vars: TStrings): Boolean;
var
P: PPChar;
begin
Vars.BeginUpdate;
try
Vars.Clear;
P := System.envp;
Result := P <> nil;
while (P <> nil) and (P^ <> nil) do
begin
Vars.Add(P^);
Inc(P);
end;
finally
Vars.EndUpdate;
end;
end;
{$ENDIF KYLIX}
{$IFDEF UNIX}
function GetEnvironmentVars(const Vars: TStrings; Expand: Boolean): Boolean;
begin
Result := GetEnvironmentVars(Vars); // Expand is there just for x-platform compatibility
end;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
function GetEnvironmentVars(const Vars: TStrings): Boolean;
begin
Result := GetEnvironmentVars(Vars, True);
end;
function GetEnvironmentVars(const Vars: TStrings; Expand: Boolean): Boolean;
{$IFDEF CLR}
var
Dic: IDictionaryEnumerator;
begin
Vars.BeginUpdate;
try
Vars.Clear;
for Dic in System.Environment.GetEnvironmentVariables do
Vars.Add(string(Dic.Key) + '=' + string(Dic.Value));
finally
Vars.EndUpdate;
end;
Result := True;
end;
{$ELSE ~CLR}
var
Raw: PChar;
Expanded: string;
I: Integer;
begin
Vars.BeginUpdate;
try
Vars.Clear;
Raw := GetEnvironmentStrings;
try
MultiSzToStrings(Vars, Raw);
Result := True;
finally
FreeEnvironmentStrings(Raw);
end;
if Expand then
begin
for I := 0 to Vars.Count - 1 do
begin
Expanded := Vars[I];
if ExpandEnvironmentVar(Expanded) then
Vars[I] := Expanded;
end;
end;
finally
Vars.EndUpdate;
end;
end;
{$ENDIF ~CLR}
{$ENDIF MSWINDOWS}
function SetEnvironmentVar(const Name, Value: string): Boolean;
begin
{$IFDEF CLR}
if System.Environment.GetEnvironmentVariables.Contains(Name) then
System.Environment.GetEnvironmentVariables.Item[Name] := Value
else
System.Environment.GetEnvironmentVariables.Add(Name, Value);
Result := True;
{$ELSE ~CLR}
{$IFDEF UNIX}
SetEnv(PChar(Name), PChar(Value), 1);
Result := True;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
Result := SetEnvironmentVariable(PChar(Name), PChar(Value));
{$ENDIF MSWINDOWS}
{$ENDIF ~CLR}
end;
{$IFNDEF CLR}
{$IFDEF MSWINDOWS}
function CreateEnvironmentBlock(const Options: TEnvironmentOptions; const AdditionalVars: TStrings): PChar;
const
RegLocalEnvironment = 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment';
RegUserEnvironment = '\Environment\';
var
KeyNames, TempList: TStrings;
Temp, Name, Value: string;
I: Integer;
begin
TempList := TStringList.Create;
try
// add additional environment variables
if eoAdditional in Options then
for I := 0 to AdditionalVars.Count - 1 do
begin
Temp := AdditionalVars[I];
ExpandEnvironmentVar(Temp);
TempList.Add(Temp);
end;
// get environment strings from local machine
if eoLocalMachine in Options then
begin
KeyNames := TStringList.Create;
try
if RegGetValueNames(HKEY_LOCAL_MACHINE, RegLocalEnvironment, KeyNames) then
begin
for I := 0 to KeyNames.Count - 1 do
begin
Name := KeyNames[I];
Value := RegReadString(HKEY_LOCAL_MACHINE, RegLocalEnvironment, Name);
ExpandEnvironmentVar(Value);
TempList.Add(Name + '=' + Value);
end;
end;
finally
FreeAndNil(KeyNames);
end;
end;
// get environment strings from current user
if eoCurrentUser in Options then
begin
KeyNames := TStringLIst.Create;
try
if RegGetValueNames(HKEY_CURRENT_USER, RegUserEnvironment, KeyNames) then
begin
for I := 0 to KeyNames.Count - 1 do
begin
Name := KeyNames[I];
Value := RegReadString(HKEY_CURRENT_USER, RegUserEnvironment, Name);
ExpandEnvironmentVar(Value);
TempList.Add(Name + '=' + Value);
end;
end;
finally
KeyNames.Free;
end;
end;
// transform stringlist into multi-PChar
StringsToMultiSz(Result, TempList);
finally
FreeAndNil(TempList);
end;
end;
// frees an environment block allocated by CreateEnvironmentBlock and
// sets Env to nil
procedure DestroyEnvironmentBlock(var Env: PChar);
begin
FreeMultiSz(Env);
end;
procedure SetGlobalEnvironmentVariable(VariableName, VariableContent: string);
const
cEnvironment = 'Environment';
begin
if VariableName = '' then
Exit;
if VariableContent = '' then
begin
RegDeleteEntry(HKEY_CURRENT_USER, cEnvironment, VariableName);
SetEnvironmentVariable(PChar(VariableName), nil);
end
else
begin
RegWriteAnsiString(HKEY_CURRENT_USER, cEnvironment, VariableName, VariableContent);
SetEnvironmentVariable(PChar(VariableName), PChar(VariableContent));
end;
SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, LPARAM(PChar(cEnvironment)));
end;
//=== Common Folders =========================================================
// Utility function which returns the Windows independent CurrentVersion key
// inside HKEY_LOCAL_MACHINE
const
HKLM_CURRENT_VERSION_WINDOWS = 'SOFTWARE\Microsoft\Windows\CurrentVersion';
HKLM_CURRENT_VERSION_NT = 'SOFTWARE\Microsoft\Windows NT\CurrentVersion';
function REG_CURRENT_VERSION: string;
begin
if IsWinNT then
Result := HKLM_CURRENT_VERSION_NT
else
Result := HKLM_CURRENT_VERSION_WINDOWS;
end;
{ TODO : Check for documented solution }
function GetCommonFilesFolder: string;
begin
Result := RegReadStringDef(HKEY_LOCAL_MACHINE, HKLM_CURRENT_VERSION_WINDOWS,
'CommonFilesDir', '');
end;
{$ENDIF MSWINDOWS}
{$ENDIF ~CLR}
function GetCurrentFolder: string;
{$IFDEF CLR}
begin
Result := System.Environment.CurrentDirectory;
end;
{$ELSE ~CLR}
{$IFDEF UNIX}
const
InitialSize = 64;
var
Size: Integer;
begin
Size := InitialSize;
while True do
begin
SetLength(Result, Size);
if getcwd(PChar(Result), Size) <> nil then
begin
StrResetLength(Result);
Exit;
end;
if GetLastError <> ERANGE then
RaiseLastOSError;
Size := Size * 2;
end;
end;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
var
Required: Cardinal;
begin
Result := '';
Required := GetCurrentDirectory(0, nil);
if Required <> 0 then
begin
SetLength(Result, Required);
GetCurrentDirectory(Required, PChar(Result));
StrResetLength(Result);
end;
end;
{$ENDIF MSWINDOWS}
{$ENDIF ~CLR}
{$IFDEF MSWINDOWS}
{ TODO : Check for documented solution }
function GetProgramFilesFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
{$ELSE ~CLR}
Result := RegReadStringDef(HKEY_LOCAL_MACHINE, HKLM_CURRENT_VERSION_WINDOWS, 'ProgramFilesDir', '');
{$ENDIF ~CLR}
end;
{$IFNDEF CLR}
{ TODO : Check for documented solution }
function GetWindowsFolder: string;
var
Required: Cardinal;
begin
Result := '';
Required := GetWindowsDirectory(nil, 0);
if Required <> 0 then
begin
SetLength(Result, Required);
GetWindowsDirectory(PChar(Result), Required);
StrResetLength(Result);
end;
end;
{$ENDIF ~CLR}
{ TODO : Check for documented solution }
function GetWindowsSystemFolder: string;
{$IFDEF CLR}
begin
Result := System.Environment.SystemDirectory;
end;
{$ELSE ~CLR}
var
Required: Cardinal;
begin
Result := '';
Required := GetSystemDirectory(nil, 0);
if Required <> 0 then
begin
SetLength(Result, Required);
GetSystemDirectory(PChar(Result), Required);
StrResetLength(Result);
end;
end;
{$ENDIF ~CLR}
function GetWindowsTempFolder: string;
{$IFDEF CLR}
begin
Result := Path.GetTempPath;
end;
{$ELSE ~CLR}
var
Required: Cardinal;
begin
Result := '';
Required := GetTempPath(0, nil);
if Required <> 0 then
begin
SetLength(Result, Required);
GetTempPath(Required, PChar(Result));
StrResetLength(Result);
Result := PathRemoveSeparator(Result);
end;
end;
{$ENDIF ~CLR}
function GetDesktopFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_DESKTOP);
{$ENDIF ~CLR}
end;
{ TODO : Check GetProgramsFolder = GetProgramFilesFolder }
function GetProgramsFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.Programs);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_PROGRAMS);
{$ENDIF ~CLR}
end;
{$ENDIF MSWINDOWS}
function GetPersonalFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.Personal);
{$ELSE ~CLR}
{$IFDEF UNIX}
Result := GetEnvironmentVariable('HOME');
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
Result := GetSpecialFolderLocation(CSIDL_PERSONAL);
{$ENDIF MSWINDOWS}
{$ENDIF ~CLR}
end;
{$IFDEF MSWINDOWS}
function GetFavoritesFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.Favorites);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_FAVORITES);
{$ENDIF ~CLR}
end;
function GetStartupFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.Startup);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_STARTUP);
{$ENDIF ~CLR}
end;
function GetRecentFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.Recent);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_RECENT);
{$ENDIF ~CLR}
end;
function GetSendToFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.SendTo);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_SENDTO);
{$ENDIF ~CLR}
end;
function GetStartmenuFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.StartMenu);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_STARTMENU);
{$ENDIF ~CLR}
end;
function GetDesktopDirectoryFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_DESKTOPDIRECTORY);
{$ENDIF ~CLR}
end;
{$IFNDEF CLR}
function GetNethoodFolder: string;
begin
Result := GetSpecialFolderLocation(CSIDL_NETHOOD);
end;
{$ENDIF ~CLR}
{$IFNDEF CLR}
function GetFontsFolder: string;
begin
Result := GetSpecialFolderLocation(CSIDL_FONTS);
end;
function GetCommonStartmenuFolder: string;
begin
Result := GetSpecialFolderLocation(CSIDL_COMMON_STARTMENU);
end;
{$ENDIF ~CLR}
function GetCommonProgramsFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_COMMON_PROGRAMS);
{$ENDIF ~CLR}
end;
{$IFNDEF CLR}
function GetCommonStartupFolder: string;
begin
Result := GetSpecialFolderLocation(CSIDL_COMMON_STARTUP);
end;
{$ENDIF ~CLR}
function GetCommonDesktopdirectoryFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_COMMON_DESKTOPDIRECTORY);
{$ENDIF ~CLR}
end;
function GetCommonAppdataFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_COMMON_APPDATA);
{$ENDIF ~CLR}
end;
function GetAppdataFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_APPDATA);
{$ENDIF ~CLR}
end;
{$IFNDEF CLR}
function GetPrinthoodFolder: string;
begin
Result := GetSpecialFolderLocation(CSIDL_PRINTHOOD);
end;
{$ENDIF ~CLR}
function GetCommonFavoritesFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.Favorites);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_COMMON_FAVORITES);
{$ENDIF ~CLR}
end;
function GetTemplatesFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.Templates);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_TEMPLATES);
{$ENDIF ~CLR}
end;
function GetInternetCacheFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.InternetCache);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_INTERNET_CACHE);
{$ENDIF ~CLR}
end;
function GetCookiesFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.Cookies);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_COOKIES);
{$ENDIF ~CLR}
end;
function GetHistoryFolder: string;
begin
{$IFDEF CLR}
Result := System.Environment.GetFolderPath(Environment.SpecialFolder.History);
{$ELSE ~CLR}
Result := GetSpecialFolderLocation(CSIDL_HISTORY);
{$ENDIF ~CLR}
end;
{$IFNDEF CLR}
function GetProfileFolder: string;
begin
Result := GetSpecialFolderLocation(CSIDL_PROFILE);
end;
{$ENDIF ~CLR}
// the following special folders are pure virtual and cannot be
// mapped to a directory path:
// CSIDL_INTERNET
// CSIDL_CONTROLS
// CSIDL_PRINTERS
// CSIDL_BITBUCKET
// CSIDL_DRIVES
// CSIDL_NETWORK
// CSIDL_ALTSTARTUP
// CSIDL_COMMON_ALTSTARTUP
{$IFNDEF CLR}
// Identification
type
TVolumeInfoKind = (vikName, vikSerial, vikFileSystem);
function GetVolumeInfoHelper(const Drive: string; InfoKind: TVolumeInfoKind): string;
var
VolumeSerialNumber: DWORD;
MaximumComponentLength: DWORD;
Flags: DWORD;
Name: array [0..MAX_PATH] of Char;
FileSystem: array [0..15] of Char;
ErrorMode: Cardinal;
DriveStr: string;
begin
{ TODO : Change to RootPath }
{ TODO : Perform better checking of Drive param or document that no checking
is performed. RM Suggested:
DriveStr := Drive;
if (Length(Drive) < 2) or (Drive[2] <> ':') then
DriveStr := GetCurrentFolder;
DriveStr := DriveStr[1] + ':\'; }
Result := '';
DriveStr := Drive + ':\';
ErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
try
if GetVolumeInformation(PChar(DriveStr), Name, SizeOf(Name), @VolumeSerialNumber,
MaximumComponentLength, Flags, FileSystem, SizeOf(FileSystem)) then
case InfoKind of
vikName:
Result := StrPas(Name);
vikSerial:
begin
Result := IntToHex(HiWord(VolumeSerialNumber), 4) + '-' +
IntToHex(LoWord(VolumeSerialNumber), 4);
end;
vikFileSystem:
Result := StrPas(FileSystem);
end;
finally
SetErrorMode(ErrorMode);
end;
end;
function GetVolumeName(const Drive: string): string;
begin
Result := GetVolumeInfoHelper(Drive, vikName);
end;
function GetVolumeSerialNumber(const Drive: string): string;
begin
Result := GetVolumeInfoHelper(Drive, vikSerial);
end;
function GetVolumeFileSystem(const Drive: string): string;
begin
Result := GetVolumeInfoHelper(Drive, vikFileSystem);
end;
{ TODO -cHelp : Donator (incl. TFileSystemFlag[s]): Robert Rossmair }
function GetVolumeFileSystemFlags(const Volume: string): TFileSystemFlags;
var
MaximumComponentLength, Flags: Cardinal;
Flag: TFileSystemFlag;
begin
if not GetVolumeInformation(PChar(PathAddSeparator(Volume)), nil, 0, nil,
MaximumComponentLength, Flags, nil, 0) then
RaiseLastOSError;
Result := [];
for Flag := Low(TFileSystemFlag) to High(TFileSystemFlag) do
if (Flags and Ord(Flag)) <> 0 then
Include(Result, Flag);
end;
{$ENDIF ~CLR}
{$ENDIF MSWINDOWS}
{ TODO -cDoc: Contributor: twm }
function GetIPAddress(const HostName: string): string;
{$IFDEF CLR}
var
Host: IPHostEntry;
begin
Host := System.Net.Dns.Resolve(HostName);
if (Host <> nil) and (Length(Host.AddressList) > 0) then
Result := Host.AddressList[0].ToString()
else
Result := '';
end;
{$ELSE ~CLR}
var
{$IFDEF MSWINDOWS}
R: Integer;
WSAData: TWSAData;
{$ENDIF MSWINDOWS}
HostEnt: PHostEnt;
Host: string;
SockAddr: TSockAddrIn;
begin
Result := '';
{$IFDEF MSWINDOWS}
R := WSAStartup(MakeWord(1, 1), WSAData);
if R = 0 then
try
{$ENDIF MSWINDOWS}
Host := HostName;
if Host = '' then
begin
SetLength(Host, MAX_PATH);
GetHostName(PChar(Host), MAX_PATH);
end;
HostEnt := GetHostByName(PChar(Host));
if HostEnt <> nil then
begin
SockAddr.sin_addr.S_addr := Longint(PLongint(HostEnt^.h_addr_list^)^);
Result := inet_ntoa(SockAddr.sin_addr);
end;
{$IFDEF MSWINDOWS}
finally
WSACleanup;
end;
{$ENDIF MSWINDOWS}
end;
{$ENDIF ~CLR}
{$IFDEF UNIX}
{ TODO -cDoc: Donator: twm, Contributor rrossmair }
// Returns all IP addresses of the local machine in the form
// <interface>=<IP-Address> (which allows for access to the interface names
// by means of Results.Names and the addresses through Results.Values)
//
// Example:
//
// lo=127.0.0.1
// eth0=10.10.10.1
// ppp0=217.82.187.130
//
// note that this will append to Results!
//
procedure GetIpAddresses(Results: TStrings);
var
Sock: Integer;
IfReq: TIfReq;
SockAddrPtr: PSockAddrIn;
ListSave, IfList: PIfNameIndex;
begin
//need a socket for ioctl()
Sock := socket(AF_INET, SOCK_STREAM, 0);
if Sock < 0 then
RaiseLastOSError;
try
//returns pointer to dynamically allocated list of structs
ListSave := if_nameindex();
try
IfList := ListSave;
//walk thru the array returned and query for each
//interface's address
while IfList^.if_index <> 0 do
begin
//copy in the interface name to look up address of
strncpy(IfReq.ifrn_name, IfList^.if_name, IFNAMSIZ);
//get the address for this interface
if ioctl(Sock, SIOCGIFADDR, @IfReq) <> 0 then
RaiseLastOSError;
//print out the address
SockAddrPtr := PSockAddrIn(@IfReq.ifru_addr);
Results.Add(Format('%s=%s', [IfReq.ifrn_name, inet_ntoa(SockAddrPtr^.sin_addr)]));
Inc(IfList);
end;
finally
//free the dynamic memory kernel allocated for us
if_freenameindex(ListSave);
end;
finally
Libc.__close(Sock)
end;
end;
{$ENDIF UNIX}
function GetLocalComputerName: string;
{$IFDEF CLR}
begin
Result := System.Environment.MachineName;
end;
{$ELSE ~CLR}
// (rom) UNIX or LINUX?
{$IFDEF LINUX}
var
MachineInfo: utsname;
begin
uname(MachineInfo);
Result := MachineInfo.nodename;
end;
{$ENDIF LINUX}
{$IFDEF MSWINDOWS}
var
Count: DWORD;
begin
Count := MAX_COMPUTERNAME_LENGTH + 1;
// set buffer size to MAX_COMPUTERNAME_LENGTH + 2 characters for safety
{ TODO : Win2k solution }
SetLength(Result, Count);
if GetComputerName(PChar(Result), Count) then
StrResetLength(Result)
else
Result := '';
end;
{$ENDIF MSWINDOWS}
{$ENDIF ~CLR}
{$IFNDEF CLR}
function GetLocalUserName: string;
{$IFDEF UNIX}
begin
Result := GetEnv('USER');
end;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
var
Count: DWORD;
begin
Count := 256 + 1; // UNLEN + 1
// set buffer size to 256 + 2 characters
{ TODO : Win2k solution }
SetLength(Result, Count);
if GetUserName(PChar(Result), Count) then
StrResetLength(Result)
else
Result := '';
end;
{$ENDIF MSWINDOWS}
{$IFDEF MSWINDOWS}
function GetRegisteredCompany: string;
begin
{ TODO : check for MSDN documentation }
Result := RegReadStringDef(HKEY_LOCAL_MACHINE, REG_CURRENT_VERSION, 'RegisteredOrganization', '');
end;
function GetRegisteredOwner: string;
begin
{ TODO : check for MSDN documentation }
Result := RegReadStringDef(HKEY_LOCAL_MACHINE, REG_CURRENT_VERSION, 'RegisteredOwner', '');
end;
{ TODO: Check supported platforms, maybe complete rewrite }
function GetUserDomainName(const CurUser: string): string;
var
Count1, Count2: DWORD;
Sd: PSID; // PSecurityDescriptor; // FPC requires PSID
Snu: SID_Name_Use;
begin
Count1 := 0;
Count2 := 0;
Sd := nil;
Snu := SIDTypeUser;
LookUpAccountName(nil, PChar(CurUser), Sd, Count1, PChar(Result), Count2, Snu);
// set buffer size to Count2 + 2 characters for safety
SetLength(Result, Count2 + 1);
Sd := AllocMem(Count1);
try
if LookUpAccountName(nil, PChar(CurUser), Sd, Count1, PChar(Result), Count2, Snu) then
StrResetLength(Result)
else
Result := EmptyStr;
finally
FreeMem(Sd);
end;
end;
{$ENDIF MSWINDOWS}
function GetDomainName: string;
{$IFDEF UNIX}
var
MachineInfo: utsname;
begin
uname(MachineInfo);
Result := MachineInfo.domainname;
end;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
begin
Result := GetUserDomainName(GetLocalUserName);
end;
{$ENDIF MSWINDOWS}
{$IFDEF MSWINDOWS}
// Reference: How to Obtain BIOS Information from the Registry
// http://support.microsoft.com/default.aspx?scid=kb;en-us;q195268
function GetBIOSName: string;
const
Win9xBIOSInfoKey = 'Enum\Root\*PNP0C01\0000';
begin
if IsWinNT then
Result := ''
else
Result := RegReadStringDef(HKEY_LOCAL_MACHINE, Win9xBIOSInfoKey, 'BIOSName', '');
end;
function GetBIOSCopyright: string;
const
ADR_BIOSCOPYRIGHT = $FE091;
begin
Result := '';
if not IsWinNT and not IsBadReadPtr(Pointer(ADR_BIOSCOPYRIGHT), 2) then
try
Result := PChar(ADR_BIOSCOPYRIGHT);
except
Result := '';
end;
end;
function GetBIOSExtendedInfo: string;
const
ADR_BIOSEXTENDEDINFO = $FEC71;
begin
Result := '';
if not IsWinNT and not IsBadReadPtr(Pointer(ADR_BIOSEXTENDEDINFO), 2) then
try
Result := PChar(ADR_BIOSEXTENDEDINFO);
except
Result := '';
end;
end;
// Reference: How to Obtain BIOS Information from the Registry
// http://support.microsoft.com/default.aspx?scid=kb;en-us;q195268
{ TODO : the date string can be e.g. 00/00/00 }
function GetBIOSDate: TDateTime;
const
WinNT_REG_PATH = 'HARDWARE\DESCRIPTION\System';
WinNT_REG_KEY = 'SystemBiosDate';
Win9x_REG_PATH = 'Enum\Root\*PNP0C01\0000';
Win9x_REG_KEY = 'BiosDate';
var
RegStr: string;
{$IFDEF RTL150_UP}
FormatSettings: TFormatSettings;
{$ELSE RTL150_UP}
RegFormat: string;
RegSeparator: Char;
{$ENDIF RTL150_UP}
begin
if IsWinNT then
RegStr := RegReadString(HKEY_LOCAL_MACHINE, WinNT_REG_PATH, WinNT_REG_KEY)
else
RegStr := RegReadString(HKEY_LOCAL_MACHINE, Win9x_REG_PATH, Win9x_REG_KEY);
{$IFDEF RTL150_UP}
FillChar(FormatSettings, SizeOf(FormatSettings), 0);
FormatSettings.DateSeparator := '/';
FormatSettings.ShortDateFormat := 'm/d/y';
if not TryStrToDate(RegStr, Result, FormatSettings) then
begin
FormatSettings.ShortDateFormat := 'y/m/d';
if not TryStrToDate(RegStr, Result, FormatSettings) then
Result := 0;
end;
{$ELSE RTL150_UP}
Result := 0;
{ TODO : change to a threadsafe solution }
RegFormat := ShortDateFormat;
RegSeparator := DateSeparator;
try
DateSeparator := '/';
try
ShortDateFormat := 'm/d/y';
Result := StrToDate(RegStr);
except
try
ShortDateFormat := 'y/m/d';
Result := StrToDate(RegStr);
except
end;
end;
finally
ShortDateFormat := RegFormat;
DateSeparator := RegSeparator;
end;
{$ENDIF RTL150_UP}
end;
{$ENDIF MSWINDOWS}
//=== Processes, Tasks and Modules ===========================================
{$IFDEF UNIX}
const
CommLen = 16; // synchronize with size of comm in struct task_struct in
// /usr/include/linux/sched.h
SProcDirectory = '/proc';
function RunningProcessesList(const List: TStrings; FullPath: Boolean): Boolean;
var
ProcDir: PDirectoryStream;
PtrDirEnt: PDirEnt;
Scratch: TDirEnt;
ProcID: __pid_t;
E: Integer;
FileName: string;
F: PIOFile;
begin
Result := False;
ProcDir := opendir(SProcDirectory);
if ProcDir <> nil then
begin
PtrDirEnt := nil;
if readdir_r(ProcDir, @Scratch, PtrDirEnt) <> 0 then
Exit;
List.BeginUpdate;
try
while PtrDirEnt <> nil do
begin
Val(PtrDirEnt^.d_name, ProcID, E);
if E = 0 then // name was process id
begin
FileName := '';
if FullPath then
FileName := SymbolicLinkTarget(Format('/proc/%s/exe', [PtrDirEnt^.d_name]));
if FileName = '' then // usually due to insufficient access rights
begin
// read stat
FileName := Format('/proc/%s/stat', [PtrDirEnt^.d_name]);
F := fopen(PChar(FileName), 'r');
if F = nil then
raise EJclError.CreateResFmt(@RsInvalidProcessID, [ProcID]);
try
SetLength(FileName, CommLen);
if fscanf(F, PChar(Format('%%*d (%%%d[^)])', [CommLen])), PChar(FileName)) <> 1 then
RaiseLastOSError;
StrResetLength(FileName);
finally
fclose(F);
end;
end;
List.AddObject(FileName, Pointer(ProcID));
end;
if readdir_r(ProcDir, @Scratch, PtrDirEnt) <> 0 then
Break;
end;
finally
List.EndUpdate;
end;
end;
end;
{$ENDIF UNIX}
{$ENDIF ~CLR}
{$IFDEF MSWINDOWS}
function RunningProcessesList(const List: TStrings; FullPath: Boolean): Boolean;
{$IFDEF CLR}
var
Processes: array of Process;
I: Integer;
HasModules: Boolean;
begin
Result := True;
Processes := Process.GetProcesses;
for I := 0 to High(Processes) do
begin
try
HasModules := Processes[I].Modules.Count > 0;
except
on Win32Exception do
HasModules := False;
end;
if not HasModules then
List.Add(Processes[I].ProcessName)
else
if FullPath then
List.Add(Processes[I].MainModule.FileName)
else
List.Add(Processes[I].MainModule.ModuleName);
end;
end;
{$ELSE ~CLR}
// This function always returns an empty string on Win9x
function ProcessFileName(PID: DWORD): string;
var
Handle: THandle;
begin
Result := '';
Handle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PID);
if Handle <> 0 then
try
SetLength(Result, MAX_PATH);
if FullPath then
begin
if GetModuleFileNameEx(Handle, 0, PChar(Result), MAX_PATH) > 0 then
StrResetLength(Result)
else
Result := '';
end
else
begin
if GetModuleBaseNameA(Handle, 0, PChar(Result), MAX_PATH) > 0 then
StrResetLength(Result)
else
Result := '';
end;
finally
CloseHandle(Handle);
end;
end;
{ TODO: Check return value of CreateToolhelp32Snapshot on Windows NT (0?) }
function BuildListTH: Boolean;
var
SnapProcHandle: THandle;
ProcEntry: TProcessEntry32;
NextProc: Boolean;
FileName: string;
begin
SnapProcHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
Result := (SnapProcHandle <> INVALID_HANDLE_VALUE);
if Result then
try
ProcEntry.dwSize := SizeOf(ProcEntry);
NextProc := Process32First(SnapProcHandle, ProcEntry);
while NextProc do
begin
if ProcEntry.th32ProcessID = 0 then
begin
// PID 0 is always the "System Idle Process" but this name cannot be
// retrieved from the system and has to be fabricated.
FileName := RsSystemIdleProcess;
end
else
begin
if IsWin2k or IsWinXP or IsWin2003 or IsWin2003R2 or IsWinXP64
or IsWinVista or IsWinLonghorn then
begin
FileName := ProcessFileName(ProcEntry.th32ProcessID);
if FileName = '' then
FileName := ProcEntry.szExeFile;
end
else
begin
FileName := ProcEntry.szExeFile;
if not FullPath then
FileName := ExtractFileName(FileName);
end;
end;
List.AddObject(FileName, Pointer(ProcEntry.th32ProcessID));
NextProc := Process32Next(SnapProcHandle, ProcEntry);
end;
finally
CloseHandle(SnapProcHandle);
end;
end;
function BuildListPS: Boolean;
var
PIDs: array [0..1024] of DWORD;
Needed: DWORD;
I: Integer;
FileName: string;
begin
Result := EnumProcesses(@PIDs, SizeOf(PIDs), Needed);
if Result then
begin
for I := 0 to (Needed div SizeOf(DWORD)) - 1 do
begin
case PIDs[I] of
0:
// PID 0 is always the "System Idle Process" but this name cannot be
// retrieved from the system and has to be fabricated.
FileName := RsSystemIdleProcess;
2:
// On NT 4 PID 2 is the "System Process" but this name cannot be
// retrieved from the system and has to be fabricated.
if IsWinNT4 then
FileName := RsSystemProcess
else
FileName := ProcessFileName(PIDs[I]);
8:
// On Win2K PID 8 is the "System Process" but this name cannot be
// retrieved from the system and has to be fabricated.
if IsWin2k or IsWinXP then
FileName := RsSystemProcess
else
FileName := ProcessFileName(PIDs[I]);
else
FileName := ProcessFileName(PIDs[I]);
end;
if FileName <> '' then
List.AddObject(FileName, Pointer(PIDs[I]));
end;
end;
end;
begin
{ TODO : safer solution? }
List.BeginUpdate;
try
if GetWindowsVersion in [wvWinNT31, wvWinNT35, wvWinNT351, wvWinNT4] then
Result := BuildListPS
else
Result := BuildListTH;
finally
List.EndUpdate;
end;
end;
{$ENDIF ~CLR}
{$IFNDEF CLR}
{ TODO Windows 9x ? }
function LoadedModulesList(const List: TStrings; ProcessID: DWORD; HandlesOnly: Boolean): Boolean;
procedure AddToList(ProcessHandle: THandle; Module: HMODULE);
var
FileName: array [0..MAX_PATH] of Char;
ModuleInfo: TModuleInfo;
begin
{$IFDEF FPC}
if GetModuleInformation(ProcessHandle, Module, ModuleInfo, SizeOf(ModuleInfo)) then
{$ELSE ~FPC}
if GetModuleInformation(ProcessHandle, Module, @ModuleInfo, SizeOf(ModuleInfo)) then
{$ENDIF ~FPC}
begin
if HandlesOnly then
List.AddObject('', Pointer(ModuleInfo.lpBaseOfDll))
else
if GetModuleFileNameEx(ProcessHandle, Module, Filename, SizeOf(Filename)) > 0 then
List.AddObject(FileName, Pointer(ModuleInfo.lpBaseOfDll));
end;
end;
function EnumModulesVQ(ProcessHandle: THandle): Boolean;
var
MemInfo: TMemoryBasicInformation;
Base: PChar;
LastAllocBase: Pointer;
Res: DWORD;
begin
Base := nil;
LastAllocBase := nil;
FillChar(MemInfo, SizeOf(MemInfo), #0);
Res := VirtualQueryEx(ProcessHandle, Base, MemInfo, SizeOf(MemInfo));
Result := (Res = SizeOf(MemInfo));
while Res = SizeOf(MemInfo) do
begin
if MemInfo.AllocationBase <> LastAllocBase then
begin
{$IFDEF FPC}
if MemInfo._Type = MEM_IMAGE then
{$ELSE ~FPC}
if MemInfo.Type_9 = MEM_IMAGE then
{$ENDIF ~FPC}
AddToList(ProcessHandle, HMODULE(MemInfo.AllocationBase));
LastAllocBase := MemInfo.AllocationBase;
end;
Inc(Base, MemInfo.RegionSize);
Res := VirtualQueryEx(ProcessHandle, Base, MemInfo, SizeOf(MemInfo));
end;
end;
function EnumModulesPS: Boolean;
var
ProcessHandle: THandle;
Needed: DWORD;
Modules: array of THandle;
I, Cnt: Integer;
begin
Result := False;
ProcessHandle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, ProcessID);
if ProcessHandle <> 0 then
try
Result := EnumProcessModules(ProcessHandle, nil, 0, Needed);
if Result then
begin
Cnt := Needed div SizeOf(HMODULE);
SetLength(Modules, Cnt);
if EnumProcessModules(ProcessHandle, @Modules[0], Needed, Needed) then
for I := 0 to Cnt - 1 do
AddToList(ProcessHandle, Modules[I]);
end
else
Result := EnumModulesVQ(ProcessHandle);
finally
CloseHandle(ProcessHandle);
end;
end;
{ TODO: Check return value of CreateToolhelp32Snapshot on Windows NT (0?) }
function EnumModulesTH: Boolean;
var
SnapProcHandle: THandle;
Module: TModuleEntry32;
Next: Boolean;
begin
SnapProcHandle := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, ProcessID);
Result := (SnapProcHandle <> INVALID_HANDLE_VALUE);
if Result then
try
FillChar(Module, SizeOf(Module), #0);
Module.dwSize := SizeOf(Module);
Next := Module32First(SnapProcHandle, Module);
while Next do
begin
if HandlesOnly then
List.AddObject('', Pointer(Module.hModule))
else
List.AddObject(Module.szExePath, Pointer(Module.hModule));
Next := Module32Next(SnapProcHandle, Module);
end;
finally
CloseHandle(SnapProcHandle);
end;
end;
begin
List.BeginUpdate;
try
if IsWinNT then
Result := EnumModulesPS
else
Result := EnumModulesTH;
finally
List.EndUpdate;
end;
end;
function GetTasksList(const List: TStrings): Boolean;
function EnumWindowsProc(Wnd: THandle; List: TStrings): Boolean; stdcall;
var
Caption: array [0..1024] of Char;
begin
if IsMainAppWindow(Wnd) and (GetWindowText(Wnd, Caption, SizeOf(Caption)) > 0) then
List.AddObject(Caption, Pointer(Wnd));
Result := True;
end;
begin
List.BeginUpdate;
try
Result := EnumWindows(@EnumWindowsProc, Integer(List));
finally
List.EndUpdate;
end;
end;
function ModuleFromAddr(const Addr: Pointer): HMODULE;
var
MI: TMemoryBasicInformation;
begin
VirtualQuery(Addr, MI, SizeOf(MI));
if MI.State <> MEM_COMMIT then
Result := 0
else
Result := HMODULE(MI.AllocationBase);
end;
{$IFNDEF FPC}
function IsSystemModule(const Module: HMODULE): Boolean;
var
CurModule: PLibModule;
begin
Result := False;
if Module <> 0 then
begin
CurModule := LibModuleList;
while CurModule <> nil do
begin
if CurModule.Instance = Module then
begin
Result := True;
Break;
end;
CurModule := CurModule.Next;
end;
end;
end;
{$ENDIF ~FPC}
// Reference: http://msdn.microsoft.com/library/periodic/period97/win321197.htm
{ TODO : wrong link }
function IsMainAppWindow(Wnd: THandle): Boolean;
var
ParentWnd: THandle;
ExStyle: DWORD;
begin
if IsWindowVisible(Wnd) then
begin
ParentWnd := GetWindowLong(Wnd, GWL_HWNDPARENT);
ExStyle := GetWindowLong(Wnd, GWL_EXSTYLE);
Result := ((ParentWnd = 0) or (ParentWnd = GetDesktopWindow)) and
((ExStyle and WS_EX_TOOLWINDOW = 0) or (ExStyle and WS_EX_APPWINDOW <> 0));
end
else
Result := False;
end;
function IsWindowResponding(Wnd: THandle; Timeout: Integer): Boolean;
var
Res: DWORD;
begin
Result := SendMessageTimeout(Wnd, WM_NULL, 0, 0, SMTO_ABORTIFHUNG, Timeout, Res) <> 0;
end;
function GetWindowIcon(Wnd: THandle; LargeIcon: Boolean): HICON;
var
Width, Height: Integer;
TempIcon: HICON;
IconType: DWORD;
begin
if LargeIcon then
begin
Width := GetSystemMetrics(SM_CXICON);
Height := GetSystemMetrics(SM_CYICON);
IconType := ICON_BIG;
TempIcon := GetClassLong(Wnd, GCL_HICON);
end
else
begin
Width := GetSystemMetrics(SM_CXSMICON);
Height := GetSystemMetrics(SM_CYSMICON);
IconType := ICON_SMALL;
TempIcon := GetClassLong(Wnd, GCL_HICONSM);
end;
if TempIcon = 0 then
TempIcon := SendMessage(Wnd, WM_GETICON, IconType, 0);
if (TempIcon = 0) and not LargeIcon then
TempIcon := SendMessage(Wnd, WM_GETICON, ICON_BIG, 0);
Result := CopyImage(TempIcon, IMAGE_ICON, Width, Height, 0);
end;
function GetWindowCaption(Wnd: THandle): string;
const
BufferAllocStep = 256;
var
Buffer: PChar;
Size, TextLen: Integer;
begin
{ TODO : use string }
Result := '';
Buffer := nil;
try
Size := GetWindowTextLength(Wnd) + 2 - BufferAllocStep;
repeat
Inc(Size, BufferAllocStep);
ReallocMem(Buffer, Size);
TextLen := GetWindowText(Wnd, Buffer, Size);
until TextLen < Size - 1;
if TextLen > 0 then
Result := Buffer;
finally
FreeMem(Buffer);
end;
end;
// Q178893
// http://support.microsoft.com/default.aspx?scid=kb;en-us;178893
function TerminateApp(ProcessID: DWORD; Timeout: Integer): TJclTerminateAppResult;
var
ProcessHandle: THandle;
function EnumWindowsProc(Wnd: THandle; ProcessID: DWORD): Boolean; stdcall;
var
PID: DWORD;
begin
GetWindowThreadProcessId(Wnd, @PID);
if ProcessID = PID then
PostMessage(Wnd, WM_CLOSE, 0, 0);
Result := True;
end;
begin
Result := taError;
if ProcessID <> GetCurrentProcessId then
begin
ProcessHandle := OpenProcess(SYNCHRONIZE or PROCESS_TERMINATE, False, ProcessID);
if ProcessHandle <> 0 then
try
EnumWindows(@EnumWindowsProc, LPARAM(ProcessID));
if WaitForSingleObject(ProcessHandle, Timeout) = WAIT_OBJECT_0 then
Result := taClean
else
if TerminateProcess(ProcessHandle, 0) then
Result := taKill;
finally
CloseHandle(ProcessHandle);
end;
end;
end;
function TerminateTask(Wnd: THandle; Timeout: Integer): TJclTerminateAppResult;
var
PID: DWORD;
begin
if GetWindowThreadProcessId(Wnd, @PID) <> 0 then
Result := TerminateApp(PID, Timeout)
else
Result := taError;
end;
function GetProcessNameFromWnd(Wnd: THandle): string;
var
List: TStringList;
PID: DWORD;
I: Integer;
begin
Result := '';
if IsWindow(Wnd) then
begin
PID := INVALID_HANDLE_VALUE;
GetWindowThreadProcessId(Wnd, @PID);
List := TStringList.Create;
try
if RunningProcessesList(List, True) then
begin
I := List.IndexOfObject(Pointer(PID));
if I > -1 then
Result := List[I];
end;
finally
List.Free;
end;
end;
end;
function GetPidFromProcessName(const ProcessName: string): DWORD;
var
List: TStringList;
I: Integer;
HasFullPath: Boolean;
begin
Result := INVALID_HANDLE_VALUE;
List := TStringList.Create;
try
HasFullPath := ExtractFilePath(ProcessName) <> '';
if RunningProcessesList(List, HasFullPath) then
begin
I := List.IndexOf(ProcessName);
if I > -1 then
Result := DWORD(List.Objects[I]);
end;
finally
List.Free;
end;
end;
function GetProcessNameFromPid(PID: DWORD): string;
var
List: TStringList;
I: Integer;
begin
// Note: there are other ways to retrieve the name of the process given it's
// PID but this implementation seems to work best without making assumptions
// although it may not be the most efficient implementation.
Result := '';
List := TStringList.Create;
try
if RunningProcessesList(List, True) then
begin
I := List.IndexOfObject(Pointer(PID));
if I > -1 then
Result := List[I];
end;
finally
List.Free;
end;
end;
function GetMainAppWndFromPid(PID: DWORD): THandle;
type
PSearch = ^TSearch;
TSearch = record
PID: DWORD;
Wnd: THandle;
end;
var
SearchRec: TSearch;
function EnumWindowsProc(Wnd: THandle; Res: PSearch): Boolean; stdcall;
var
WindowPid: DWORD;
begin
WindowPid := 0;
GetWindowThreadProcessId(Wnd, @WindowPid);
if (WindowPid = Res^.PID) and IsMainAppWindow(Wnd) then
begin
Res^.Wnd := Wnd;
Result := False;
end
else
Result := True;
end;
begin
SearchRec.PID := PID;
SearchRec.Wnd := 0;
EnumWindows(@EnumWindowsProc, Integer(@SearchRec));
Result := SearchRec.Wnd;
end;
function GetShellProcessName: string;
const
cShellKey = 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon';
cShellValue = 'Shell';
cShellDefault = 'explorer.exe';
cShellSystemIniFileName = 'system.ini';
cShellBootSection = 'boot';
begin
if IsWinNT then
Result := RegReadStringDef(HKEY_LOCAL_MACHINE, cShellKey, cShellValue, '')
else
Result := IniReadString(PathAddSeparator(GetWindowsFolder) + cShellSystemIniFileName, cShellBootSection, cShellValue);
if Result = '' then
Result := cShellDefault;
end;
function GetShellProcessHandle: THandle;
var
Pid: Longword;
begin
Pid := GetPidFromProcessName(GetShellProcessName);
Result := OpenProcess(PROCESS_ALL_ACCESS, False, Pid);
if Result = 0 then
RaiseLastOSError;
end;
//=== Version Information ====================================================
{ Q159/238
Windows 95 retail, OEM 4.00.950 7/11/95
Windows 95 retail SP1 4.00.950A 7/11/95-12/31/95
OEM Service Release 2 4.00.1111* (4.00.950B) 8/24/96
OEM Service Release 2.1 4.03.1212-1214* (4.00.950B) 8/24/96-8/27/97
OEM Service Release 2.5 4.03.1214* (4.00.950C) 8/24/96-11/18/97
Windows 98 retail, OEM 4.10.1998 5/11/98
Windows 98 Second Edition 4.10.2222A 4/23/99
Windows Millennium 4.90.3000
}
{ TODO : Distinquish between all these different releases? }
var
KernelVersionHi: DWORD;
function GetWindowsVersion: TWindowsVersion;
var
TrimmedWin32CSDVersion: string;
SystemInfo: TSystemInfo;
OSVersionInfoEx: TOSVersionInfoEx;
const
SM_SERVERR2 = 89;
begin
Result := wvUnknown;
TrimmedWin32CSDVersion := Trim(Win32CSDVersion);
case Win32Platform of
VER_PLATFORM_WIN32_WINDOWS:
case Win32MinorVersion of
0..9:
if (TrimmedWin32CSDVersion = 'B') or (TrimmedWin32CSDVersion = 'C') then
Result := wvWin95OSR2
else
Result := wvWin95;
10..89:
// On Windows ME Win32MinorVersion can be 10 (indicating Windows 98
// under certain circumstances (image name is setup.exe). Checking
// the kernel version is one way of working around that.
if KernelVersionHi = $0004005A then // 4.90.x.x
Result := wvWinME
else
if TrimmedWin32CSDVersion = 'A' then
Result := wvWin98SE
else
Result := wvWin98;
90:
Result := wvWinME;
end;
VER_PLATFORM_WIN32_NT:
case Win32MajorVersion of
3:
case Win32MinorVersion of
1:
Result := wvWinNT31;
5:
Result := wvWinNT35;
51:
Result := wvWinNT351;
end;
4:
Result := wvWinNT4;
5:
case Win32MinorVersion of
0:
Result := wvWin2000;
1:
Result := wvWinXP;
2:
begin
OSVersionInfoEx.dwOSVersionInfoSize := SizeOf(OSVersionInfoEx);
GetNativeSystemInfo(SystemInfo);
if GetSystemMetrics(SM_SERVERR2) <> 0 then
Result := wvWin2003R2
else if (SystemInfo.wProcessorArchitecture <> PROCESSOR_ARCHITECTURE_INTEL)
and GetVersionEx(OSVersionInfoEx) and (OSVersionInfoEx.wProductType = VER_NT_WORKSTATION) then
Result := wvWinXP64
else
Result := wvWin2003;
end;
end;
6:
if Win32MinorVersion = 0 then
begin
OSVersionInfoEx.dwOSVersionInfoSize := SizeOf(OSVersionInfoEx);
if GetVersionEx(OSVersionInfoEx) and (OSVersionInfoEx.wProductType = VER_NT_WORKSTATION) then
Result := wvWinVista
else
Result := wvWinLonghorn;
end;
end;
end;
end;
function NtProductType: TNtProductType;
const
ProductType = 'SYSTEM\CurrentControlSet\Control\ProductOptions';
var
Product: string;
OSVersionInfo: TOSVersionInfoEx;
SystemInfo: TSystemInfo;
begin
Result := ptUnknown;
FillChar(OSVersionInfo, SizeOf(OSVersionInfo), 0);
FillChar(SystemInfo, SizeOf(SystemInfo), 0);
OSVersionInfo.dwOSVersionInfoSize := SizeOf(OSVersionInfo);
GetNativeSystemInfo(SystemInfo);
// Favor documented API over registry
if IsWinNT4 and (GetWindowsServicePackVersion >= 6) then
begin
if GetVersionEx(OSVersionInfo) then
begin
if (OSVersionInfo.wProductType = VER_NT_WORKSTATION) then
Result := ptWorkstation
else if (OSVersionInfo.wSuiteMask and VER_SUITE_ENTERPRISE) = VER_SUITE_ENTERPRISE then
Result := ptEnterprise
else
Result := ptServer;
end;
end
else
if IsWin2K then
begin
if GetVersionEx(OSVersionInfo) then
begin
if OSVersionInfo.wProductType in [VER_NT_SERVER,VER_NT_DOMAIN_CONTROLLER] then
begin
if (OSVersionInfo.wSuiteMask and VER_SUITE_DATACENTER) <> 0 then
Result := ptDatacenterServer
else if (OSVersionInfo.wSuiteMask and VER_SUITE_ENTERPRISE) <> 0 then
Result := ptAdvancedServer
else
Result := ptServer;
end
else
Result := ptProfessional;
end;
end
else
if IsWinXP64 or IsWin2003 or IsWin2003R2 then // all (5.2)
begin
if GetVersionEx(OSVersionInfo) then
begin
if OSVersionInfo.wProductType in [VER_NT_SERVER,VER_NT_DOMAIN_CONTROLLER] then
begin
if (OSVersionInfo.wSuiteMask and VER_SUITE_DATACENTER) = VER_SUITE_DATACENTER then
Result := ptDatacenterServer
else
if (OSVersionInfo.wSuiteMask and VER_SUITE_ENTERPRISE) = VER_SUITE_ENTERPRISE then
Result := ptEnterprise
else if (OSVersionInfo.wSuiteMask = VER_SUITE_BLADE) then
Result := ptWebEdition
else
Result := ptServer;
end
else
if (OSVersionInfo.wProductType = VER_NT_WORKSTATION) then
Result := ptProfessional;
end;
end
else
if IsWinXP or IsWinVista or IsWinLonghorn then // workstation
begin
if GetVersionEx(OSVersionInfo) then
begin
if OSVersionInfo.wProductType = VER_NT_WORKSTATION then
begin
if (OSVersionInfo.wSuiteMask and VER_SUITE_PERSONAL) = VER_SUITE_PERSONAL then
Result := ptPersonal
else
Result := ptProfessional;
end;
end;
end;
if Result = ptUnknown then
begin
// Non Windows 2000/XP system or the above method failed, try registry
Product := RegReadStringDef(HKEY_LOCAL_MACHINE, ProductType, 'ProductType', '');
if CompareText(Product, 'WINNT') = 0 then
Result := ptWorkStation
else
if CompareText(Product, 'SERVERNT') = 0 then
Result := {ptServer} ptAdvancedServer
else
if CompareText(Product, 'LANMANNT') = 0 then
Result := {ptAdvancedServer} ptServer
else
Result := ptUnknown;
end;
end;
function GetWindowsVersionString: string;
begin
case GetWindowsVersion of
wvWin95:
Result := RsOSVersionWin95;
wvWin95OSR2:
Result := RsOSVersionWin95OSR2;
wvWin98:
Result := RsOSVersionWin98;
wvWin98SE:
Result := RsOSVersionWin98SE;
wvWinME:
Result := RsOSVersionWinME;
wvWinNT31, wvWinNT35, wvWinNT351:
Result := Format(RsOSVersionWinNT3, [Win32MinorVersion]);
wvWinNT4:
Result := Format(RsOSVersionWinNT4, [Win32MinorVersion]);
wvWin2000:
Result := RsOSVersionWin2000;
wvWinXP:
Result := RsOSVersionWinXP;
wvWin2003:
Result := RsOSVersionWin2003;
wvWin2003R2:
Result := RsOSVersionWin2003R2;
wvWinXP64:
Result := RsOSVersionWinXP64;
wvWinLonghorn:
Result := RsOSVersionWinLonghorn;
wvWinVista:
Result := RsOSVersionWinVista;
else
Result := '';
end;
end;
function NtProductTypeString: string;
begin
case NtProductType of
ptWorkStation:
Result := RsProductTypeWorkStation;
ptServer:
Result := RsProductTypeServer;
ptAdvancedServer:
Result := RsProductTypeAdvancedServer;
ptPersonal:
Result := RsProductTypePersonal;
ptProfessional:
Result := RsProductTypeProfessional;
ptDatacenterServer:
Result := RsProductTypeDatacenterServer;
ptEnterprise:
Result := RsProductTypeEnterprise;
ptWebEdition:
Result := RsProductTypeWebEdition;
else
Result := '';
end;
end;
function GetWindowsServicePackVersion: Integer;
const
RegWindowsControl = 'SYSTEM\CurrentControlSet\Control\Windows';
var
SP: Integer;
VersionInfo: TOSVersionInfoEx;
begin
Result := 0;
if IsWin2K or IsWinXP or IsWin2003 or IsWinXP64 or IsWin2003R2 or IsWinVista
or IsWinLonghorn then
begin
FillChar(VersionInfo, SizeOf(VersionInfo), 0);
VersionInfo.dwOSVersionInfoSize := SizeOf(VersionInfo);
if GetVersionEx(VersionInfo) then
Result := VersionInfo.wServicePackMajor;
end
else
begin
SP := RegReadIntegerDef(HKEY_LOCAL_MACHINE, RegWindowsControl, 'CSDVersion', 0);
Result := StrToInt(IntToHex(SP, 4)) div 100;
end;
end;
function GetWindowsServicePackVersionString: string;
var
SP: Integer;
begin
SP := GetWindowsServicePackVersion;
if SP > 0 then
Result := Format(RsSPInfo, [SP])
else
Result := '';
end;
// Imports copied from OpenGL unit. Direct using of OpenGL unit might cause unexpected problems due
// setting 8087CW in the intialization section
function glGetString(name: Cardinal): PChar; stdcall; external opengl32;
function glGetError: Cardinal; stdcall; external opengl32;
function gluErrorString(errCode: Cardinal): PChar; stdcall; external 'glu32.dll';
function GetOpenGLVersion(const Win: THandle; out Version, Vendor: AnsiString): Boolean;
const
GL_NO_ERROR = 0;
GL_VENDOR = $1F00;
GL_VERSION = $1F02;
var
pfd: TPixelFormatDescriptor;
iFormatIndex: Integer;
hGLContext: HGLRC;
hGLDC: HDC;
pcTemp: PChar;
glErr: Cardinal;
bError: Boolean;
sOpenGLVersion, sOpenGLVendor: string;
Save8087CW: Word;
procedure FunctionFailedError(Name: string);
begin
raise EJclError.CreateResFmt(@RsEOpenGLInfo, [Name]);
end;
begin
{ To call for the version information string we must first have an active
context established for use. We can, of course, close this after use }
Save8087CW := Get8087ControlWord;
try
Set8087CW($133F);
hGLContext := 0;
Result := False;
bError := False;
if Win = 0 then
begin
Result := False;
Vendor := RsOpenGLInfoError;
Version := RsOpenGLInfoError;
Exit;
end;
FillChar(pfd, SizeOf(pfd), 0);
with pfd do
begin
nSize := SizeOf(pfd);
nVersion := 1; { The Current Version of the descriptor is 1 }
dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL;
iPixelType := PFD_TYPE_RGBA;
cColorBits := 24; { support 24-bit colour }
cDepthBits := 32; { Depth of the z-buffer }
iLayerType := PFD_MAIN_PLANE;
end;
hGLDC := GetDC(Win);
try
iFormatIndex := ChoosePixelFormat(hGLDC, @pfd);
if iFormatIndex = 0 then
FunctionFailedError('ChoosePixelFormat');
if not SetPixelFormat(hGLDC, iFormatIndex, @pfd) then
FunctionFailedError('SetPixelFormat');
hGLContext := wglCreateContext(hGLDC);
if hGLContext = 0 then
FunctionFailedError('wglCreateContext');
if not wglMakeCurrent(hGLDC, hGLContext) then
FunctionFailedError('wglMakeCurrent');
{ TODO : Review the following. Not sure I am 100% happy with this code
in its current structure. }
pcTemp := glGetString(GL_VERSION);
if pcTemp <> nil then
begin
{ TODO : Store this information in a Global Variable, and return that??
This would save this work being performed again with later calls }
sOpenGLVersion := StrPas(pcTemp);
end
else
begin
bError := True;
glErr := glGetError;
if glErr <> GL_NO_ERROR then
begin
sOpenGLVersion := gluErrorString(glErr);
sOpenGLVendor := '';
end;
end;
pcTemp := glGetString(GL_VENDOR);
if pcTemp <> nil then
begin
{ TODO : Store this information in a Global Variable, and return that??
This would save this work being performed again with later calls }
sOpenGLVendor := StrPas(pcTemp);
end
else
begin
bError := True;
glErr := glGetError;
if glErr <> GL_NO_ERROR then
begin
sOpenGLVendor := gluErrorString(glErr);
Exit;
end;
end;
Result := (not bError);
Version := sOpenGLVersion;
Vendor := sOpenGLVendor;
finally
{ Close all resources }
wglMakeCurrent(hGLDC, 0);
if hGLContext <> 0 then
wglDeleteContext(hGLContext);
end;
finally
Set8087CW(Save8087CW);
end;
end;
function GetNativeSystemInfo(var SystemInfo: TSystemInfo): Boolean;
type
TGetNativeSystemInfo = procedure (var SystemInfo: TSystemInfo) stdcall;
var
LibraryHandle: HMODULE;
_GetNativeSystemInfo: TGetNativeSystemInfo;
begin
Result := False;
LibraryHandle := LoadLibrary('kernel32.dll');
if LibraryHandle <> 0 then
begin
try
_GetNativeSystemInfo := GetProcAddress(LibraryHandle,'GetNativeSystemInfo');
if Assigned(_GetNativeSystemInfo) then
begin
_GetNativeSystemInfo(SystemInfo);
Result := True;
end
else
GetSystemInfo(SystemInfo);
finally
FreeLibrary(LibraryHandle);
end;
end
else
GetSystemInfo(SystemInfo);
end;
function GetProcessorArchitecture: TProcessorArchitecture;
var
ASystemInfo: TSystemInfo;
begin
GetNativeSystemInfo(ASystemInfo);
case ASystemInfo.wProcessorArchitecture of
PROCESSOR_ARCHITECTURE_INTEL:
Result := pax8632;
PROCESSOR_ARCHITECTURE_IA64:
Result := paIA64;
PROCESSOR_ARCHITECTURE_AMD64:
Result := pax8664;
else
Result := paUnknown;
end;
end;
function IsWindows64: Boolean;
var
ASystemInfo: TSystemInfo;
begin
GetNativeSystemInfo(ASystemInfo);
Result := ASystemInfo.wProcessorArchitecture in [PROCESSOR_ARCHITECTURE_IA64,PROCESSOR_ARCHITECTURE_AMD64];
end;
{$ENDIF ~CLR}
{$ENDIF MSWINDOWS}
{$IFNDEF CLR}
function GetOSVersionString: string;
{$IFDEF UNIX}
var
MachineInfo: utsname;
begin
uname(MachineInfo);
Result := Format('%s %s', [MachineInfo.sysname, MachineInfo.release]);
end;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
begin
Result := Format('%s %s', [GetWindowsVersionString, GetWindowsServicePackVersionString]);
end;
{$ENDIF MSWINDOWS}
//=== Hardware ===============================================================
// Helper function for GetMacAddress()
// Converts the adapter_address array to a string
function AdapterToString(Adapter: PJclByteArray): string;
begin
Result := Format('%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x',
[Integer(Adapter[0]), Integer(Adapter[1]),
Integer(Adapter[2]), Integer(Adapter[3]),
Integer(Adapter[4]), Integer(Adapter[5])]);
end;
{ TODO: RTLD version of NetBios }
{$IFDEF MSWINDOWS}
type
TNetBios = function(P: PNCB): Byte; stdcall;
var
NetBiosLib: HINST = 0;
_NetBios: TNetBios;
{$IFDEF FPC}
NullAdapterAddress: array [0..5] of Byte = ($00, $00, $00, $00, $00, $00);
OID_ipMACEntAddr: array [0..9] of UINT = (1, 3, 6, 1, 2, 1, 2, 2, 1, 6);
OID_ifEntryType: array [0..9] of UINT = (1, 3, 6, 1, 2, 1, 2, 2, 1, 3);
OID_ifEntryNum: array [0..7] of UINT = (1, 3, 6, 1, 2, 1, 2, 1);
{$ENDIF FPC}
function GetMacAddresses(const Machine: string; const Addresses: TStrings): Integer;
procedure ExitNetbios;
begin
if NetBiosLib <> 0 then
begin
FreeLibrary(NetBiosLib);
NetBiosLib := 0;
end;
end;
function InitNetbios: Boolean;
begin
Result := True;
if NetBiosLib = 0 then
begin
NetBiosLib := LoadLibrary(PChar('netapi32.dll'));
Result := NetBiosLib <> 0;
if Result then
begin
@_NetBios := GetProcAddress(NetBiosLib, PChar('Netbios'));
Result := @_NetBios <> nil;
if not Result then
ExitNetbios;
end;
end;
end;
function NetBios(P: PNCB): Byte;
begin
if InitNetbios then
Result := _NetBios(P)
else
Result := 1; // anything other than NRC_GOODRET will do
end;
procedure GetMacAddressesNetBios;
// Platform SDK
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netbios/netbios_1l82.asp
// Microsoft Knowledge Base Article - 118623
// HOWTO: Get the MAC Address for an Ethernet Adapter
// http://support.microsoft.com/default.aspx?scid=kb;en-us;118623
type
AStat = packed record
adapt: TAdapterStatus;
NameBuff: array [0..29] of TNameBuffer;
end;
var
NCB: TNCB;
Enum: TLanaEnum;
I, L, NameLen: Integer;
Adapter: AStat;
MachineName: string;
begin
MachineName := UpperCase(Machine);
if MachineName = '' then
MachineName := '*';
NameLen := Length(MachineName);
L := NCBNAMSZ - NameLen;
if L > 0 then
begin
SetLength(MachineName, NCBNAMSZ);
FillChar(MachineName[NameLen + 1], L, ' ');
end;
FillChar(NCB, SizeOf(NCB), #0);
NCB.ncb_command := NCBENUM;
NCB.ncb_buffer := Pointer(@Enum);
NCB.ncb_length := SizeOf(Enum);
if NetBios(@NCB) = NRC_GOODRET then
begin
Result := Enum.Length;
for I := 0 to Ord(Enum.Length) - 1 do
begin
FillChar(NCB, SizeOf(NCB), #0);
NCB.ncb_command := NCBRESET;
NCB.ncb_lana_num := Enum.lana[I];
if NetBios(@NCB) = NRC_GOODRET then
begin
FillChar(NCB, SizeOf(NCB), #0);
NCB.ncb_command := NCBASTAT;
NCB.ncb_lana_num := Enum.lana[I];
Move(MachineName[1], NCB.ncb_callname, SizeOf(NCB.ncb_callname));
NCB.ncb_buffer := PChar(@Adapter);
NCB.ncb_length := SizeOf(Adapter);
if NetBios(@NCB) = NRC_GOODRET then
Addresses.Add(AdapterToString(@Adapter.adapt));
end;
end;
end;
end;
procedure GetMacAddressesSnmp;
const
InetMib1 = 'inetmib1.dll';
DunAdapterAddress: array [0..4] of Byte = ($44, $45, $53, $54, $00);
{$IFNDEF FPC // can't resolve address of const }
NullAdapterAddress: array [0..5] of Byte = ($00, $00, $00, $00, $00, $00);
OID_ipMACEntAddr: array [0..9] of UINT = (1, 3, 6, 1, 2, 1, 2, 2, 1, 6);
OID_ifEntryType: array [0..9] of UINT = (1, 3, 6, 1, 2, 1, 2, 2, 1, 3);
OID_ifEntryNum: array [0..7] of UINT = (1, 3, 6, 1, 2, 1, 2, 1);
{$ENDIF ~FPC}
var
PollForTrapEvent: THandle;
SupportedView: PAsnObjectIdentifier;
MIB_ifMACEntAddr: TAsnObjectIdentifier;
MIB_ifEntryType: TAsnObjectIdentifier;
MIB_ifEntryNum: TAsnObjectIdentifier;
VarBindList: TSnmpVarBindList;
VarBind: array [0..1] of TSnmpVarBind;
ErrorStatus, ErrorIndex: TAsnInteger32;
DTmp: Integer;
Ret: Boolean;
MAC: PJclByteArray;
begin
if LoadSnmp then
try
if LoadSnmpExtension(InetMib1) then
try
MIB_ifMACEntAddr.idLength := Length(OID_ipMACEntAddr);
MIB_ifMACEntAddr.ids := @OID_ipMACEntAddr;
MIB_ifEntryType.idLength := Length(OID_ifEntryType);
MIB_ifEntryType.ids := @OID_ifEntryType;
MIB_ifEntryNum.idLength := Length(OID_ifEntryNum);
MIB_ifEntryNum.ids := @OID_ifEntryNum;
if SnmpExtensionInit(GetTickCount, PollForTrapEvent, SupportedView) then
begin
VarBindList.list := @VarBind[0];
VarBind[0].name := DEFINE_NULLOID;
VarBind[1].name := DEFINE_NULLOID;
VarBindList.len := 1;
SnmpUtilOidCpy(@VarBind[0].name, @MIB_ifEntryNum);
Ret := SnmpExtensionQuery(SNMP_PDU_GETNEXT, VarBindList, ErrorStatus, ErrorIndex);
if Ret then
begin
Result := VarBind[0].value.number;
VarBindList.len := 2;
SnmpUtilOidCpy(@VarBind[0].name, @MIB_ifEntryType);
SnmpUtilOidCpy(@VarBind[1].name, @MIB_ifMACEntAddr);
while Ret do
begin
Ret := SnmpExtensionQuery(SNMP_PDU_GETNEXT, VarBindList, ErrorStatus, ErrorIndex);
if Ret then
begin
Ret := SnmpUtilOidNCmp(@VarBind[0].name, @MIB_ifEntryType, MIB_ifEntryType.idLength) = SNMP_ERRORSTATUS_NOERROR;
if Ret then
begin
DTmp := VarBind[0].value.number;
if DTmp = 6 then
begin
Ret := SnmpUtilOidNCmp(@VarBind[1].name, @MIB_ifMACEntAddr, MIB_ifMACEntAddr.idLength) = SNMP_ERRORSTATUS_NOERROR;
if Ret and (VarBind[1].value.address.stream <> nil) then
begin
MAC := PJclByteArray(VarBind[1].value.address.stream);
if not CompareMem(MAC, @NullAdapterAddress, SizeOf(NullAdapterAddress)) then
Addresses.Add(AdapterToString(MAC));
end;
end;
end;
end;
end;
end;
SnmpUtilVarBindFree(@VarBind[0]);
SnmpUtilVarBindFree(@VarBind[1]);
end;
finally
UnloadSnmpExtension;
end;
finally
UnloadSnmp;
end;
end;
begin
Result := -1;
Addresses.BeginUpdate;
try
Addresses.Clear;
GetMacAddressesNetBios;
if (Result <= 0) and (Machine = '') then
GetMacAddressesSnmp;
finally
Addresses.EndUpdate;
end;
end;
{$ENDIF MSWINDOWS}
function ReadTimeStampCounter: Int64; assembler;
asm
DW $310F
end;
function GetIntelCacheDescription(const D: Byte): string;
var
I: Integer;
begin
Result := '';
if D <> 0 then
for I := Low(IntelCacheDescription) to High(IntelCacheDescription) do
if IntelCacheDescription[I].D = D then
begin
Result := IntelCacheDescription[I].I;
Break;
end;
// (outchy) added a return value for unknow D value
if Result = '' then
Result := Format(RsIntelUnknownCache,[D]);
end;
procedure GetCpuInfo(var CpuInfo: TCpuInfo);
begin
CpuInfo := CPUID;
CpuInfo.IsFDIVOK := TestFDIVInstruction;
if CpuInfo.HasInstruction then
begin
{$IFDEF MSWINDOWS}
if (CpuInfo.Features and TSC_FLAG) = TSC_FLAG then
GetCpuSpeed(CpuInfo.FrequencyInfo);
{$ENDIF MSWINDOWS}
end;
end;
function RoundFrequency(const Frequency: Integer): Integer;
const
NF: array [0..8] of Integer = (0, 20, 33, 50, 60, 66, 80, 90, 100);
var
Freq, RF: Integer;
I: Byte;
Hi, Lo: Byte;
begin
RF := 0;
Freq := Frequency mod 100;
for I := 0 to 8 do
begin
if Freq < NF[I] then
begin
Hi := I;
Lo := I - 1;
if (NF[Hi] - Freq) > (Freq - NF[Lo]) then
RF := NF[Lo] - Freq
else
RF := NF[Hi] - Freq;
Break;
end;
end;
Result := Frequency + RF;
end;
function GetCPUSpeed(var CpuSpeed: TFreqInfo): Boolean;
{$IFDEF UNIX}
begin
{ TODO : GetCPUSpeed: Solution for Linux }
Result := False;
end;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
var
T0, T1: Int64;
CountFreq: Int64;
Freq, Freq2, Freq3, Total: Int64;
TotalCycles, Cycles: Int64;
Stamp0, Stamp1: Int64;
TotalTicks, Ticks: Double;
Tries, Priority: Integer;
Thread: THandle;
begin
Stamp0 := 0;
Stamp1 := 0;
Freq := 0;
Freq2 := 0;
Freq3 := 0;
Tries := 0;
TotalCycles := 0;
TotalTicks := 0;
Total := 0;
Thread := GetCurrentThread();
Result := QueryPerformanceFrequency(CountFreq);
if Result then
begin
while ((Tries < 3) or ((Tries < 20) and ((Abs(3 * Freq - Total) > 3) or
(Abs(3 * Freq2 - Total) > 3) or (Abs(3 * Freq3 - Total) > 3)))) do
begin
Inc(Tries);
Freq3 := Freq2;
Freq2 := Freq;
QueryPerformanceCounter(T0);
T1 := T0;
Priority := GetThreadPriority(Thread);
if Priority <> THREAD_PRIORITY_ERROR_RETURN then
SetThreadPriority(Thread, THREAD_PRIORITY_TIME_CRITICAL);
try
while T1 - T0 < 50 do
begin
QueryPerformanceCounter(T1);
Stamp0 := ReadTimeStampCounter;
end;
T0 := T1;
while T1 - T0 < 1000 do
begin
QueryPerformanceCounter(T1);
Stamp1 := ReadTimeStampCounter;
end;
finally
if Priority <> THREAD_PRIORITY_ERROR_RETURN then
SetThreadPriority(Thread, Priority);
end;
Cycles := Stamp1 - Stamp0;
Ticks := T1 - T0;
Ticks := Ticks * 100000;
// avoid division by zero
if CountFreq = 0 then
Ticks := High(Int64)
else
Ticks := Ticks / (CountFreq / 10);
TotalTicks := TotalTicks + Ticks;
TotalCycles := TotalCycles + Cycles;
// avoid division by zero
if Ticks = 0 then
Freq := High(Freq)
else
Freq := Round(Cycles / Ticks);
Total := Freq + Freq2 + Freq3;
end;
// avoid division by zero
if TotalTicks = 0 then
begin
Freq3 := High(Freq3);
Freq2 := High(Freq2);
CpuSpeed.RawFreq := High(CpuSpeed.RawFreq);
end
else
begin
Freq3 := Round((TotalCycles * 10) / TotalTicks); // freq. in multiples of 10^5 Hz
Freq2 := Round((TotalCycles * 100) / TotalTicks); // freq. in multiples of 10^4 Hz
CpuSpeed.RawFreq := Round(TotalCycles / TotalTicks);
end;
CpuSpeed.NormFreq := CpuSpeed.RawFreq;
if Freq2 - (Freq3 * 10) >= 6 then
Inc(Freq3);
Freq := CpuSpeed.RawFreq * 10;
if (Freq3 - Freq) >= 6 then
Inc(CpuSpeed.NormFreq);
CpuSpeed.ExTicks := Round(TotalTicks);
CpuSpeed.InCycles := TotalCycles;
CpuSpeed.NormFreq := RoundFrequency(CpuSpeed.NormFreq);
Result := True;
end;
end;
{$ENDIF MSWINDOWS}
// Helper function for CPUID. Initializes Intel specific fields.
procedure IntelSpecific(var CpuInfo: TCpuInfo);
var
I, J: Integer;
begin
with CpuInfo do
begin
Manufacturer := 'Intel';
if HasCacheInfo then
begin
if (IntelSpecific.L2Cache <> 0) then
begin
L2CacheSize := IntelSpecific.L2Cache shr 16;
L2CacheLineSize := IntelSpecific.L2Cache and $FF;
L2CacheAssociativity := (IntelSpecific.L2Cache shr 12) and $F;
end;
for I := Low(IntelSpecific.CacheDescriptors) to High(IntelSpecific.CacheDescriptors) do
if IntelSpecific.CacheDescriptors[I]<>0 then
for J := Low(IntelCacheDescription) to High(IntelCacheDescription) do
if IntelCacheDescription[J].D = IntelSpecific.CacheDescriptors[I] then
with IntelCacheDescription[J] do
case Family of
//cfInstructionTLB :
//cfDataTLB :
cfL1InstructionCache :
begin
Inc(L1InstructionCacheSize,Size);
L1InstructionCacheLineSize := LineSize;
L1InstructionCacheAssociativity := WaysOfAssoc;
end;
cfL1DataCache :
begin
Inc(L1DataCacheSize,Size);
L1DataCacheLineSize := LineSize;
L1DataCacheAssociativity := WaysOfAssoc;
end;
cfL2Cache :
if (IntelSpecific.L2Cache = 0) then
begin
Inc(L2CacheSize,Size);
L2CacheLineSize := LineSize;
L2CacheAssociativity := WaysOfAssoc;
end;
cfL3Cache :
begin
Inc(L3CacheSize,Size);
L3CacheLineSize := LineSize;
L3CacheAssociativity := WaysOfAssoc;
L3LinesPerSector := LinePerSector;
end;
//cfTrace : // no numeric informations
//cfOther :
end;
end;
if not HasExtendedInfo then
begin
case Family of
4:
case Model of
1:
CpuName := 'Intel 486DX Processor';
2:
CpuName := 'Intel 486SX Processor';
3:
CpuName := 'Intel DX2 Processor';
4:
CpuName := 'Intel 486 Processor';
5:
CpuName := 'Intel SX2 Processor';
7:
CpuName := 'Write-Back Enhanced Intel DX2 Processor';
8:
CpuName := 'Intel DX4 Processor';
else
CpuName := 'Intel 486 Processor';
end;
5:
CpuName := 'Pentium';
6:
case Model of
1:
CpuName := 'Pentium Pro';
3:
CpuName := 'Pentium II';
5:
case L2CacheSize of
0:
CpuName := 'Celeron';
1024:
CpuName := 'Pentium II Xeon';
2048:
CpuName := 'Pentium II Xeon';
else
CpuName := 'Pentium II';
end;
6:
case L2CacheSize of
0:
CpuName := 'Celeron';
128:
CpuName := 'Celeron';
else
CpuName := 'Pentium II';
end;
7:
case L2CacheSize of
1024:
CpuName := 'Pentium III Xeon';
2048:
CpuName := 'Pentium III Xeon';
else
CpuName := 'Pentium III';
end;
8:
case IntelSpecific.BrandID of
1:
CpuName := 'Celeron';
2:
CpuName := 'Pentium III';
3:
CpuName := 'Pentium III Xeon';
4:
CpuName := 'Pentium III';
else
CpuName := 'Pentium III';
end;
10:
CpuName := 'Pentium III Xeon';
11:
CpuName := 'Pentium III';
else
StrPCopy(CpuName, Format('P6 (Model %d)', [Model]));
end;
15:
case IntelSpecific.BrandID of
1:
CpuName := 'Celeron';
8:
CpuName := 'Pentium 4';
14:
CpuName := 'Xeon';
else
CpuName := 'Pentium 4';
end;
else
StrPCopy(CpuName, Format('P%d', [Family]));
end;
end;
MMX := (Features and MMX_FLAG) <> 0;
if (Features and SSE_FLAG) <> 0 then
if (Features and SSE2_FLAG) <> 0 then
if (IntelSpecific.ExFeatures and EINTEL_SSE3) <> 0 then
SSE := 3
else
SSE := 2
else
SSE := 1
else
SSE := 0;
Is64Bits := HasExtendedInfo and ((IntelSpecific.Ex64Features and EINTEL64_EM64T)<>0);
end;
end;
// Helper function for CPUID. Initializes Cyrix specific fields.
procedure CyrixSpecific(var CpuInfo: TCpuInfo);
begin
with CpuInfo do
begin
Manufacturer := 'Cyrix';
if not HasExtendedInfo then
begin
case Family of
4:
CpuName := 'Cyrix MediaGX';
5:
case Model of
2:
CpuName := 'Cyrix 6x86';
4:
CpuName := 'Cyrix GXm';
end;
6:
CpuName := '6x86MX';
else
StrPCopy(CpuName, Format('%dx86', [Family]));
end;
end;
end;
end;
// Helper function for CPUID. Initializes AMD specific fields.
resourcestring
RsUnknownAMDModel = 'Unknown AMD (Model %d)';
procedure AMDSpecific(var CpuInfo: TCpuInfo);
begin
with CpuInfo do
begin
Manufacturer := 'AMD';
if not HasExtendedInfo then
begin
case Family of
4:
CpuName := 'Am486(R) or Am5x86';
5:
case Model of
0:
CpuName := 'AMD-K5 (Model 0)';
1:
CpuName := 'AMD-K5 (Model 1)';
2:
CpuName := 'AMD-K5 (Model 2)';
3:
CpuName := 'AMD-K5 (Model 3)';
6:
CpuName := 'AMD-K6® (Model 6)';
7:
CpuName := 'AMD-K6® (Model 7)';
8:
CpuName := 'AMD-K6®-2 (Model 8)';
9:
CpuName := 'AMD-K6®-III (Model 9)';
else
StrFmt(CpuName,PChar(RsUnknownAMDModel),[Model]);
end;
6:
case Model of
1:
CpuName := 'AMD Athlon™ (Model 1)';
2:
CpuName := 'AMD Athlon™ (Model 2)';
3:
CpuName := 'AMD Duron™ (Model 3)';
4:
CpuName := 'AMD Athlon™ (Model 4)';
6:
CpuName := 'AMD Athlon™ XP (Model 6)';
7:
CpuName := 'AMD Duron™ (Model 7)';
8:
CpuName := 'AMD Athlon™ XP (Model 8)';
10:
CpuName := 'AMD Athlon™ XP (Model 10)';
else
StrFmt(CpuName,PChar(RsUnknownAMDModel),[Model]);
end;
8:
else
CpuName := 'Unknown AMD Chip';
end;
end;
if (HasCacheInfo) then
begin
L1DataCacheSize := AMDSpecific.L1DataCache[ciSize];
L1DataCacheLineSize := AMDSpecific.L1DataCache[ciLineSize];
L1DataCacheAssociativity := AMDSpecific.L1DataCache[ciAssociativity];
L1InstructionCacheSize := AMDSpecific.L1InstructionCache[ciSize];
L1InstructionCacheLineSize := AMDSpecific.L1InstructionCache[ciLineSize];
L1InstructionCacheAssociativity := AMDSpecific.L1InstructionCache[ciAssociativity];
L2CacheLineSize := AMDSpecific.L2Cache and $FF;
L2CacheAssociativity := (AMDSpecific.L2Cache shr 12) and $F;
L2CacheSize := AMDSpecific.L2Cache shr 16;
end;
MMX := (Features and AMD_MMX) <> 0;
ExMMX := HasExtendedInfo and ((AMDSpecific.ExFeatures and EAMD_EXMMX) <> 0);
_3DNow := HasExtendedInfo and ((AMDSpecific.ExFeatures and EAMD_3DNOW) <> 0);
Ex3DNow := HasExtendedInfo and ((AMDSpecific.ExFeatures and EAMD_EX3DNOW) <> 0);
if (Features and AMD_SSE) <> 0 then
if (Features and AMD_SSE2) <> 0 then
SSE := 2
else
SSE := 1
else
SSE := 0;
Is64Bits := HasExtendedInfo and ((AMDSpecific.ExFeatures and EAMD_LONG) <> 0);
end;
end;
// Helper function for CPUID. Initializes Transmeta specific fields.
procedure TransmetaSpecific(var CpuInfo: TCpuInfo);
begin
with CpuInfo do
begin
Manufacturer := 'Transmeta';
if not HasExtendedInfo then
CpuName := 'Crusoe';
if HasCacheInfo then
begin
L1DataCacheSize := TransmetaSpecific.L1DataCache[ciSize];
L1DataCacheLineSize := TransmetaSpecific.L1DataCache[ciLineSize];
L1DataCacheAssociativity := TransmetaSpecific.L1DataCache[ciAssociativity];
L1InstructionCacheSize := TransmetaSpecific.L1CodeCache[ciSize];
L1InstructionCacheLineSize := TransmetaSpecific.L1CodeCache[ciLineSize];
L1InstructionCacheAssociativity := TransmetaSpecific.L1CodeCache[ciAssociativity];
L2CacheLineSize := TransmetaSpecific.L2Cache and $FF;
L2CacheAssociativity := (TransmetaSpecific.L2Cache shr 12) and $F;
L2CacheSize := TransmetaSpecific.L2Cache shr 16;
end;
MMX := (Features and TRANSMETA_MMX) <> 0;
end;
end;
// Helper function for CPUID. Initializes Via specific fields.
procedure ViaSpecific(var CpuInfo: TCpuInfo);
begin
with CpuInfo do
begin
Manufacturer := 'Via';
if not HasExtendedInfo then
CpuName := 'C3';
if HasCacheInfo then
begin
L1DataCacheSize := VIASpecific.L1DataCache[ciSize];
L1DataCacheLineSize := VIASpecific.L1DataCache[ciLineSize];
L1DataCacheAssociativity := VIASpecific.L1DataCache[ciAssociativity];
L1InstructionCacheSize := VIASpecific.L1InstructionCache[ciSize];
L1InstructionCacheLineSize := VIASpecific.L1InstructionCache[ciLineSize];
L1InstructionCacheAssociativity := VIASpecific.L1InstructionCache[ciAssociativity];
L2CacheLineSize := VIASpecific.L2DataCache and $FF;
L2CacheAssociativity := (VIASpecific.L2DataCache shr 12) and $F;
L2CacheSize := VIASpecific.L2DataCache shr 16;
end;
MMX := (Features and VIA_MMX) <> 0;
if (Features and VIA_SSE) <> 0
then SSE := 1
else SSE := 0;
_3DNow := (Features and VIA_3DNOW) <> 0;
end;
end;
function CPUID: TCpuInfo;
var
CPUInfo: TCpuInfo;
HiVal: Cardinal;
ExHiVal: Cardinal;
TimesToExecute, CurrentLoop: Byte;
begin
FillChar(CPUInfo, sizeof(CPUInfo), 0);
asm
PUSH EAX
PUSH EBP
PUSH EBX
PUSH ECX
PUSH EDI
PUSH EDX
PUSH ESI
{$IFDEF PIC} // position independent code for linux
MOV ESI, EBX // get the GOT placed in ebx
{$ELSE} // PIC
XOR ESI, ESI
{$ENDIF} // PIC
@@Check80486:
MOV [CPUInfo.Family], 4
PUSHFD
POP EAX
MOV ECX, EAX
XOR EAX, 200000H
PUSH EAX
POPFD
PUSHFD
POP EAX
XOR EAX, ECX
JE @@DoneCpuType
@@HasCPUIDInstruction:
MOV [CPUInfo.HasInstruction], 1
MOV EAX, 0
DB 0FH
DB 0A2H
MOV HiVal, EAX
MOV DWORD PTR [CPUInfo.VendorIDString], EBX
MOV DWORD PTR [CPUInfo.VendorIDString + 4], EDX
MOV DWORD PTR [CPUInfo.VendorIDString + 8], ECX
@@CheckIntel:
CMP DWORD PTR [ESI].VendorIDIntel, EBX //'uneG'
JNE @@CheckAMD
CMP DWORD PTR [ESI+4].VendorIDIntel, EDX //'Ieni'
JNE @@CheckAMD
CMP DWORD PTR [ESI+8].VendorIDIntel, ECX //'letn'
JNE @@CheckAMD
MOV [CPUInfo.CpuType], CPU_TYPE_INTEL
JMP @@CheckIntelExtended
@@CheckAMD:
CMP DWORD PTR [ESI].VendorIDAMD, EBX //'htuA'
JNE @@CheckCyrix
CMP DWORD PTR [ESI+4].VendorIDAMD, EDX //'itne'
JNE @@CheckCyrix
CMP DWORD PTR [ESI+8].VendorIDAMD, ECX //'DMAc'
JNE @@CheckCyrix
MOV [CPUInfo.CpuType], CPU_TYPE_AMD
JMP @@CheckAMDExtended
@@CheckCyrix:
CMP DWORD PTR [ESI].VendorIDCyrix, EBX //'iryC'
JNE @@CheckVIA
CMP DWORD PTR [ESI+4].VendorIDCyrix, EDX //'snIx'
JNE @@CheckVIA
CMP DWORD PTR [ESI+8].VendorIDCyrix, ECX //'daet'
JNE @@CheckVIA
MOV [CPUInfo.CpuType], CPU_TYPE_CYRIX
JMP @@CheckCyrixExtended
@@CheckVIA:
CMP DWORD PTR [ESI].VendorIDVIA, EBX //'tneC'
JNE @@CheckTransmeta
CMP DWORD PTR [ESI+4].VendorIDVIA, EDX //'Hrua'
JNE @@CheckTransmeta
CMP DWORD PTR [ESI+8].VendorIDVIA, ECX //'slua'
JNE @@CheckTransmeta
MOV [CPUInfo.CpuType], CPU_TYPE_VIA
JMP @@CheckVIAExtended
@@CheckTransmeta:
CMP DWORD PTR [ESI].VendorIDTransmeta, EBX //'uneG'
JNE @@StandardFunctions
CMP DWORD PTR [ESI+4].VendorIDTransmeta, EDX //'Teni'
JNE @@StandardFunctions
CMP DWORD PTR [ESI+8].VendorIDTransmeta, ECX //'68xM'
JNE @@StandardFunctions
MOV [CPUInfo.CpuType], CPU_TYPE_TRANSMETA
JMP @@CheckTransmetaExtended
@@CheckIntelExtended:
MOV EAX, 80000000h
DB 0Fh
DB 0A2h
TEST EAX, 80000000h
JZ @@StandardFunctions
JMP @@IntelOnly
@@CheckAMDExtended:
MOV EAX, 1
CMP HiVal, 1
JL @@StandardFunctions
DB 0Fh
DB 0A2h
MOV [CpuInfo.Features], EDX
MOV EAX, 80000000h
DB 0Fh
DB 0A2h
CMP EAX, 0
JE @@StandardFunctions
JMP @@AMDOnly
@@CheckCyrixExtended:
MOV EAX, 80000000h
DB 0Fh
DB 0A2h
CMP EAX, 0
JE @@StandardFunctions
JMP @@CyrixOnly
@@CheckVIAExtended:
MOV EAX, 80000000h
DB 0Fh
DB 0A2h
CMP EAX, 0
JE @@StandardFunctions
JMP @@VIAOnly
@@CheckTransmetaExtended:
JMP @@TransmetaOnly
@@StandardFunctions:
CMP HiVal, 1
JL @@DoneCPUType
MOV EAX, 1
DB 0FH
DB 0A2H
MOV [CPUInfo.Features], EDX
MOV [CPUInfo.IntelSpecific.BrandID], BL
MOV EBX, EAX
AND EAX, 3000H
SHR EAX, 12
MOV [CPUInfo.PType], AL
MOV EAX, EBX
AND EAX, 0F00H
SHR EAX, 8
MOV [CPUInfo.Family], AL
MOV EAX, EBX
AND EAX, 00F0H
SHR EAX, 4
MOV [CPUInfo.MODEL], AL
MOV EAX, EBX
AND EAX, 000FH
MOV [CPUInfo.Stepping], AL
CMP [CpuInfo.CpuType], CPU_TYPE_INTEL
JNE @@DoneCPUType
MOV [CPUInfo.IntelSpecific.ExFeatures], ECX // (outchy) added extended features for intel processors
@@IntelStandard:
CMP HiVal, 2
JL @@DoneCPUType
MOV CurrentLoop, 0
MOV [CPUInfo.HasCacheInfo], 1
PUSH ECX
@@RepeatCacheQuery:
POP ECX
MOV EAX, 2
DB 0FH
DB 0A2H
INC CurrentLoop
CMP CurrentLoop, 1
JNE @@DoneCacheQuery
MOV TimesToExecute, AL
CMP AL, 0
JE @@DoneCPUType
@@DoneCacheQuery:
PUSH ECX
MOV CL, CurrentLoop
SUB CL, TimesToExecute
JNZ @@RepeatCacheQuery
POP ECX
MOV DWORD PTR [CPUInfo.IntelSpecific.CacheDescriptors], EAX
MOV DWORD PTR [CPUInfo.IntelSpecific.CacheDescriptors + 4], EBX
MOV DWORD PTR [CPUInfo.IntelSpecific.CacheDescriptors + 8], ECX
MOV DWORD PTR [CPUInfo.IntelSpecific.CacheDescriptors + 12], EDX
JMP @@DoneCPUType
@@IntelOnly:
MOV ExHiVal, EAX
MOV EAX, 80000001h
CMP ExHiVal, EAX
JL @@StandardFunctions
MOV [CPUInfo.HasExtendedInfo], 1
DB 0Fh
DB 0A2h
MOV [CPUInfo.IntelSpecific.Ex64Features], EDX
MOV EAX, 80000002h
CMP ExHiVal, EAX
JL @@StandardFunctions
MOV [CPUInfo.HasExtendedInfo], 1
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName], EAX
MOV DWORD PTR [CPUInfo.CpuName + 4], EBX
MOV DWORD PTR [CPUInfo.CpuName + 8], ECX
MOV DWORD PTR [CPUInfo.CpuName + 12], EDX
MOV EAX, 80000003h
CMP ExHiVal, EAX
JL @@StandardFunctions
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName + 16], EAX
MOV DWORD PTR [CPUInfo.CpuName + 20], EBX
MOV DWORD PTR [CPUInfo.CpuName + 24], ECX
MOV DWORD PTR [CPUInfo.CpuName + 28], EDX
MOV EAX, 80000004h
CMP ExHiVal, EAX
JL @@StandardFunctions
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName + 32], EAX
MOV DWORD PTR [CPUInfo.CpuName + 36], EBX
MOV DWORD PTR [CPUInfo.CpuName + 40], ECX
MOV DWORD PTR [CPUInfo.CpuName + 44], EDX
MOV EAX, 80000006h
CMP ExHiVal, EAX
JL @@StandardFunctions
DB 0Fh
DB 0A2h
MOV [CPUInfo.IntelSpecific.L2Cache], EDX
JMP @@StandardFunctions
@@AMDOnly:
MOV ExHiVal, EAX
MOV EAX, 80000001h
CMP ExHiVal, EAX
JL @@DoneCPUType
MOV [CPUInfo.HasExtendedInfo], 1
DB 0Fh
DB 0A2h
MOV ECX, EAX
//AND EAX, 0F000H
//SHR EAX, 12
//MOV [CPUInfo.PType], AL // (outchy) AMD processors don't support ProcessorType
//MOV EAX, ECX
AND EAX, 00000F00h
SHR EAX, 8
MOV [CPUInfo.Family], AL
MOV EAX, ECX
AND EAX, 0FF00000h
SHR EAX, 20
MOV [CpuInfo.ExtendedFamily], AL
MOV EAX, ECX
AND EAX, 000000F0h
SHR EAX, 4
MOV [CPUInfo.Model], AL
MOV EAX, ECX
AND EAX, 000F0000h
SHR EAX, 16
MOV [CpuInfo.ExtendedModel], AL
MOV EAX, ECX
AND EAX, 000FH
MOV [CPUInfo.Stepping], AL
MOV [CPUInfo.AMDSpecific.ExFeatures], EDX
MOV EAX, 80000002h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName], EAX
MOV DWORD PTR [CPUInfo.CpuName + 4], EBX
MOV DWORD PTR [CPUInfo.CpuName + 8], ECX
MOV DWORD PTR [CPUInfo.CpuName + 12], EDX
MOV EAX, 80000003h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName + 16], EAX
MOV DWORD PTR [CPUInfo.CpuName + 20], EBX
MOV DWORD PTR [CPUInfo.CpuName + 24], ECX
MOV DWORD PTR [CPUInfo.CpuName + 28], EDX
MOV EAX, 80000004h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName + 32], EAX
MOV DWORD PTR [CPUInfo.CpuName + 36], EBX
MOV DWORD PTR [CPUInfo.CpuName + 40], ECX
MOV DWORD PTR [CPUInfo.CpuName + 44], EDX
MOV EAX, 80000005h
CMP ExHiVal, EAX
JL @@DoneCPUType
MOV [CPUInfo.HasCacheInfo], 1
DB 0Fh
DB 0A2h
MOV [CPUInfo.AMDSpecific.MByteInstructionTLB], AX
SHR EAX, 16
MOV [CPUInfo.AMDSpecific.MByteDataTLB], AX
MOV [CPUInfo.AMDSpecific.KByteInstructionTLB], BX
SHR EBX, 16
MOV [CPUInfo.AMDSpecific.KByteDataTLB], BX
MOV [CPUInfo.AMDSpecific.L1DataCache], ECX
MOV [CPUInfo.AMDSpecific.L1InstructionCache], EDX
MOV EAX, 80000006h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV [CpuInfo.AMDSpecific.L2MByteInstructionTLB], AX
SHR EAX, 16
MOV [CpuInfo.AMDSpecific.L2MByteDataTLB], AX
MOV [CpuInfo.AMDSpecific.L2KByteInstructionTLB], BX
SHR EBX, 16
MOV [CpuInfo.AMDSpecific.L2KByteDataTLB], BX
MOV [CpuInfo.AMDSpecific.L2Cache], ECX
MOV EAX, 80000007h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV [CpuInfo.AMDSpecific.AdvancedPowerManagement], EDX
MOV EAX, 80000008h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV [CPUInfo.AMDSpecific.PhysicalAddressSize], AL
MOV [CPUInfo.AMDSpecific.VirtualAddressSize], AH
JMP @@DoneCPUType
@@CyrixOnly:
MOV ExHiVal, EAX
MOV EAX, 80000001h
CMP ExHiVal, EAX
JL @@DoneCPUType
MOV [CPUInfo.HasExtendedInfo], 1
DB 0Fh
DB 0A2h
MOV ECX, EAX
AND EAX, 0F000H
SHR EAX, 12
MOV [CPUInfo.PType], AL
MOV EAX, ECX
AND EAX, 0F00H
SHR EAX, 8
MOV [CPUInfo.Family], AL
MOV EAX, ECX
AND EAX, 00F0H
SHR EAX, 4
MOV [CPUInfo.Model], AL
MOV EAX, ECX
AND EAX, 000FH
MOV [CPUInfo.Stepping], AL
MOV [CPUInfo.Features], EDX
MOV EAX, 80000002h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName], EAX
MOV DWORD PTR [CPUInfo.CpuName + 4], EBX
MOV DWORD PTR [CPUInfo.CpuName + 8], ECX
MOV DWORD PTR [CPUInfo.CpuName + 12], EDX
MOV EAX, 80000003h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName + 16], EAX
MOV DWORD PTR [CPUInfo.CpuName + 20], EBX
MOV DWORD PTR [CPUInfo.CpuName + 24], ECX
MOV DWORD PTR [CPUInfo.CpuName + 28], EDX
MOV EAX, 80000004h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName + 32], EAX
MOV DWORD PTR [CPUInfo.CpuName + 36], EBX
MOV DWORD PTR [CPUInfo.CpuName + 40], ECX
MOV DWORD PTR [CPUInfo.CpuName + 44], EDX
MOV EAX, 80000005h
CMP ExHiVal, EAX
JL @@DoneCPUType
MOV [CPUInfo.HasCacheInfo], 1
DB 0Fh
DB 0A2h
MOV [CPUInfo.CyrixSpecific.TLBInfo], EBX
MOV [CPUInfo.CyrixSpecific.L1CacheInfo], ECX
JMP @@DoneCPUType
@@VIAOnly:
MOV ExHiVal, EAX
MOV EAX, 80000001h
CMP ExHiVal, EAX
JL @@VIAExtended
MOV [CPUInfo.HasExtendedInfo], 1
DB 0Fh
DB 0A2h
MOV [CpuInfo.Features], EDX
MOV ECX, EAX
AND EAX, 000Fh
MOV [CpuInfo.Stepping], AL
MOV EAX, ECX
AND EAX, 00F0h
MOV [CpuInfo.Model], AL
MOV EAX, ECX
AND EAX, 0F00h
MOV [CpuInfo.Family], AL
MOV EAX, ECX
AND EAX, 3000h
MOV [CpuInfo.Stepping], AL
MOV EAX, 80000002h
CMP ExHiVal, EAX
JL @@VIAExtended
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName], EAX
MOV DWORD PTR [CPUInfo.CpuName + 4], EBX
MOV DWORD PTR [CPUInfo.CpuName + 8], ECX
MOV DWORD PTR [CPUInfo.CpuName + 12], EDX
MOV EAX, 80000003h
CMP ExHiVal, EAX
JL @@VIAExtended
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName + 16], EAX
MOV DWORD PTR [CPUInfo.CpuName + 20], EBX
MOV DWORD PTR [CPUInfo.CpuName + 24], ECX
MOV DWORD PTR [CPUInfo.CpuName + 28], EDX
MOV EAX, 80000004h
CMP ExHiVal, EAX
JL @@VIAExtended
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName + 32], EAX
MOV DWORD PTR [CPUInfo.CpuName + 36], EBX
MOV DWORD PTR [CPUInfo.CpuName + 40], ECX
MOV DWORD PTR [CPUInfo.CpuName + 44], EDX
MOV EAX, 80000005h
CMP ExHiVal, EAX
JL @@VIAExtended
DB 0Fh
DB 0A2h
MOV [CPUInfo.VIASpecific.InstructionTLB], BX
SHR EBX, 16
MOV [CPUInfo.VIASpecific.DataTLB], BX
MOV [CPUInfo.VIASpecific.L1DataCache], ECX
MOV [CPUInfo.VIASpecific.L1InstructionCache], EDX
MOV [CPUInfo.HasCacheInfo], 1
MOV EAX, 80000006h
CMP ExHiVal, EAX
JL @@VIAExtended
DB 0Fh
DB 0A2h
MOV [CPUInfo.VIASpecific.L2DataCache], ECX
@@VIAExtended:
MOV EAX, 0C0000000h
DB 0Fh
DB 0A2h
CMP EAX, 0
JE @@DoneCpuType
MOV ExHiVal, EAX
MOV EAX, 0C0000001h
CMP ExHiVal, EAX
JL @@DoneCpuType
DB 0Fh
DB 0A2h
MOV [CPUInfo.VIASpecific.ExFeatures], EDX
JMP @@DoneCpuType
@@TransmetaOnly:
MOV EAX, 1
CMP HiVal, EAX
JL @@TransmetaExtended1
DB 0Fh
DB 0A2h
MOV [CpuInfo.Features], EDX
MOV EBX, EAX
AND EAX, 3000H
SHR EAX, 12
MOV [CPUInfo.PType], AL
MOV EAX, EBX
AND EAX, 0F00H
SHR EAX, 8
MOV [CPUInfo.Family], AL
MOV EAX, EBX
AND EAX, 00F0H
SHR EAX, 4
MOV [CPUInfo.MODEL], AL
MOV EAX, EBX
AND EAX, 000FH
MOV [CPUInfo.Stepping], AL
// no information when eax is 2
// eax is 3 means Serial Number, not detected there
@@TransmetaExtended1:
MOV EAX, 80000000h
DB 0Fh
DB 0A2h
CMP EAX, 0
JE @@TransmetaExtended2
MOV ExHiVal, EAX
MOV [CPUInfo.HasExtendedInfo], 1
MOV DWORD PTR [CPUInfo.CpuName], EBX // small CPU description, overriden if ExHiVal >=80000004
MOV DWORD PTR [CPUInfo.CpuName + 4], EDX
MOV DWORD PTR [CPUInfo.CpuName + 8], ECX
MOV EAX, 80000001h
CMP ExHiVal, EAX
JL @@TransmetaExtended2
DB 0Fh
DB 0A2h
MOV [CPUInfo.TransmetaSpecific.ExFeatures], EDX
MOV EAX, 80000002h
CMP ExHiVal, EAX
JL @@TransmetaExtended2
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName], EAX // large CPU description
MOV DWORD PTR [CPUInfo.CpuName + 4], EBX
MOV DWORD PTR [CPUInfo.CpuName + 8], ECX
MOV DWORD PTR [CPUInfo.CpuName + 12], EDX
MOV EAX, 80000003h
CMP ExHiVal, EAX
JL @@TransmetaExtended2
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName + 16], EAX
MOV DWORD PTR [CPUInfo.CpuName + 20], EBX
MOV DWORD PTR [CPUInfo.CpuName + 24], ECX
MOV DWORD PTR [CPUInfo.CpuName + 28], EDX
MOV EAX, 80000004h
CMP ExHiVal, EAX
JL @@TransmetaExtended2
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.CpuName + 32], EAX
MOV DWORD PTR [CPUInfo.CpuName + 36], EBX
MOV DWORD PTR [CPUInfo.CpuName + 40], ECX
MOV DWORD PTR [CPUInfo.CpuName + 44], EDX
MOV EAX, 80000005h
CMP ExHiVal, EAX
JL @@TransmetaExtended2
DB 0Fh
DB 0A2h
MOV [CPUInfo.HasCacheInfo], 1
MOV [CPUInfo.TransmetaSpecific.CodeTLB], BX
SHR EBX, 16
MOV [CPUInfo.TransmetaSpecific.DataTLB], BX
MOV [CPUInfo.TransmetaSpecific.L1DataCache], ECX
MOV [CPUInfo.TransmetaSpecific.L1CodeCache], EDX
MOV EAX, 80000006h
CMP ExHiVal, EAX
JL @@TransmetaExtended2
DB 0Fh
DB 0A2h
MOV [CPUInfo.TransmetaSpecific.L2Cache], ECX
@@TransmetaExtended2:
MOV EAX, 80860000h
DB 0Fh
DB 0A2h
CMP EAX, 0
JE @@DoneCPUType
MOV ExHiVal, EAX
MOV EAX, 80860001h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV [CPUInfo.TransmetaSpecific.RevisionABCD], EBX
MOV [CPUInfo.TransmetaSpecific.RevisionXXXX], ECX
MOV [CPUInfo.TransmetaSpecific.TransmetaFeatures], EDX
MOV EAX, 80860002h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV [CPUInfo.TransmetaSpecific.CodeMorphingABCD], EBX
MOV [CPUInfo.TransmetaSpecific.CodeMorphingXXXX], ECX
MOV EAX, 80860003h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations], EAX
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 4], EBX
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 8], ECX
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 12], EDX
MOV EAX, 80860004h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 16], EAX
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 20], EBX
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 24], ECX
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 28], EDX
MOV EAX, 80860005h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 32], EAX
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 36], EBX
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 40], ECX
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 44], EDX
MOV EAX, 80860006h
CMP ExHiVal, EAX
JL @@DoneCPUType
DB 0Fh
DB 0A2h
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 48], EAX
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 52], EBX
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 56], ECX
MOV DWORD PTR [CPUInfo.TransmetaSpecific.TransmetaInformations + 60], EDX
MOV EAX, 80860007h
CMP ExHiVal, EAX
JL @@DoneCPUType
MOV EBX, [CPUInfo.TransmetaSpecific.TransmetaFeatures]
TEST EBX, STRANSMETA_LONGRUN
JZ @@DoneCPUType
DB 0Fh
DB 0A2h
MOV [CPUInfo.TransmetaSpecific.CurrentFrequency], EAX
MOV [CPUInfo.TransmetaSpecific.CurrentVoltage], EBX
MOV [CPUInfo.TransmetaSpecific.CurrentPerformance], ECX
@@DoneCpuType:
POP ESI
POP EDX
POP EDI
POP ECX
POP EBX
POP EBP
POP EAX
end;
case CPUInfo.CpuType of
CPU_TYPE_INTEL : IntelSpecific(CpuInfo);
CPU_TYPE_CYRIX : CyrixSpecific(CpuInfo);
CPU_TYPE_AMD : AMDSpecific(CpuInfo);
CPU_TYPE_TRANSMETA : TransmetaSpecific(CpuInfo);
CPU_TYPE_VIA : ViaSpecific(CpuInfo);
else begin
CpuInfo.Manufacturer := 'Unknown';
CpuInfo.CpuName := 'Unknown';
end;
end;
Result := CPUInfo;
end;
function TestFDIVInstruction: Boolean;
var
TopNum: Double;
BottomNum: Double;
One: Double;
ISOK: Boolean;
begin
// The following code was found in Borlands fdiv.asm file in the
// Delphi 3\Source\RTL\SYS directory, (I made some minor modifications)
// therefore I cannot take credit for it.
TopNum := 2658955;
BottomNum := PI;
One := 1;
asm
PUSH EAX
FLD [TopNum]
FDIV [BottomNum]
FMUL [BottomNum]
FSUBR [TopNum]
FCOMP [One]
FSTSW AX
SHR EAX, 8
AND EAX, 01H
MOV ISOK, AL
POP EAX
end;
Result := ISOK;
end;
//=== Alloc granularity ======================================================
procedure RoundToAllocGranularity64(var Value: Int64; Up: Boolean);
begin
if (Value mod AllocGranularity) <> 0 then
if Up then
Value := ((Value div AllocGranularity) + 1) * AllocGranularity
else
Value := (Value div AllocGranularity) * AllocGranularity;
end;
procedure RoundToAllocGranularityPtr(var Value: Pointer; Up: Boolean);
begin
if (Cardinal(Value) mod AllocGranularity) <> 0 then
if Up then
Value := Pointer(((Cardinal(Value) div AllocGranularity) + 1) * AllocGranularity)
else
Value := Pointer((Cardinal(Value) div AllocGranularity) * AllocGranularity);
end;
//=== Advanced Power Management (APM) ========================================
{$IFDEF MSWINDOWS}
function GetAPMLineStatus: TAPMLineStatus;
var
SystemPowerStatus: TSystemPowerStatus;
begin
Result := alsUnknown;
if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion < 5) then // Windows NT doesn't support GetSystemPowerStatus
Exit; // so we return alsUnknown
if not GetSystemPowerStatus(SystemPowerStatus) then
RaiseLastOSError
else
begin
case SystemPowerStatus.ACLineStatus of
0:
Result := alsOffline;
1:
Result := alsOnline;
255:
Result := alsUnknown;
end;
end;
end;
function GetAPMBatteryFlag: TAPMBatteryFlag;
var
SystemPowerStatus: TSystemPowerStatus;
begin
Result := abfUnknown;
if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion < 5) then // Windows NT doesn't support GetSystemPowerStatus
Exit; // so we return abfUnknown
if not GetSystemPowerStatus(SystemPowerStatus) then
RaiseLastOSError
else
begin
case SystemPowerStatus.BatteryFlag of
1:
Result := abfHigh;
2:
Result := abfLow;
4:
Result := abfCritical;
8:
Result := abfCharging;
128:
Result := abfNoBattery;
255:
Result := abfUnknown;
end;
end;
end;
function GetAPMBatteryFlags: TAPMBatteryFlags;
var
SystemPowerStatus: TSystemPowerStatus;
begin
Result := [];
if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion < 5) then // Windows NT doesn't support GetSystemPowerStatus
begin
Result := [abfUnknown];
Exit; // so we return [abfUnknown]
end;
if not GetSystemPowerStatus(SystemPowerStatus) then
RaiseLastOSError
else
begin
if (SystemPowerStatus.BatteryFlag and 1) <> 0 then
Result := Result + [abfHigh];
if (SystemPowerStatus.BatteryFlag and 2) <> 0 then
Result := Result + [abfLow];
if (SystemPowerStatus.BatteryFlag and 4) <> 0 then
Result := Result + [abfCritical];
if (SystemPowerStatus.BatteryFlag and 8) <> 0 then
Result := Result + [abfCharging];
if (SystemPowerStatus.BatteryFlag and 128) <> 0 then
Result := Result + [abfNoBattery];
if SystemPowerStatus.BatteryFlag = 255 then
Result := Result + [abfUnknown];
end;
end;
function GetAPMBatteryLifePercent: Integer;
var
SystemPowerStatus: TSystemPowerStatus;
begin
Result := 0;
if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion < 5) then // Windows NT doesn't support GetSystemPowerStatus
Exit;
if not GetSystemPowerStatus(SystemPowerStatus) then
RaiseLastOSError
else
Result := SystemPowerStatus.BatteryLifePercent;
end;
function GetAPMBatteryLifeTime: DWORD;
var
SystemPowerStatus: TSystemPowerStatus;
begin
Result := 0;
if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion < 5) then // Windows NT doesn't support GetSystemPowerStatus
Exit;
if not GetSystemPowerStatus(SystemPowerStatus) then
RaiseLastOSError
else
Result := SystemPowerStatus.BatteryLifeTime;
end;
function GetAPMBatteryFullLifeTime: DWORD;
var
SystemPowerStatus: TSystemPowerStatus;
begin
Result := 0;
if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion < 5) then // Windows NT doesn't support GetSystemPowerStatus
Exit;
if not GetSystemPowerStatus(SystemPowerStatus) then
RaiseLastOSError
else
Result := SystemPowerStatus.BatteryFullLifeTime;
end;
//=== Memory Information =====================================================
function GetMaxAppAddress: Cardinal;
var
SystemInfo: TSystemInfo;
begin
FillChar(SystemInfo, SizeOf(SystemInfo), #0);
GetSystemInfo(SystemInfo);
Result := Integer(SystemInfo.lpMaximumApplicationAddress);
end;
function GetMinAppAddress: Cardinal;
var
SystemInfo: TSystemInfo;
begin
FillChar(SystemInfo, SizeOf(SystemInfo), #0);
GetSystemInfo(SystemInfo);
Result := Integer(SystemInfo.lpMinimumApplicationAddress);
end;
{$ENDIF MSWINDOWS}
function GetMemoryLoad: Byte;
{$IFDEF UNIX}
var
SystemInf: TSysInfo ;
begin
SysInfo(SystemInf);
with SystemInf do
Result := 100 - Round(100 * freeram / totalram);
end;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
var
MemoryStatus: TMemoryStatus;
begin
FillChar(MemoryStatus, SizeOf(MemoryStatus), 0);
MemoryStatus.dwLength := SizeOf(MemoryStatus);
GlobalMemoryStatus(MemoryStatus);
Result := MemoryStatus.dwMemoryLoad;
end;
{$ENDIF MSWINDOWS}
function GetSwapFileSize: Cardinal;
{$IFDEF UNIX}
var
SystemInf: TSysInfo;
begin
SysInfo(SystemInf);
Result := SystemInf.totalswap;
end;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
var
MemoryStatus: TMemoryStatus;
begin
FillChar(MemoryStatus, SizeOf(MemoryStatus), 0);
MemoryStatus.dwLength := SizeOf(MemoryStatus);
GlobalMemoryStatus(MemoryStatus);
with MemoryStatus do
Result := dwTotalPageFile - dwAvailPageFile;
end;
{$ENDIF MSWINDOWS}
function GetSwapFileUsage: Byte;
{$IFDEF UNIX}
var
SystemInf: TSysInfo;
begin
SysInfo(SystemInf);
with SystemInf do
Result := 100 - Trunc(100 * FreeSwap / TotalSwap);
end;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
var
MemoryStatus: TMemoryStatus;
begin
FillChar(MemoryStatus, SizeOf(MemoryStatus), 0);
MemoryStatus.dwLength := SizeOf(MemoryStatus);
GlobalMemoryStatus(MemoryStatus);
with MemoryStatus do
if dwTotalPageFile > 0 then
Result := 100 - Trunc(dwAvailPageFile / dwTotalPageFile * 100)
else
Result := 0;
end;
{$ENDIF MSWINDOWS}
function GetTotalPhysicalMemory: Cardinal;
{$IFDEF UNIX}
var
SystemInf: TSysInfo;
begin
SysInfo(SystemInf);
Result := SystemInf.totalram;
end;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
var
MemoryStatus: TMemoryStatus;
begin
FillChar(MemoryStatus, SizeOf(MemoryStatus), 0);
MemoryStatus.dwLength := SizeOf(MemoryStatus);
GlobalMemoryStatus(MemoryStatus);
Result := MemoryStatus.dwTotalPhys;
end;
{$ENDIF MSWINDOWS}
function GetFreePhysicalMemory: Cardinal;
{$IFDEF UNIX}
var
SystemInf: TSysInfo;
begin
SysInfo(SystemInf);
Result := SystemInf.freeram;
end;
{$ENDIF UNIX}
{$IFDEF MSWINDOWS}
var
MemoryStatus: TMemoryStatus;
begin
FillChar(MemoryStatus, SizeOf(MemoryStatus), 0);
MemoryStatus.dwLength := SizeOf(MemoryStatus);
GlobalMemoryStatus(MemoryStatus);
Result := MemoryStatus.dwAvailPhys;
end;
function GetTotalPageFileMemory: Cardinal;
var
MemoryStatus: TMemoryStatus;
begin
FillChar(MemoryStatus, SizeOf(MemoryStatus), 0);
MemoryStatus.dwLength := SizeOf(MemoryStatus);
GlobalMemoryStatus(MemoryStatus);
Result := MemoryStatus.dwTotalPageFile;
end;
function GetFreePageFileMemory: Cardinal;
var
MemoryStatus: TMemoryStatus;
begin
FillChar(MemoryStatus, SizeOf(MemoryStatus), 0);
MemoryStatus.dwLength := SizeOf(MemoryStatus);
GlobalMemoryStatus(MemoryStatus);
Result := MemoryStatus.dwAvailPageFile;
end;
function GetTotalVirtualMemory: Cardinal;
var
MemoryStatus: TMemoryStatus;
begin
FillChar(MemoryStatus, SizeOf(MemoryStatus), 0);
MemoryStatus.dwLength := SizeOf(MemoryStatus);
GlobalMemoryStatus(MemoryStatus);
Result := MemoryStatus.dwTotalVirtual;
end;
function GetFreeVirtualMemory: Cardinal;
var
MemoryStatus: TMemoryStatus;
begin
FillChar(MemoryStatus, SizeOf(MemoryStatus), 0);
MemoryStatus.dwLength := SizeOf(MemoryStatus);
GlobalMemoryStatus(MemoryStatus);
Result := MemoryStatus.dwAvailVirtual;
end;
//=== Keyboard Information ===================================================
function GetKeybStateHelper(VirtualKey: Cardinal; Mask: Byte): Boolean;
var
Keys: TKeyboardState;
begin
Result := GetKeyBoardState(Keys) and (Keys[VirtualKey] and Mask <> 0);
end;
function GetKeyState(const VirtualKey: Cardinal): Boolean;
begin
Result := GetKeybStateHelper(VirtualKey, $80);
end;
function GetNumLockKeyState: Boolean;
begin
Result := GetKeybStateHelper(VK_NUMLOCK, $01);
end;
function GetScrollLockKeyState: Boolean;
begin
Result := GetKeybStateHelper(VK_SCROLL, $01);
end;
function GetCapsLockKeyState: Boolean;
begin
Result := GetKeybStateHelper(VK_CAPITAL, $01);
end;
//=== Windows 95/98/ME system resources information ==========================
{ TODO -oPJH : compare to Win9xFreeSysResources }
var
ResmeterLibHandle: THandle;
MyGetFreeSystemResources: function(ResType: UINT): UINT; stdcall;
procedure UnloadSystemResourcesMeterLib;
begin
if ResmeterLibHandle <> 0 then
begin
FreeLibrary(ResmeterLibHandle);
ResmeterLibHandle := 0;
@MyGetFreeSystemResources := nil;
end;
end;
function IsSystemResourcesMeterPresent: Boolean;
procedure LoadResmeter;
var
OldErrorMode: UINT;
begin
OldErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
try
ResmeterLibHandle := LoadLibrary('rsrc32.dll');
finally
SetErrorMode(OldErrorMode);
end;
if ResmeterLibHandle <> 0 then
begin
@MyGetFreeSystemResources := GetProcAddress(ResmeterLibHandle, '_MyGetFreeSystemResources32@4');
if not Assigned(MyGetFreeSystemResources) then
UnloadSystemResourcesMeterLib;
end;
end;
begin
if not IsWinNT and (ResmeterLibHandle = 0) then
LoadResmeter;
Result := (ResmeterLibHandle <> 0);
end;
function GetFreeSystemResources(const ResourceType: TFreeSysResKind): Integer;
const
ParamValues: array [TFreeSysResKind] of UINT = (0, 1, 2);
begin
if IsSystemResourcesMeterPresent then
Result := MyGetFreeSystemResources(ParamValues[ResourceType])
else
Result := -1;
end;
function GetFreeSystemResources: TFreeSystemResources;
begin
with Result do
begin
SystemRes := GetFreeSystemResources(rtSystem);
GdiRes := GetFreeSystemResources(rtGdi);
UserRes := GetFreeSystemResources(rtUser);
end;
end;
//=== Initialization/Finalization ============================================
procedure InitSysInfo;
var
SystemInfo: TSystemInfo;
Kernel32FileName: string;
VerFixedFileInfo: TVSFixedFileInfo;
begin
{ processor information related initialization }
FillChar(SystemInfo, SizeOf(SystemInfo), 0);
GetSystemInfo(SystemInfo);
ProcessorCount := SystemInfo.dwNumberOfProcessors;
AllocGranularity := SystemInfo.dwAllocationGranularity;
PageSize := SystemInfo.dwPageSize;
{ Windows version information }
IsWinNT := Win32Platform = VER_PLATFORM_WIN32_NT;
Kernel32FileName := GetModulePath(GetModuleHandle(kernel32));
if (not IsWinNT) and VersionFixedFileInfo(Kernel32FileName, VerFixedFileInfo) then
KernelVersionHi := VerFixedFileInfo.dwProductVersionMS
else
KernelVersionHi := 0;
case GetWindowsVersion of
wvUnknown:
;
wvWin95:
IsWin95 := True;
wvWin95OSR2:
IsWin95OSR2 := True;
wvWin98:
IsWin98 := True;
wvWin98SE:
IsWin98SE := True;
wvWinME:
IsWinME := True;
wvWinNT31:
begin
IsWinNT3 := True;
IsWinNT31 := True;
end;
wvWinNT35:
begin
IsWinNT3 := True;
IsWinNT35 := True;
end;
wvWinNT351:
begin
IsWinNT3 := True;
IsWinNT35 := True;
IsWinNT351 := True;
end;
wvWinNT4:
IsWinNT4 := True;
wvWin2000:
IsWin2K := True;
wvWinXP:
IsWinXP := True;
wvWin2003:
IsWin2003 := True;
wvWinXP64:
IsWinXP64 := True;
wvWin2003R2:
IsWin2003R2 := True;
wvWinVista:
IsWinVista := True;
wvWinLonghorn:
IsWinLonghorn := True;
end;
end;
procedure FinalizeSysInfo;
begin
UnloadSystemResourcesMeterLib;
end;
initialization
InitSysInfo;
finalization
FinalizeSysInfo;
{$ENDIF MSWINDOWS}
{$ENDIF ~CLR}
// History:
// $Log: JclSysInfo.pas,v $
// Revision 1.56 2005/12/12 21:54:09 outchy
// HWND changed to THandle (linking problems with BCB).
//
// Revision 1.55 2005/11/22 08:37:59 obones
// Added missing EXTERNALSYM declarations
//
// Revision 1.54 2005/11/21 11:50:22 outchy
// Detection of Windows Vista/Longhorn/2003 R2/XP 64.
// From: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/getting_the_system_version.asp
//
// Revision 1.53 2005/10/30 01:51:27 rrossmair
// - introduce KEEP_DEPRECATED as alias for ~DROP_OBSOLETE_CODE
// - some style cleaning
//
// Revision 1.52 2005/09/28 23:27:50 outchy
// Added constant of bits of the MXCSR register.
//
// Revision 1.51 2005/08/09 10:30:22 ahuser
// JCL.NET changes
//
// Revision 1.50 2005/08/09 07:39:28 marquardt
// forgot to compile last (bad) changes
//
// Revision 1.49 2005/08/09 07:35:42 marquardt
// minor style fix
//
// Revision 1.48 2005/08/08 07:02:56 marquardt
// minor style fix
//
// Revision 1.47 2005/08/07 13:09:55 outchy
// Changed PByteArray to PJclByteArray to avoid RangeCheck exceptions.
//
// Revision 1.46 2005/07/03 19:29:27 ahuser
// Fixed another CLR IFDEFs bug
//
// Revision 1.45 2005/07/02 18:40:19 ahuser
// Fixed IFDEFs
//
// Revision 1.44 2005/05/23 19:19:17 outchy
// IT2974: Memory sizes should be cardinal values (not Integer values).
//
// Revision 1.43 2005/05/05 20:08:45 ahuser
// JCL.NET support
//
// Revision 1.42 2005/04/07 00:41:35 rrossmair
// - changed for FPC 1.9.8
//
// Revision 1.41 2005/03/12 01:32:50 outchy
// Update of the CPUID function. New processors detection, constants reworked and specifications upgraded.
//
// Revision 1.40 2005/03/08 08:33:17 marquardt
// overhaul of exceptions and resourcestrings, minor style cleaning
//
// Revision 1.39 2005/03/03 15:35:59 rikbarker
// Windows 2003 Fix for NTProductType and GetWindowsServicePackVersion
//
// Revision 1.38 2005/02/24 16:34:40 marquardt
// remove divider lines, add section lines (unfinished)
//
// Revision 1.37 2005/02/24 07:36:24 marquardt
// resolved the compiler warnings, style cleanup, removed code from JclContainerIntf.pas
//
// Revision 1.36 2005/02/20 04:37:09 rrossmair
// - added GetIPAddress() and GetIPAddresses() for Unix
//
// Revision 1.35 2004/12/19 20:16:31 rrossmair
// - added TCpuInfo improvements by Florent Ouchet
//
// Revision 1.34 2004/12/07 02:40:07 rrossmair
// - added GetVolumeFileSystemFlags function
//
// Revision 1.33 2004/10/21 08:40:10 marquardt
// style cleaning
//
// Revision 1.32 2004/10/17 23:48:22 mthoma
// Removed contributions... Reintroduced orignal GetOpenGLVersion.
//
// Revision 1.31 2004/10/17 20:25:21 mthoma
// style cleaning, adjusting contributors
//
// Revision 1.30 2004/10/10 12:52:12 marquardt
// DestroyEnvironmentBlock introduced
//
// Revision 1.29 2004/08/04 09:05:51 marquardt
// forgot to export SetGlobalEnvironmentVariable
//
// Revision 1.28 2004/08/04 06:11:49 marquardt
// added SetGlobalEnvironmentVariable
//
// Revision 1.27 2004/08/03 07:22:37 marquardt
// resourcestring cleanup
//
// Revision 1.26 2004/07/31 06:21:01 marquardt
// fixing TStringLists, adding BeginUpdate/EndUpdate, finalization improved
//
// Revision 1.25 2004/07/28 18:00:51 marquardt
// various style cleanings, some minor fixes
//
// Revision 1.24 2004/07/16 04:11:46 rrossmair
// fixed RunningProcessesList for Win2003
//
// Revision 1.23 2004/06/16 07:30:28 marquardt
// added tilde to all IFNDEF ENDIFs, inherited qualified
//
// Revision 1.22 2004/06/14 13:05:18 marquardt
// style cleaning ENDIF, Tabs
//
// Revision 1.21 2004/06/14 06:24:52 marquardt
// style cleaning IFDEF
//
// Revision 1.20 2004/06/02 03:23:46 rrossmair
// cosmetic changes in several units (code formatting, help TODOs processed etc.)
//
// Revision 1.19 2004/05/08 08:44:17 rrossmair
// introduced & applied symbol HAS_UNIT_LIBC
//
// Revision 1.18 2004/05/05 07:12:03 rrossmair
// changes for FPC compatibility
//
// Revision 1.17 2004/05/05 00:15:12 mthoma
// Updated headers: Added donors as contributors, adjusted the initial authors, added cvs names when they were not obvious. Changed $data to $date where necessary,
//
// Windows NT 4 and earlier do not support GetSystemPowerStatus. Modified the APM function accordingly.
//
// Revision 1.16 2004/04/19 06:14:43 rrossmair
// Help TODOs done
//
// Revision 1.15 2004/04/18 19:57:29
// - rename one of the GetOpenGLVersion to GetOpenGLVersionBitmapRendering
// - delete pre-loading of Glu32Handle
// - move the OpenGl32Handle call to directly before ChoosePixelFormat
//
// Revision 1.14 2004/04/18 05:14:11 rrossmair
// fixed GetOpenGLVersion (draw to bitmap overload); removed VCL dependency ("uses Graphics")
//
// Revision 1.13 2004/04/18 00:43:19
// modify und bugfix GetOpenGLVersion, add second function for bitmap rendering
//
// Revision 1.12 2004/04/09 15:05:09 mthoma
// Added new function GetAPMBatteryFlags.
//
// Revision 1.11 2004/04/07 13:55:09 peter3
// - var params cannot be passed by adress
//
// Revision 1.10 2004/04/07 07:33:39 marquardt
// fixes for GetVersionEx
//
// Revision 1.9 2004/04/06 04:53:18
// adapt compiler conditions, add log entry
//
end.