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

5319 lines
182 KiB
ObjectPascal
Raw Blame History

{**************************************************************************************************}
{ }
{ 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 }
{ Andre 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 Thornquist (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: 2007-06-16 20:31:47 +0200 (sam., 16 juin 2007) $
// 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 UNITVERSIONING}
JclUnitVersioning,
{$ENDIF UNITVERSIONING}
{$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, ActiveX,
{$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}
{$IFNDEF FPC}
function GetCommonDocumentsFolder: string;
{$ENDIF ~FPC}
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, wvWinServer2008);
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;
IsWinServer2008: 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;
FlushLineSize: Byte;
APICID: Byte;
ExFeatures: Cardinal;
Ex64Features: Cardinal;
Ex64Features2: Cardinal;
PhysicalAddressBits: Byte;
VirtualAddressBits: Byte;
end;
TCyrixSpecific = record
L1CacheInfo: array [0..3] of Byte;
TLBInfo: array [0..3] of Byte;
end;
TAMDSpecific = packed record
ExFeatures: Cardinal;
ExFeatures2: Cardinal;
Features2: Cardinal;
BrandID: Byte;
FlushLineSize: Byte;
APICID: Byte;
ExBrandID: Word;
// do not split L1 MByte TLB
L1MByteInstructionTLB: array [TTLBInformation] of Byte;
L1MByteDataTLB: array [TTLBInformation] of Byte;
// do not split L1 KByte TLB
L1KByteInstructionTLB: array [TTLBInformation] of Byte;
L1KByteDataTLB: array [TTLBInformation] of Byte;
L1DataCache: array [TCacheInformation] of Byte;
L1InstructionCache: array [TCacheInformation] of Byte;
// do not split L2 MByte TLB
L2MByteInstructionTLB: array [TTLBInformation] of Byte; // L2 TLB for 2-MByte and 4-MByte pages
L2MByteDataTLB: array [TTLBInformation] of Byte; // L2 TLB for 2-MByte and 4-MByte pages
// do not split L2 KByte TLB
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;
DEPCapable: 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;
LogicalCore: Byte;
PhysicalCore: Byte;
HyperThreadingTechnology: Boolean;
// 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_VMX = BIT_5; // Virtual Machine Technology
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_SSSE3 = BIT_9; // SSSE 3 extensions
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_CMPXCHG16B = BIT_13; // CMPXCHG16B instruction
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_EDB = BIT_20; // Execute Disable Bit
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
{ Extended Intel 64 Bits Feature Flags continued }
EINTEL64_2_LAHF = BIT_0; // LAHF/SAHF available in 64 bit mode
EINTEL64_2_BIT_1 = BIT_1; // Reserved, do not count on value
EINTEL64_2_BIT_2 = BIT_2; // Reserved, do not count on value
EINTEL64_2_BIT_3 = BIT_3; // Reserved, do not count on value
EINTEL64_2_BIT_4 = BIT_4; // Reserved, do not count on value
EINTEL64_2_BIT_5 = BIT_5; // Reserved, do not count on value
EINTEL64_2_BIT_6 = BIT_6; // Reserved, do not count on value
EINTEL64_2_BIT_7 = BIT_7; // Reserved, do not count on value
EINTEL64_2_BIT_8 = BIT_8; // Reserved, do not count on value
EINTEL64_2_BIT_9 = BIT_9; // Reserved, do not count on value
EINTEL64_2_BIT_10 = BIT_10; // Reserved, do not count on value
EINTEL64_2_BIT_11 = BIT_11; // Reserved, do not count on value
EINTEL64_2_BIT_12 = BIT_12; // Reserved, do not count on value
EINTEL64_2_BIT_13 = BIT_13; // Reserved, do not count on value
EINTEL64_2_BIT_14 = BIT_14; // Reserved, do not count on value
EINTEL64_2_BIT_15 = BIT_15; // Reserved, do not count on value
EINTEL64_2_BIT_16 = BIT_16; // Reserved, do not count on value
EINTEL64_2_BIT_17 = BIT_17; // Reserved, do not count on value
EINTEL64_2_BIT_18 = BIT_18; // Reserved, do not count on value
EINTEL64_2_BIT_19 = BIT_19; // Reserved, do not count on value
EINTEL64_2_BIT_20 = BIT_20; // Reserved, do not count on value
EINTEL64_2_BIT_21 = BIT_21; // Reserved, do not count on value
EINTEL64_2_BIT_22 = BIT_22; // Reserved, do not count on value
EINTEL64_2_BIT_23 = BIT_23; // Reserved, do not count on value
EINTEL64_2_BIT_24 = BIT_24; // Reserved, do not count on value
EINTEL64_2_BIT_25 = BIT_25; // Reserved, do not count on value
EINTEL64_2_BIT_26 = BIT_26; // Reserved, do not count on value
EINTEL64_2_BIT_27 = BIT_27; // Reserved, do not count on value
EINTEL64_2_BIT_28 = BIT_28; // Reserved, do not count on value
EINTEL64_2_BIT_29 = BIT_29; // Reserved, do not count on value
EINTEL64_2_BIT_30 = BIT_30; // Reserved, do not count on value
EINTEL64_2_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_PSE32 = 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_FXSR = 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_HTT = BIT_28; // Hyper-Threading Technology
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 Standard Feature Flags continued }
AMD2_SSE3 = BIT_0; // SSE3 extensions
AMD2_BIT_1 = BIT_1; // Reserved, do not count on value
AMD2_BIT_2 = BIT_2; // Reserved, do not count on value
AMD2_BIT_3 = BIT_3; // Reserved, do not count on value
AMD2_BIT_4 = BIT_4; // Reserved, do not count on value
AMD2_BIT_5 = BIT_5; // Reserved, do not count on value
AMD2_BIT_6 = BIT_6; // Reserved, do not count on value
AMD2_BIT_7 = BIT_7; // Reserved, do not count on value
AMD2_BIT_8 = BIT_8; // Reserved, do not count on value
AMD2_BIT_9 = BIT_9; // Reserved, do not count on value
AMD2_BIT_10 = BIT_10; // Reserved, do not count on value
AMD2_BIT_11 = BIT_11; // Reserved, do not count on value
AMD2_BIT_12 = BIT_12; // Reserved, do not count on value
AMD2_CMPXCHG16B = BIT_13; // CMPXCHG16B available
AMD2_BIT_14 = BIT_14; // Reserved, do not count on value
AMD2_BIT_15 = BIT_15; // Reserved, do not count on value
AMD2_BIT_16 = BIT_16; // Reserved, do not count on value
AMD2_BIT_17 = BIT_17; // Reserved, do not count on value
AMD2_BIT_18 = BIT_18; // Reserved, do not count on value
AMD2_BIT_19 = BIT_19; // Reserved, do not count on value
AMD2_BIT_20 = BIT_20; // Reserved, do not count on value
AMD2_BIT_21 = BIT_21; // Reserved, do not count on value
AMD2_BIT_22 = BIT_22; // Reserved, do not count on value
AMD2_BIT_23 = BIT_23; // Reserved, do not count on value
AMD2_BIT_24 = BIT_24; // Reserved, do not count on value
AMD2_BIT_25 = BIT_25; // Reserved, do not count on value
AMD2_BIT_26 = BIT_26; // Reserved, do not count on value
AMD2_BIT_27 = BIT_27; // Reserved, do not count on value
AMD2_BIT_28 = BIT_28; // Reserved, do not count on value
AMD2_BIT_29 = BIT_29; // Reserved, do not count on value
AMD2_BIT_30 = BIT_30; // Reserved, do not count on value
AMD2_RAZ = BIT_31; // RAZ
{ 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_NX = 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 Extended Feature Flags continued }
EAMD2_LAHF = BIT_0; // LAHF/SAHF available in 64-bit mode
EAMD2_CMPLEGACY = BIT_1; // core multi-processing legacy mode
EAMD2_SVM = BIT_2; // Secure Virtual Machine
EAMD2_BIT_3 = BIT_3; // Reserved, do not count on value
EAMD2_ALTMOVCR8 = BIT_4; // LOCK MOV CR0 means MOV CR8
EAMD2_BIT_5 = BIT_5; // Reserved, do not count on value
EAMD2_BIT_6 = BIT_6; // Reserved, do not count on value
EAMD2_BIT_7 = BIT_7; // Reserved, do not count on value
EAMD2_BIT_8 = BIT_8; // Reserved, do not count on value
EAMD2_BIT_9 = BIT_9; // Reserved, do not count on value
EAMD2_BIT_10 = BIT_10; // Reserved, do not count on value
EAMD2_BIT_11 = BIT_11; // Reserved, do not count on value
EAMD2_BIT_12 = BIT_12; // Reserved, do not count on value
EAMD2_BIT_13 = BIT_13; // Reserved, do not count on value
EAMD2_BIT_14 = BIT_14; // Reserved, do not count on value
EAMD2_BIT_15 = BIT_15; // Reserved, do not count on value
EAMD2_BIT_16 = BIT_16; // Reserved, do not count on value
EAMD2_BIT_17 = BIT_17; // Reserved, do not count on value
EAMD2_BIT_18 = BIT_18; // Reserved, do not count on value
EAMD2_BIT_19 = BIT_19; // Reserved, do not count on value
EAMD2_BIT_20 = BIT_20; // Reserved, do not count on value
EAMD2_BIT_21 = BIT_21; // Reserved, do not count on value
EAMD2_BIT_22 = BIT_22; // Reserved, do not count on value
EAMD2_BIT_23 = BIT_23; // Reserved, do not count on value
EAMD2_BIT_24 = BIT_24; // Reserved, do not count on value
EAMD2_BIT_25 = BIT_25; // Reserved, do not count on value
EAMD2_BIT_26 = BIT_26; // Reserved, do not count on value
EAMD2_BIT_27 = BIT_27; // Reserved, do not count on value
EAMD2_BIT_28 = BIT_28; // Reserved, do not count on value
EAMD2_BIT_29 = BIT_29; // Reserved, do not count on value
EAMD2_BIT_30 = BIT_30; // Reserved, do not count on value
EAMD2_BIT_31 = BIT_31; // Reserved, do not count on value
{ AMD Power Management Features Flags }
PAMD_TEMPSENSOR = BIT_0; // Temperature Sensor
PAMD_FREQUENCYID = BIT_1; // Frequency ID Control
PAMD_VOLTAGEID = BIT_2; // Voltage ID Control
PAMD_THERMALTRIP = BIT_3; // Thermal Trip
PAMD_THERMALMONITOR = BIT_4; // Thermal Monitoring
PAMD_SOFTTHERMCONTROL = BIT_5; // Software Thermal Control
PAMD_BIT_6 = BIT_6; // Reserved, do not count on value
PAMD_BIT_7 = BIT_7; // Reserved, do not count on value
PAMD_TSC_INVARIANT = BIT_8; // TSC rate is invariant
PAMD_BIT_9 = BIT_9; // Reserved, do not count on value
PAMD_BIT_10 = BIT_10; // Reserved, do not count on value
PAMD_BIT_11 = BIT_11; // Reserved, do not count on value
PAMD_BIT_12 = BIT_12; // Reserved, do not count on value
PAMD_BIT_13 = BIT_13; // Reserved, do not count on value
PAMD_BIT_14 = BIT_14; // Reserved, do not count on value
PAMD_BIT_15 = BIT_15; // Reserved, do not count on value
PAMD_BIT_16 = BIT_16; // Reserved, do not count on value
PAMD_BIT_17 = BIT_17; // Reserved, do not count on value
PAMD_BIT_18 = BIT_18; // Reserved, do not count on value
PAMD_BIT_19 = BIT_19; // Reserved, do not count on value
PAMD_BIT_20 = BIT_20; // Reserved, do not count on value
PAMD_BIT_21 = BIT_21; // Reserved, do not count on value
PAMD_BIT_22 = BIT_22; // Reserved, do not count on value
PAMD_BIT_23 = BIT_23; // Reserved, do not count on value
PAMD_BIT_24 = BIT_24; // Reserved, do not count on value
PAMD_BIT_25 = BIT_25; // Reserved, do not count on value
PAMD_BIT_26 = BIT_26; // Reserved, do not count on value
PAMD_BIT_27 = BIT_27; // Reserved, do not count on value
PAMD_BIT_28 = BIT_28; // Reserved, do not count on value
PAMD_BIT_29 = BIT_29; // Reserved, do not count on value
PAMD_BIT_30 = BIT_30; // Reserved, do not count on value
PAMD_BIT_31 = BIT_31; // Reserved, do not count on value
{ 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..58] of TCacheInfo = (
(D: $00; Family: cfOther; I: RsIntelCacheDescr00),
(D: $01; Family: cfInstructionTLB; Size: 4; WaysOfAssoc: 4; Entries: 32; I: RsIntelCacheDescr01),
(D: $02; Family: cfInstructionTLB; Size: 4096; WaysOfAssoc: 4; Entries: 2; I: RsIntelCacheDescr02),
(D: $03; Family: cfDataTLB; Size: 4; WaysOfAssoc: 4; Entries: 64; I: RsIntelCacheDescr03),
(D: $04; Family: cfDataTLB; Size: 4096; WaysOfAssoc: 4; Entries: 8; I: RsIntelCacheDescr04),
(D: $05; Family: cfDataTLB; Size: 4096; WaysOfAssoc: 4; Entries: 32; I: RsIntelCacheDescr05),
(D: $06; Family: cfL1InstructionCache; Size: 8; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr06),
(D: $08; Family: cfL1InstructionCache; Size: 16; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr08),
(D: $0A; Family: cfL1DataCache; Size: 8; WaysOfAssoc: 2; LineSize: 32; I: RsIntelCacheDescr0A),
(D: $0B; Family: cfInstructionTLB; Size: 4; WaysOfAssoc: 4; Entries: 4; I: RsIntelCacheDescr0B),
(D: $0C; Family: cfL1DataCache; Size: 16; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr0C),
(D: $22; Family: cfL3Cache; Size: 512; WaysOfAssoc: 4; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr22),
(D: $23; Family: cfL3Cache; Size: 1024; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr23),
(D: $25; Family: cfL3Cache; Size: 2048; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr25),
(D: $29; Family: cfL3Cache; Size: 4096; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr29),
(D: $2C; Family: cfL1DataCache; Size: 32; WaysOfAssoc: 8; LineSize: 64; I: RsIntelCacheDescr2C),
(D: $30; Family: cfL1InstructionCache; Size: 32; WaysOfAssoc: 8; LineSize: 64; I: RsIntelCacheDescr30),
(D: $40; Family: cfOther; I: RsIntelCacheDescr40),
(D: $41; Family: cfL2Cache; Size: 128; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr41),
(D: $42; Family: cfL2Cache; Size: 256; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr42),
(D: $43; Family: cfL2Cache; Size: 512; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr43),
(D: $44; Family: cfL2Cache; Size: 1024; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr44),
(D: $45; Family: cfL2Cache; Size: 2048; WaysOfAssoc: 4; LineSize: 32; I: RsIntelCacheDescr45),
(D: $46; Family: cfL3Cache; Size: 4096; WaysOfAssoc: 4; LineSize: 64; I: RsIntelCacheDescr46),
(D: $47; Family: cfL3Cache; Size: 8192; WaysOfAssoc: 8; LineSize: 64; I: RsIntelCacheDescr47),
(D: $49; Family: cfL2Cache; Size: 4096; WaysOfAssoc: 16; LineSize: 64; I: RsIntelCacheDescr49),
(D: $50; Family: cfInstructionTLB; Size: 4; Entries: 64; I: RsIntelCacheDescr50),
(D: $51; Family: cfInstructionTLB; Size: 4; Entries: 128; I: RsIntelCacheDescr51),
(D: $52; Family: cfInstructionTLB; Size: 4; Entries: 256; I: RsIntelCacheDescr52),
(D: $56; Family: cfDataTLB; Size: 4096; WaysOfAssoc: 4; Entries: 16; I: RsIntelCacheDescr56),
(D: $57; Family: cfDataTLB; Size: 4; WaysOfAssoc: 4; Entries: 16; I: RsIntelCacheDescr57),
(D: $5B; Family: cfDataTLB; Size: 4096; Entries: 64; I: RsIntelCacheDescr5B),
(D: $5C; Family: cfDataTLB; Size: 4096; Entries: 128; I: RsIntelCacheDescr5C),
(D: $5D; Family: cfDataTLB; Size: 4096; Entries: 256; I: RsIntelCacheDescr5D),
(D: $60; Family: cfL1DataCache; Size: 16; WaysOfAssoc: 8; LineSize: 64; I: RsIntelCacheDescr60),
(D: $66; Family: cfL1DataCache; Size: 8; WaysOfAssoc: 4; LineSize: 64; I: RsIntelCacheDescr66),
(D: $67; Family: cfL1DataCache; Size: 16; WaysOfAssoc: 4; LineSize: 64; I: RsIntelCacheDescr67),
(D: $68; Family: cfL1DataCache; Size: 32; WaysOfAssoc: 4; LineSize: 64; I: RsIntelCacheDescr68),
(D: $70; Family: cfTrace; Size: 12; WaysOfAssoc: 8; I: RsIntelCacheDescr70),
(D: $71; Family: cfTrace; Size: 16; WaysOfAssoc: 8; I: RsIntelCacheDescr71),
(D: $72; Family: cfTrace; Size: 32; WaysOfAssoc: 8; I: RsIntelCacheDescr72),
(D: $78; Family: cfL2Cache; Size: 1024; WaysOfAssoc: 4; LineSize: 64; I: RsIntelCacheDescr78),
(D: $79; Family: cfL2Cache; Size: 128; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr79),
(D: $7A; Family: cfL2Cache; Size: 256; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr7A),
(D: $7B; Family: cfL2Cache; Size: 512; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr7B),
(D: $7C; Family: cfL2Cache; Size: 1024; WaysOfAssoc: 8; LineSize: 64; LinePerSector: 2; I: RsIntelCacheDescr7C),
(D: $7D; Family: cfL2Cache; Size: 2048; WaysOfAssoc: 8; LineSize: 64; I: RsIntelCacheDescr7D),
(D: $7F; Family: cfL2Cache; Size: 512; WaysOfAssoc: 2; LineSize: 64; I: RsIntelCacheDescr7F),
(D: $82; Family: cfL2Cache; Size: 256; WaysOfAssoc: 8; LineSize: 32; I: RsIntelCacheDescr82),
(D: $83; Family: cfL2Cache; Size: 512; WaysOfAssoc: 8; LineSize: 32; I: RsIntelCacheDescr83),
(D: $84; Family: cfL2Cache; Size: 1024; WaysOfAssoc: 8; LineSize: 32; I: RsIntelCacheDescr84),
(D: $85; Family: cfL2Cache; Size: 2048; WaysOfAssoc: 8; LineSize: 32; I: RsIntelCacheDescr85),
(D: $86; Family: cfL2Cache; Size: 512; WaysOfAssoc: 4; LineSize: 64; I: RsIntelCacheDescr86),
(D: $87; Family: cfL2Cache; Size: 1024; WaysOfAssoc: 8; LineSize: 64; I: RsIntelCacheDescr87),
(D: $B0; Family: cfInstructionTLB; Size: 4; WaysOfAssoc: 4; Entries: 128; I: RsIntelCacheDescrB0),
(D: $B3; Family: cfDataTLB; Size: 4; WaysOfAssoc: 4; Entries: 128; I: RsIntelCacheDescrB3),
(D: $B4; Family: cfDataTLB; Size: 4; WaysOfAssoc: 4; Entries: 256; I: RsIntelCacheDescrB4),
(D: $F0; Family: cfOther; I: RsIntelCacheDescrF0),
(D: $F1; Family: cfOther; I: RsIntelCacheDescrF1)
);
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;
function GetBPP: Cardinal;
// installed programs information
function ProgIDExists(const ProgID: string): Boolean;
function IsWordInstalled: Boolean;
function IsExcelInstalled: Boolean;
function IsAccessInstalled: Boolean;
function IsPowerPointInstalled: Boolean;
function IsFrontPageInstalled: Boolean;
function IsOutlookInstalled: Boolean;
function IsInternetExplorerInstalled: Boolean;
function IsMSProjectInstalled: Boolean;
function IsOpenOfficeInstalled: Boolean;
{$ENDIF MSWINDOWS}
// Public global variables
var
ProcessorCount: Cardinal = 0;
AllocGranularity: Cardinal = 0;
PageSize: Cardinal = 0;
{$ENDIF ~CLR}
{$IFDEF UNITVERSIONING}
const
UnitVersioning: TUnitVersionInfo = (
RCSfile: '$URL: https://jcl.svn.sourceforge.net:443/svnroot/jcl/tags/JCL-1.100-Build2646/jcl/source/common/JclSysInfo.pas $';
Revision: '$Revision: 2038 $';
Date: '$Date: 2007-06-16 20:31:47 +0200 (sam., 16 juin 2007) $';
LogPath: 'JCL\source\common'
);
{$ENDIF UNITVERSIONING}
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}
{$IFDEF MSWINDOWS}
{$I JclSysInfo.fpc}
{$ENDIF MSWINDOWS}
{$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;
function GetEnvironmentVars(const Vars: TStrings; Expand: Boolean): Boolean;
begin
Result := GetEnvironmentVars(Vars); // Expand is there just for x-platform compatibility
end;
{$ENDIF KYLIX}
{$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;
{$IFDEF FPC}
if GetLastOSError <> ERANGE then
{$ELSE}
if GetLastError <> ERANGE then
{$ENDIF FPC}
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}
{$IFNDEF FPC}
function GetCommonDocumentsFolder: string;
begin
Result := GetSpecialFolderLocation(CSIDL_COMMON_DOCUMENTS);
end;
{$ENDIF ~FPC}
{$ENDIF ~CLR}
{$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;
const
FileSystemFlags: array [TFileSystemFlag] of DWORD =
( FILE_CASE_SENSITIVE_SEARCH, // fsCaseSensitive
FILE_CASE_PRESERVED_NAMES, // fsCasePreservedNames
FILE_UNICODE_ON_DISK, // fsSupportsUnicodeOnDisk
FILE_PERSISTENT_ACLS, // fsPersistentACLs
FILE_FILE_COMPRESSION, // fsSupportsFileCompression
FILE_VOLUME_QUOTAS, // fsSupportsVolumeQuotas
FILE_SUPPORTS_SPARSE_FILES, // fsSupportsSparseFiles
FILE_SUPPORTS_REPARSE_POINTS, // fsSupportsReparsePoints
FILE_SUPPORTS_REMOTE_STORAGE, // fsSupportsRemoteStorage
FILE_VOLUME_IS_COMPRESSED, // fsVolumeIsCompressed
FILE_SUPPORTS_OBJECT_IDS, // fsSupportsObjectIds
FILE_SUPPORTS_ENCRYPTION, // fsSupportsEncryption
FILE_NAMED_STREAMS, // fsSupportsNamedStreams
FILE_READ_ONLY_VOLUME // fsVolumeIsReadOnly
);
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 FileSystemFlags[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
// TODO: CLR detection:
// Resolve was deprecated in Framework 2.0
// GetHostEntry was introduced in Framework 2.0
{$IFDEF BDS5_UP}
Host := System.Net.Dns.GetHostEntry(HostName);
{$ELSE ~BDS5_UP}
Host := System.Net.Dns.Resolve(HostName);
{$ENDIF ~BDS5_UP}
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
{$IFDEF FPC}
strncpy(IfReq.ifr_ifrn.ifrn_name, IfList^.if_name, IFNAMSIZ);
{$ELSE}
strncpy(IfReq.ifrn_name, IfList^.if_name, IFNAMSIZ);
{$ENDIF FPC}
//get the address for this interface
if ioctl(Sock, SIOCGIFADDR, @IfReq) <> 0 then
RaiseLastOSError;
//print out the address
{$IFDEF FPC}
SockAddrPtr := PSockAddrIn(@IfReq.ifr_ifru.ifru_addr);
Results.Add(Format('%s=%s', [IfReq.ifr_ifrn.ifrn_name, inet_ntoa(SockAddrPtr^.sin_addr)]));
{$ELSE}
SockAddrPtr := PSockAddrIn(@IfReq.ifru_addr);
Results.Add(Format('%s=%s', [IfReq.ifrn_name, inet_ntoa(SockAddrPtr^.sin_addr)]));
{$ENDIF FPC}
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;
{$IFDEF FPC}
if readdir_r(ProcDir, @Scratch, @PtrDirEnt) <> 0 then
Exit;
{$ELSE}
if readdir_r(ProcDir, @Scratch, PtrDirEnt) <> 0 then
Exit;
{$ENDIF FPC}
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;
{$IFDEF FPC}
if readdir_r(ProcDir, @Scratch, @PtrDirEnt) <> 0 then
Break;
{$ELSE}
if readdir_r(ProcDir, @Scratch, PtrDirEnt) <> 0 then
Break;
{$ENDIF FPC}
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;
HasModules := False;
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 IsWinServer2008 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') or (TrimmedWin32CSDVersion = 'B') 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 := wvWinServer2008;
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 IsWinServer2008 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;
wvWinServer2008:
Result := RsOSVersionWinServer2008;
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 IsWinServer2008 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';
}
type
TglGetStringFunc = function(name: Cardinal): PChar; stdcall;
TglGetErrorFunc = function: Cardinal; stdcall;
TgluErrorStringFunc = function(errCode: Cardinal): PChar; stdcall;
TwglCreateContextFunc = function(DC: HDC): HGLRC; stdcall;
TwglDeleteContextFunc = function(p1: HGLRC): BOOL; stdcall;
TwglMakeCurrentFunc = function(DC: HDC; p2: HGLRC): BOOL; stdcall;
const
glu32 = 'glu32.dll'; // do not localize
glGetStringName = 'glGetString'; // do not localize
glGetErrorName = 'glGetError'; // do not localize
gluErrorStringName = 'gluErrorString'; // do not localize
wglCreateContextName = 'wglCreateContext'; // do not localize
wglDeleteContextName = 'wglDeleteContext'; // do not localize
wglMakeCurrentName = 'wglMakeCurrent'; // do not localize
ChoosePixelFormatName = 'ChoosePixelFormat'; // do not localize
SetPixelFormatName = 'SetPixelFormat'; // do not localize
function GetOpenGLVersion(const Win: THandle; out Version, Vendor: AnsiString): Boolean;
const
GL_NO_ERROR = 0;
GL_VENDOR = $1F00;
GL_VERSION = $1F02;
var
OpenGlLib, Glu32Lib: HModule;
glGetStringFunc: TglGetStringFunc;
glGetErrorFunc: TglGetErrorFunc;
gluErrorStringFunc: TgluErrorStringFunc;
wglCreateContextFunc: TwglCreateContextFunc;
wglDeleteContextFunc: TwglDeleteContextFunc;
wglMakeCurrentFunc: TwglMakeCurrentFunc;
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
@glGetStringFunc := nil;
@glGetErrorFunc := nil;
@gluErrorStringFunc := nil;
@wglCreateContextFunc := nil;
@wglDeleteContextFunc := nil;
@wglMakeCurrentFunc := nil;
Glu32Lib := 0;
OpenGlLib := SafeLoadLibrary(opengl32);
try
if OpenGlLib <> 0 then
begin
Glu32Lib := SafeLoadLibrary(glu32); // do not localize
if (OpenGlLib <> 0) and (Glu32Lib <> 0) then
begin
glGetStringFunc := GetProcAddress(OpenGlLib, glGetStringName);
glGetErrorFunc := GetProcAddress(OpenGlLib, glGetErrorName);
gluErrorStringFunc := GetProcAddress(Glu32Lib, gluErrorStringName);
wglCreateContextFunc := GetProcAddress(OpenGlLib, wglCreateContextName);
wglDeleteContextFunc := GetProcAddress(OpenGlLib, wglDeleteContextName);
wglMakeCurrentFunc := GetProcAddress(OpenGlLib, wglMakeCurrentName);
end;
end;
if not (Assigned(glGetStringFunc) and Assigned(glGetErrorFunc) and Assigned(gluErrorStringFunc) and
Assigned(wglCreateContextFunc) and Assigned(wglDeleteContextFunc) and Assigned(wglMakeCurrentFunc)) then
begin
@glGetStringFunc := nil;
Result := False;
Vendor := RsOpenGLInfoError;
Version := RsOpenGLInfoError;
Exit;
end;
{ 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(ChoosePixelFormatName);
if not SetPixelFormat(hGLDC, iFormatIndex, @pfd) then
FunctionFailedError(SetPixelFormatName);
hGLContext := wglCreateContextFunc(hGLDC);
if hGLContext = 0 then
FunctionFailedError(wglCreateContextName);
if not wglMakeCurrentFunc(hGLDC, hGLContext) then
FunctionFailedError(wglMakeCurrentName);
{ TODO : Review the following. Not sure I am 100% happy with this code
in its current structure. }
pcTemp := glGetStringFunc(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 := glGetErrorFunc;
if glErr <> GL_NO_ERROR then
begin
sOpenGLVersion := gluErrorStringFunc(glErr);
sOpenGLVendor := '';
end;
end;
pcTemp := glGetStringFunc(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 := glGetErrorFunc;
if glErr <> GL_NO_ERROR then
begin
sOpenGLVendor := gluErrorStringFunc(glErr);
Exit;
end;
end;
Result := (not bError);
Version := sOpenGLVersion;
Vendor := sOpenGLVendor;
finally
{ Close all resources }
wglMakeCurrentFunc(hGLDC, 0);
if hGLContext <> 0 then
wglDeleteContextFunc(hGLContext);
end;
finally
Set8087CW(Save8087CW);
end;
finally
if (OpenGlLib <> 0) then
FreeLibrary(OpenGlLib);
if (Glu32Lib <> 0) then
FreeLibrary(Glu32Lib);
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}
function CPUID: TCpuInfo;
function HasCPUIDInstruction: Boolean;
const
ID_FLAG = $200000;
begin
asm
PUSHFD
POP EAX
MOV ECX, EAX
XOR EAX, ID_FLAG
AND ECX, ID_FLAG
PUSH EAX
POPFD
PUSHFD
POP EAX
AND EAX, ID_FLAG
XOR EAX, ECX
SETNZ Result
end;
end;
procedure CallCPUID(ValueEAX, ValueECX: Cardinal; var ReturnedEAX, ReturnedEBX, ReturnedECX, ReturnedEDX);
begin
asm
PUSH EDI
PUSH EBX
MOV EAX, ValueEAX
MOV ECX, ValueECX
// CPUID
DB 0FH
DB 0A2H
MOV EDI, ReturnedEAX
MOV Cardinal PTR [EDI], EAX
MOV EAX, ReturnedEBX
MOV EDI, ReturnedECX
MOV Cardinal PTR [EAX], EBX
MOV Cardinal PTR [EDI], ECX
MOV EAX, ReturnedEDX
MOV Cardinal PTR [EAX], EDX
POP EBX
POP EDI
end;
end;
procedure ProcessStandard(var CPUInfo: TCpuInfo; HiVal: Cardinal);
var
VersionInfo, AdditionalInfo, ExFeatures: Cardinal;
begin
if HiVal >= 1 then
begin
CallCPUID(1, 0, VersionInfo, AdditionalInfo, ExFeatures, CPUInfo.Features);
CPUInfo.PType := (VersionInfo and $00003000) shr 12;
CPUInfo.Family := (VersionInfo and $00000F00) shr 8;
CPUInfo.Model := (VersionInfo and $000000F0) shr 4;
CPUInfo.Stepping := (VersionInfo and $0000000F);
CPUInfo.ExtendedModel := (VersionInfo and $000F0000) shr 16;
CPUInfo.ExtendedFamily := (VersionInfo and $0FF00000) shr 20;
if CPUInfo.CpuType = CPU_TYPE_INTEL then
begin
CPUInfo.IntelSpecific.ExFeatures := ExFeatures;
CPUInfo.IntelSpecific.BrandID := AdditionalInfo and $000000FF;
CPUInfo.IntelSpecific.FlushLineSize := (AdditionalInfo and $0000FF00) shr 8;
CPUInfo.IntelSpecific.APICID := (AdditionalInfo and $FF000000) shr 24;
CPUInfo.LogicalCore := (AdditionalInfo and $00FF0000) shr 16;
CPUInfo.HyperThreadingTechnology := (CPUInfo.Features and INTEL_HTT) <> 0;
if HiVal >= 2 then
begin
CPUInfo.HasCacheInfo := True;
// TODO: multiple loops
CallCPUID(2, 0, CPUInfo.IntelSpecific.CacheDescriptors[0], CPUInfo.IntelSpecific.CacheDescriptors[4],
CPUInfo.IntelSpecific.CacheDescriptors[8], CPUInfo.IntelSpecific.CacheDescriptors[12]);
end;
end;
end;
end;
procedure ProcessIntel(var CPUInfo: TCpuInfo; HiVal: Cardinal);
var
ExHiVal, Unused, AddressSize, CoreInfo: Cardinal;
I, J: Integer;
begin
CPUInfo.CpuType := CPU_TYPE_INTEL;
CPUInfo.Manufacturer := 'Intel';
ProcessStandard(CPUInfo, HiVal);
if HiVal >= 4 then
begin
CallCPUID(4, 0, CoreInfo, Unused, Unused, Unused);
CPUInfo.PhysicalCore := ((CoreInfo and $FC000000) shr 26) + 1;
end;
// check Intel extended
CallCPUID($80000000, 0, ExHiVal, Unused, Unused, Unused);
if ExHiVal >= $80000001 then
begin
CPUInfo.HasExtendedInfo := True;
CallCPUID($80000001, 0, Unused, Unused, CPUInfo.IntelSpecific.Ex64Features2,
CPUInfo.IntelSpecific.Ex64Features);
end;
if ExHiVal >= $80000002 then
CallCPUID($80000002, 0, CPUInfo.CpuName[0], CPUInfo.CpuName[4], CPUInfo.CpuName[8], CPUInfo.CpuName[12]);
if ExHiVal >= $80000003 then
CallCPUID($80000003, 0, CPUInfo.CpuName[16], CPUInfo.CpuName[20], CPUInfo.CpuName[24], CPUInfo.CpuName[28]);
if ExHiVal >= $80000004 then
CallCPUID($80000004, 0, CPUInfo.CpuName[32], CPUInfo.CpuName[36], CPUInfo.CpuName[40], CPUInfo.CpuName[44]);
if ExHiVal >= $80000006 then
CallCPUID($80000006, 0, Unused, Unused, CPUInfo.IntelSpecific.L2Cache, Unused);
if ExHiVal >= $80000008 then
begin
CallCPUID($80000008, 0, AddressSize, Unused, Unused, Unused);
CPUInfo.IntelSpecific.PhysicalAddressBits := AddressSize and $000000FF;
CPUInfo.IntelSpecific.VirtualAddressBits := (AddressSize and $0000FF00) shr 8;
end;
if CPUInfo.HasCacheInfo then
begin
if (CPUInfo.IntelSpecific.L2Cache <> 0) then
begin
CPUInfo.L2CacheSize := CPUInfo.IntelSpecific.L2Cache shr 16;
CPUInfo.L2CacheLineSize := CPUInfo.IntelSpecific.L2Cache and $FF;
CPUInfo.L2CacheAssociativity := (CPUInfo.IntelSpecific.L2Cache shr 12) and $F;
end;
for I := Low(CPUInfo.IntelSpecific.CacheDescriptors) to High(CPUInfo.IntelSpecific.CacheDescriptors) do
if CPUInfo.IntelSpecific.CacheDescriptors[I]<>0 then
for J := Low(IntelCacheDescription) to High(IntelCacheDescription) do
if IntelCacheDescription[J].D = CPUInfo.IntelSpecific.CacheDescriptors[I] then
with IntelCacheDescription[J] do
case Family of
//cfInstructionTLB:
//cfDataTLB:
cfL1InstructionCache:
begin
Inc(CPUInfo.L1InstructionCacheSize,Size);
CPUInfo.L1InstructionCacheLineSize := LineSize;
CPUInfo.L1InstructionCacheAssociativity := WaysOfAssoc;
end;
cfL1DataCache:
begin
Inc(CPUInfo.L1DataCacheSize,Size);
CPUInfo.L1DataCacheLineSize := LineSize;
CPUInfo.L1DataCacheAssociativity := WaysOfAssoc;
end;
cfL2Cache:
if (CPUInfo.IntelSpecific.L2Cache = 0) then
begin
Inc(CPUInfo.L2CacheSize,Size);
CPUInfo.L2CacheLineSize := LineSize;
CPUInfo.L2CacheAssociativity := WaysOfAssoc;
end;
cfL3Cache:
begin
Inc(CPUInfo.L3CacheSize,Size);
CPUInfo.L3CacheLineSize := LineSize;
CPUInfo.L3CacheAssociativity := WaysOfAssoc;
CPUInfo.L3LinesPerSector := LinePerSector;
end;
//cfTrace: // no numeric informations
//cfOther:
end;
end;
if not CPUInfo.HasExtendedInfo then
begin
case CPUInfo.Family of
4:
case CPUInfo.Model of
1:
CPUInfo.CpuName := 'Intel 486DX Processor';
2:
CPUInfo.CpuName := 'Intel 486SX Processor';
3:
CPUInfo.CpuName := 'Intel DX2 Processor';
4:
CPUInfo.CpuName := 'Intel 486 Processor';
5:
CPUInfo.CpuName := 'Intel SX2 Processor';
7:
CPUInfo.CpuName := 'Write-Back Enhanced Intel DX2 Processor';
8:
CPUInfo.CpuName := 'Intel DX4 Processor';
else
CPUInfo.CpuName := 'Intel 486 Processor';
end;
5:
CPUInfo.CpuName := 'Pentium';
6:
case CPUInfo.Model of
1:
CPUInfo.CpuName := 'Pentium Pro';
3:
CPUInfo.CpuName := 'Pentium II';
5:
case CPUInfo.L2CacheSize of
0:
CPUInfo.CpuName := 'Celeron';
1024:
CPUInfo.CpuName := 'Pentium II Xeon';
2048:
CPUInfo.CpuName := 'Pentium II Xeon';
else
CPUInfo.CpuName := 'Pentium II';
end;
6:
case CPUInfo.L2CacheSize of
0:
CPUInfo.CpuName := 'Celeron';
128:
CPUInfo.CpuName := 'Celeron';
else
CPUInfo.CpuName := 'Pentium II';
end;
7:
case CPUInfo.L2CacheSize of
1024:
CPUInfo.CpuName := 'Pentium III Xeon';
2048:
CPUInfo.CpuName := 'Pentium III Xeon';
else
CPUInfo.CpuName := 'Pentium III';
end;
8:
case CPUInfo.IntelSpecific.BrandID of
1:
CPUInfo.CpuName := 'Celeron';
2:
CPUInfo.CpuName := 'Pentium III';
3:
CPUInfo.CpuName := 'Pentium III Xeon';
4:
CPUInfo.CpuName := 'Pentium III';
else
CPUInfo.CpuName := 'Pentium III';
end;
10:
CPUInfo.CpuName := 'Pentium III Xeon';
11:
CPUInfo.CpuName := 'Pentium III';
else
StrPCopy(CPUInfo.CpuName, Format('P6 (Model %d)', [CPUInfo.Model]));
end;
15:
case CPUInfo.IntelSpecific.BrandID of
1:
CPUInfo.CpuName := 'Celeron';
8:
CPUInfo.CpuName := 'Pentium 4';
14:
CPUInfo.CpuName := 'Xeon';
else
CPUInfo.CpuName := 'Pentium 4';
end;
else
StrPCopy(CPUInfo.CpuName, Format('P%d', [CPUInfo.Family]));
end;
end;
CPUInfo.MMX := (CPUInfo.Features and MMX_FLAG) <> 0;
if (CPUInfo.Features and SSE_FLAG) <> 0 then
if (CPUInfo.Features and SSE2_FLAG) <> 0 then
if (CPUInfo.IntelSpecific.ExFeatures and EINTEL_SSE3) <> 0 then
CPUInfo.SSE := 3
else
CPUInfo.SSE := 2
else
CPUInfo.SSE := 1
else
CPUInfo.SSE := 0;
CPUInfo.Is64Bits := CPUInfo.HasExtendedInfo and ((CPUInfo.IntelSpecific.Ex64Features and EINTEL64_EM64T)<>0);
CPUInfo.DepCapable := CPUInfo.HasExtendedInfo and ((CPUInfo.IntelSpecific.Ex64Features and EINTEL64_EDB) <> 0);
end;
procedure ProcessAMD(var CPUInfo: TCpuInfo; HiVal: Cardinal);
var
ExHiVal, Unused, VersionInfo, AdditionalInfo: Cardinal;
begin
CPUInfo.CpuType := CPU_TYPE_AMD;
CPUInfo.Manufacturer := 'AMD';
// check AMD extended
if HiVal >= 1 then
begin
CallCPUID(1, 0, Unused, VersionInfo, CPUInfo.AMDSpecific.Features2, CPUInfo.Features);
CPUInfo.AMDSpecific.BrandID := VersionInfo and $000000FF;
CPUInfo.AMDSpecific.FlushLineSize := (VersionInfo and $0000FF00) shr 8;
CPUInfo.AMDSpecific.APICID := (VersionInfo and $FF000000) shr 24;
CPUInfo.HyperThreadingTechnology := (CPUInfo.Features and AMD_HTT) <> 0;
if CPUInfo.HyperThreadingTechnology then
CPUInfo.LogicalCore := (AdditionalInfo and $00FF0000) shr 16;
end;
CallCPUID($80000000, 0, ExHiVal, Unused, Unused, Unused);
if ExHiVal <> 0 then
begin
// AMD only
CPUInfo.HasExtendedInfo := True;
if ExHiVal >= $80000001 then
begin
CallCPUID($80000001, 0, VersionInfo, AdditionalInfo, CPUInfo.AMDSpecific.ExFeatures2, CPUInfo.AMDSpecific.ExFeatures);
CPUInfo.Family := (VersionInfo and $00000F00) shr 8;
CPUInfo.Model := (VersionInfo and $000000F0) shr 4;
CPUInfo.Stepping := (VersionInfo and $0000000F);
CPUInfo.ExtendedModel := (VersionInfo and $000F0000) shr 16;
CPUInfo.ExtendedFamily := (VersionInfo and $0FF00000) shr 20;
CPUInfo.AMDSpecific.ExBrandID := AdditionalInfo and $0000FFFF;
end;
if ExHiVal >= $80000002 then
CallCPUID($80000002, 0, CPUInfo.CpuName[0], CPUInfo.CpuName[4], CPUInfo.CpuName[8], CPUInfo.CpuName[12]);
if ExHiVal >= $80000003 then
CallCPUID($80000003, 0, CPUInfo.CpuName[16], CPUInfo.CpuName[20], CPUInfo.CpuName[24], CPUInfo.CpuName[28]);
if ExHiVal >= $80000004 then
CallCPUID($80000004, 0, CPUInfo.CpuName[32], CPUInfo.CpuName[36], CPUInfo.CpuName[40], CPUInfo.CpuName[44]);
if ExHiVal >= $80000005 then
begin
CPUInfo.HasCacheInfo := True;
CallCPUID($80000005, 0, CPUInfo.AMDSpecific.L1MByteInstructionTLB, CPUInfo.AMDSpecific.L1KByteInstructionTLB,
CPUInfo.AMDSpecific.L1DataCache, CPUInfo.AMDSpecific.L1InstructionCache);
end;
if ExHiVal >= $80000006 then
CallCPUID($80000006, 0, CPUInfo.AMDSpecific.L2MByteInstructionTLB, CPUInfo.AMDSpecific.L2KByteInstructionTLB,
CPUInfo.AMDSpecific.L2Cache, Unused);
if CPUInfo.HasCacheInfo then
begin
CPUInfo.L1DataCacheSize := CPUInfo.AMDSpecific.L1DataCache[ciSize];
CPUInfo.L1DataCacheLineSize := CPUInfo.AMDSpecific.L1DataCache[ciLineSize];
CPUInfo.L1DataCacheAssociativity := CPUInfo.AMDSpecific.L1DataCache[ciAssociativity];
CPUInfo.L1InstructionCacheSize := CPUInfo.AMDSpecific.L1InstructionCache[ciSize];
CPUInfo.L1InstructionCacheLineSize := CPUInfo.AMDSpecific.L1InstructionCache[ciLineSize];
CPUInfo.L1InstructionCacheAssociativity := CPUInfo.AMDSpecific.L1InstructionCache[ciAssociativity];
CPUInfo.L2CacheLineSize := CPUInfo.AMDSpecific.L2Cache and $FF;
CPUInfo.L2CacheAssociativity := (CPUInfo.AMDSpecific.L2Cache shr 12) and $F;
CPUInfo.L2CacheSize := CPUInfo.AMDSpecific.L2Cache shr 16;
end;
if ExHiVal >= $80000007 then
CallCPUID($80000007, 0, Unused, Unused, Unused, CPUInfo.AMDSpecific.AdvancedPowerManagement);
if ExHiVal >= $80000008 then
begin
CallCPUID($80000008, 0, Unused, VersionInfo, AdditionalInfo, Unused);
CPUInfo.AMDSpecific.PhysicalAddressSize := VersionInfo and $000000FF;
CPUInfo.AMDSpecific.VirtualAddressSize := (VersionInfo and $0000FF00) shr 8;
CPUInfo.PhysicalCore := (AdditionalInfo and $000000FF) + 1;
end;
end
else
begin
ProcessStandard(CPUInfo, HiVal);
case CPUInfo.Family of
4:
CPUInfo.CpuName := 'Am486(R) or Am5x86';
5:
case CPUInfo.Model of
0:
CPUInfo.CpuName := 'AMD-K5 (Model 0)';
1:
CPUInfo.CpuName := 'AMD-K5 (Model 1)';
2:
CPUInfo.CpuName := 'AMD-K5 (Model 2)';
3:
CPUInfo.CpuName := 'AMD-K5 (Model 3)';
6:
CPUInfo.CpuName := 'AMD-K6<4B> (Model 6)';
7:
CPUInfo.CpuName := 'AMD-K6<4B> (Model 7)';
8:
CPUInfo.CpuName := 'AMD-K6<4B>-2 (Model 8)';
9:
CPUInfo.CpuName := 'AMD-K6<4B>-III (Model 9)';
else
StrFmt(CPUInfo.CpuName,PChar(RsUnknownAMDModel),[CPUInfo.Model]);
end;
6:
case CPUInfo.Model of
1:
CPUInfo.CpuName := 'AMD Athlon<6F> (Model 1)';
2:
CPUInfo.CpuName := 'AMD Athlon<6F> (Model 2)';
3:
CPUInfo.CpuName := 'AMD Duron<6F> (Model 3)';
4:
CPUInfo.CpuName := 'AMD Athlon<6F> (Model 4)';
6:
CPUInfo.CpuName := 'AMD Athlon<6F> XP (Model 6)';
7:
CPUInfo.CpuName := 'AMD Duron<6F> (Model 7)';
8:
CPUInfo.CpuName := 'AMD Athlon<6F> XP (Model 8)';
10:
CPUInfo.CpuName := 'AMD Athlon<6F> XP (Model 10)';
else
StrFmt(CPUInfo.CpuName, PChar(RsUnknownAMDModel), [CPUInfo.Model]);
end;
8:
else
CPUInfo.CpuName := 'Unknown AMD Chip';
end;
end;
CPUInfo.MMX := (CPUInfo.Features and AMD_MMX) <> 0;
CPUInfo.ExMMX := CPUInfo.HasExtendedInfo and ((CPUInfo.AMDSpecific.ExFeatures and EAMD_EXMMX) <> 0);
CPUInfo._3DNow := CPUInfo.HasExtendedInfo and ((CPUInfo.AMDSpecific.ExFeatures and EAMD_3DNOW) <> 0);
CPUInfo.Ex3DNow := CPUInfo.HasExtendedInfo and ((CPUInfo.AMDSpecific.ExFeatures and EAMD_EX3DNOW) <> 0);
if (CPUInfo.Features and AMD_SSE) <> 0 then
if (CPUInfo.Features and AMD_SSE2) <> 0 then
if CPUInfo.HasExtendedInfo and ((CPUInfo.AMDSpecific.Features2 and AMD2_SSE3) <> 0) then
CPUInfo.SSE := 3
else
CPUInfo.SSE := 2
else
CPUInfo.SSE := 1
else
CPUInfo.SSE := 0;
CPUInfo.Is64Bits := CPUInfo.HasExtendedInfo and ((CPUInfo.AMDSpecific.ExFeatures and EAMD_LONG) <> 0);
CPUInfo.DEPCapable := CPUInfo.HasExtendedInfo and ((CPUInfo.AMDSpecific.ExFeatures and EAMD_NX) <> 0);
end;
procedure ProcessCyrix(var CPUInfo: TCpuInfo; HiVal: Cardinal);
var
ExHiVal, Unused, VersionInfo, AdditionalInfo: Cardinal;
begin
CPUInfo.CpuType := CPU_TYPE_CYRIX;
CPUInfo.Manufacturer := 'Cyrix';
// check Cyrix extended
CallCPUID($80000000, 0, ExHiVal, Unused, Unused, Unused);
if ExHiVal <> 0 then
begin
// Cyrix only
CPUInfo.HasExtendedInfo := True;
if ExHiVal >= $80000001 then
begin
CallCPUID($80000001, 0, VersionInfo, AdditionalInfo, Unused, CPUInfo.Features);
CPUInfo.PType := (VersionInfo and $0000F000) shr 12;
CPUInfo.Family := (VersionInfo and $00000F00) shr 8;
CPUInfo.Model := (VersionInfo and $000000F0) shr 4;
CPUInfo.Stepping := (VersionInfo and $0000000F);
end;
if ExHiVal >= $80000002 then
CallCPUID($80000002, 0, CPUInfo.CpuName[0], CPUInfo.CpuName[4], CPUInfo.CpuName[8], CPUInfo.CpuName[12]);
if ExHiVal >= $80000003 then
CallCPUID($80000003, 0, CPUInfo.CpuName[16], CPUInfo.CpuName[20], CPUInfo.CpuName[24], CPUInfo.CpuName[28]);
if ExHiVal >= $80000004 then
CallCPUID($80000004, 0, CPUInfo.CpuName[32], CPUInfo.CpuName[36], CPUInfo.CpuName[40], CPUInfo.CpuName[44]);
if ExHiVal >= $80000005 then
begin
CPUInfo.HasCacheInfo := True;
CallCPUID($80000005, 0, Unused, CPUInfo.CyrixSpecific.TLBInfo, CPUInfo.CyrixSpecific.L1CacheInfo, Unused);
end;
end
else
begin
ProcessStandard(CPUInfo, HiVal);
case CPUInfo.Family of
4:
CPUInfo.CpuName := 'Cyrix MediaGX';
5:
case CPUInfo.Model of
2:
CPUInfo.CpuName := 'Cyrix 6x86';
4:
CPUInfo.CpuName := 'Cyrix GXm';
end;
6:
CPUInfo.CpuName := '6x86MX';
else
StrPCopy(CPUInfo.CpuName, Format('%dx86', [CPUInfo.Family]));
end;
end;
end;
procedure ProcessVIA(var CPUInfo: TCpuInfo; HiVal: Cardinal);
var
ExHiVal, Unused, VersionInfo: Cardinal;
begin
CPUInfo.CpuType := CPU_TYPE_VIA;
CPUInfo.Manufacturer := 'Via';
// check VIA extended
CallCPUID($80000000, 0, ExHiVal, Unused, Unused, Unused);
if ExHiVal <> 0 then
begin
if ExHiVal >= $80000001 then
begin
CPUInfo.HasExtendedInfo := True;
CallCPUID($80000001, 0, VersionInfo, Unused, Unused, CPUInfo.ViaSpecific.ExFeatures);
CPUInfo.PType := (VersionInfo and $00003000) shr 12;
CPUInfo.Family := (VersionInfo and $00000F00) shr 8;
CPUInfo.Model := (VersionInfo and $000000F0) shr 4;
CPUInfo.Stepping := (VersionInfo and $0000000F);
end;
if ExHiVal >= $80000002 then
CallCPUID($80000002, 0, CPUInfo.CpuName[0], CPUInfo.CpuName[4], CPUInfo.CpuName[8], CPUInfo.CpuName[12]);
if ExHiVal >= $80000003 then
CallCPUID($80000003, 0, CPUInfo.CpuName[16], CPUInfo.CpuName[20], CPUInfo.CpuName[24], CPUInfo.CpuName[28]);
if ExHiVal >= $80000004 then
CallCPUID($80000004, 0, CPUInfo.CpuName[32], CPUInfo.CpuName[36], CPUInfo.CpuName[40], CPUInfo.CpuName[44]);
if ExHiVal >= $80000005 then
begin
CPUInfo.HasCacheInfo := True;
CallCPUID($80000005, 0, Unused, CPUInfo.ViaSpecific.InstructionTLB, CPUInfo.ViaSpecific.L1DataCache,
CPUInfo.ViaSpecific.L1InstructionCache);
end;
if ExHiVal >= $80000006 then
CallCPUID($80000006, 0, Unused, Unused, CPUInfo.ViaSpecific.L2DataCache, Unused);
if CPUInfo.HasCacheInfo then
begin
CPUInfo.L1DataCacheSize := CPUInfo.VIASpecific.L1DataCache[ciSize];
CPUInfo.L1DataCacheLineSize := CPUInfo.VIASpecific.L1DataCache[ciLineSize];
CPUInfo.L1DataCacheAssociativity := CPUInfo.VIASpecific.L1DataCache[ciAssociativity];
CPUInfo.L1InstructionCacheSize := CPUInfo.VIASpecific.L1InstructionCache[ciSize];
CPUInfo.L1InstructionCacheLineSize := CPUInfo.VIASpecific.L1InstructionCache[ciLineSize];
CPUInfo.L1InstructionCacheAssociativity := CPUInfo.VIASpecific.L1InstructionCache[ciAssociativity];
CPUInfo.L2CacheLineSize := CPUInfo.VIASpecific.L2DataCache and $FF;
CPUInfo.L2CacheAssociativity := (CPUInfo.VIASpecific.L2DataCache shr 12) and $F;
CPUInfo.L2CacheSize := CPUInfo.VIASpecific.L2DataCache shr 16;
end;
CallCPUID($C0000000, 0, ExHiVal, Unused, Unused, Unused);
if ExHiVal >= $C0000001 then
CallCPUID($C0000001, 0, Unused, Unused, Unused, CPUInfo.ViaSpecific.ExFeatures);
end
else
ProcessStandard(CPUInfo, HiVal);
if not CPUInfo.HasExtendedInfo then
CPUInfo.CpuName := 'C3';
CPUInfo.MMX := (CPUInfo.Features and VIA_MMX) <> 0;
if (CPUInfo.Features and VIA_SSE) <> 0
then CPUInfo.SSE := 1
else CPUInfo.SSE := 0;
CPUInfo._3DNow := (CPUInfo.Features and VIA_3DNOW) <> 0;
end;
procedure ProcessTransmeta(var CPUInfo: TCpuInfo; HiVal: Cardinal);
var
ExHiVal, Unused, VersionInfo: Cardinal;
begin
CPUInfo.CpuType := CPU_TYPE_TRANSMETA;
CPUInfo.Manufacturer := 'Transmeta';
if (HiVal >= 1) then
begin
CallCPUID(1, 0, VersionInfo, Unused, Unused, CPUInfo.Features);
CPUInfo.PType := (VersionInfo and $00003000) shr 12;
CPUInfo.Family := (VersionInfo and $00000F00) shr 8;
CPUInfo.Model := (VersionInfo and $000000F0) shr 4;
CPUInfo.Stepping := (VersionInfo and $0000000F);
end;
// no information when eax is 2
// eax is 3 means Serial Number, not detected there
// small CPU description, overriden if ExHiVal >= 80000002
CallCPUID($80000000, 0, ExHiVal, CPUInfo.CpuName[0], CPUInfo.CpuName[8], CPUInfo.CpuName[4]);
if ExHiVal <> 0 then
begin
CPUInfo.HasExtendedInfo := True;
if ExHiVal >= $80000001 then
CallCPUID($80000001, 0, Unused, Unused, Unused, CPUInfo.TransmetaSpecific.ExFeatures);
if ExHiVal >= $80000002 then
CallCPUID($80000002, 0, CPUInfo.CpuName[0], CPUInfo.CpuName[4], CPUInfo.CpuName[8], CPUInfo.CpuName[12]);
if ExHiVal >= $80000003 then
CallCPUID($80000003, 0, CPUInfo.CpuName[16], CPUInfo.CpuName[20], CPUInfo.CpuName[24], CPUInfo.CpuName[28]);
if ExHiVal >= $80000004 then
CallCPUID($80000004, 0, CPUInfo.CpuName[32], CPUInfo.CpuName[36], CPUInfo.CpuName[40], CPUInfo.CpuName[44]);
if ExHiVal >= $80000005 then
begin
CPUInfo.HasCacheInfo := True;
CallCPUID($80000005, 0, Unused, CPUInfo.TransmetaSpecific.CodeTLB, CPUInfo.TransmetaSpecific.L1DataCache,
CPUInfo.TransmetaSpecific.L1CodeCache);
end;
if CPUInfo.HasCacheInfo then
begin
CPUInfo.L1DataCacheSize := CPUInfo.TransmetaSpecific.L1DataCache[ciSize];
CPUInfo.L1DataCacheLineSize := CPUInfo.TransmetaSpecific.L1DataCache[ciLineSize];
CPUInfo.L1DataCacheAssociativity := CPUInfo.TransmetaSpecific.L1DataCache[ciAssociativity];
CPUInfo.L1InstructionCacheSize := CPUInfo.TransmetaSpecific.L1CodeCache[ciSize];
CPUInfo.L1InstructionCacheLineSize := CPUInfo.TransmetaSpecific.L1CodeCache[ciLineSize];
CPUInfo.L1InstructionCacheAssociativity := CPUInfo.TransmetaSpecific.L1CodeCache[ciAssociativity];
CPUInfo.L2CacheLineSize := CPUInfo.TransmetaSpecific.L2Cache and $FF;
CPUInfo.L2CacheAssociativity := (CPUInfo.TransmetaSpecific.L2Cache shr 12) and $F;
CPUInfo.L2CacheSize := CPUInfo.TransmetaSpecific.L2Cache shr 16;
end;
if ExHiVal >= $80000006 then
CallCPUID($80000006, 0, Unused, Unused, CPUInfo.TransmetaSpecific.L2Cache, Unused);
end
else
CPUInfo.CpuName := 'Crusoe';
CallCPUID($80860000, 0, ExHiVal, Unused, Unused, Unused);
if ExHiVal <> 0 then
begin
if ExHiVal >= $80860001 then
CallCPUID($80860001, 0, Unused, CPUInfo.TransmetaSpecific.RevisionABCD, CPUInfo.TransmetaSpecific.RevisionXXXX,
CPUInfo.TransmetaSpecific.TransmetaFeatures);
if ExHiVal >= $80860002 then
CallCPUID($80860002, 0, Unused, CPUInfo.TransmetaSpecific.CodeMorphingABCD, CPUInfo.TransmetaSpecific.CodeMorphingXXXX, Unused);
if ExHiVal >= $80860003 then
CallCPUID($80860003, 0, CPUInfo.TransmetaSpecific.TransmetaInformations[0], CPUInfo.TransmetaSpecific.TransmetaInformations[4],
CPUInfo.TransmetaSpecific.TransmetaInformations[8], CPUInfo.TransmetaSpecific.TransmetaInformations[12]);
if ExHiVal >= $80860004 then
CallCPUID($80860004, 0, CPUInfo.TransmetaSpecific.TransmetaInformations[16], CPUInfo.TransmetaSpecific.TransmetaInformations[20],
CPUInfo.TransmetaSpecific.TransmetaInformations[24], CPUInfo.TransmetaSpecific.TransmetaInformations[28]);
if ExHiVal >= $80860005 then
CallCPUID($80860005, 0, CPUInfo.TransmetaSpecific.TransmetaInformations[32], CPUInfo.TransmetaSpecific.TransmetaInformations[36],
CPUInfo.TransmetaSpecific.TransmetaInformations[40], CPUInfo.TransmetaSpecific.TransmetaInformations[44]);
if ExHiVal >= $80860006 then
CallCPUID($80860006, 0, CPUInfo.TransmetaSpecific.TransmetaInformations[48], CPUInfo.TransmetaSpecific.TransmetaInformations[52],
CPUInfo.TransmetaSpecific.TransmetaInformations[56], CPUInfo.TransmetaSpecific.TransmetaInformations[60]);
if (ExHiVal >= $80860007) and ((CPUInfo.TransmetaSpecific.TransmetaFeatures and STRANSMETA_LONGRUN) <> 0) then
CallCPUID($80860007, 0, CPUInfo.TransmetaSpecific.CurrentFrequency, CPUInfo.TransmetaSpecific.CurrentVoltage,
CPUInfo.TransmetaSpecific.CurrentPerformance, Unused);
end;
CPUInfo.MMX := (CPUInfo.Features and TRANSMETA_MMX) <> 0;
end;
var
HiVal: Cardinal;
begin
FillChar(Result, sizeof(Result), 0);
Result.LogicalCore := 1;
Result.PhysicalCore := 1;
if HasCPUIDInstruction then
begin
Result.HasInstruction := True;
CallCPUID(0, 0, HiVal, Result.VendorIDString[0], Result.VendorIDString[8],
Result.VendorIDString[4]);
if Result.VendorIDString = VendorIDIntel then
ProcessIntel(Result, HiVal)
else if Result.VendorIDString = VendorIDAMD then
ProcessAMD(Result, HiVal)
else if Result.VendorIDString = VendorIDCyrix then
ProcessCyrix(Result, HiVal)
else if Result.VendorIDString = VendorIDVIA then
ProcessVIA(Result, HiVal)
else if Result.VendorIDString = VendorIDTransmeta then
ProcessTransmeta(Result, HiVal)
else
ProcessStandard(Result, HiVal);
end
else
Result.Family := 4;
if Result.CpuType = 0 then
begin
Result.Manufacturer := 'Unknown';
Result.CpuName := 'Unknown';
end;
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
{$IFDEF FPC}
SysInfo(@SystemInf);
{$ELSE}
SysInfo(SystemInf);
{$ENDIF FPC}
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
{$IFDEF FPC}
SysInfo(@SystemInf);
{$ELSE}
SysInfo(SystemInf);
{$ENDIF FPC}
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
{$IFDEF FPC}
SysInfo(@SystemInf);
{$ELSE}
SysInfo(SystemInf);
{$ENDIF FPC}
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
{$IFDEF FPC}
SysInfo(@SystemInf);
{$ELSE}
SysInfo(SystemInf);
{$ENDIF FPC}
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
{$IFDEF FPC}
SysInfo(@SystemInf);
{$ELSE}
SysInfo(SystemInf);
{$ENDIF FPC}
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;
function GetBPP: Cardinal;
var
DC: HDC;
begin
DC := GetDC(HWND_DESKTOP);
if DC <> 0 then
begin
Result := GetDeviceCaps(DC, BITSPIXEL) * GetDeviceCaps(DC, PLANES);
ReleaseDC(HWND_DESKTOP, DC);
end
else
Result := 0;
end;
//=== Installed programs =====================================================
function ProgIDExists(const ProgID: string): Boolean;
var
Tmp: TGUID;
WideProgID: WideString;
begin
WideProgID := ProgID;
Result := Succeeded(CLSIDFromProgID(PWideChar(WideProgID), Tmp));
end;
function IsWordInstalled: Boolean;
begin
Result := ProgIDExists('Word.Application');
end;
function IsExcelInstalled: Boolean;
begin
Result := ProgIDExists('Excel.Application');
end;
function IsAccessInstalled: Boolean;
begin
Result := ProgIDExists('Access.Application');
end;
function IsPowerPointInstalled: Boolean;
begin
Result := ProgIDExists('PowerPoint.Application');
end;
function IsFrontPageInstalled: Boolean;
begin
Result := ProgIDExists('FrontPage.Application');
end;
function IsOutlookInstalled: Boolean;
begin
Result := ProgIDExists('Outlook.Application');
end;
function IsInternetExplorerInstalled: Boolean;
begin
Result := ProgIDExists('InternetExplorer.Application');
end;
function IsMSProjectInstalled: Boolean;
begin
Result := ProgIDExists('MSProject.Application');
end;
function IsOpenOfficeInstalled: Boolean;
begin
Result := ProgIDExists('com.sun.star.ServiceManager');
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;
wvWinServer2008:
IsWinServer2008 := True;
end;
end;
procedure FinalizeSysInfo;
begin
UnloadSystemResourcesMeterLib;
end;
initialization
InitSysInfo;
{$IFDEF UNITVERSIONING}
RegisterUnitVersion(HInstance, UnitVersioning);
{$ENDIF UNITVERSIONING}
finalization
{$IFDEF UNITVERSIONING}
UnregisterUnitVersion(HInstance);
{$ENDIF UNITVERSIONING}
FinalizeSysInfo;
{$ENDIF MSWINDOWS}
{$ENDIF ~CLR}
end.