I maintain lots of systems, from servers with 8GB of RAM, to those running NT4. Stretchwickster wrote faq102-3240, but it doesn't handle systems with more than 2GB of RAM - something that is becoming common.
So I've written my own function that (hopefully) handles any combination of OS and RAM amount: GetTotalRAM.
Attached is the code required. It's this complex, because Windows NT (and earlier) doesn't have GlobalMemoryStatusEx in it's kernel.
You can see from the record structure it is trivial to get other values from the system.
To ensure accurate reporting for systems that have between 2GB and 4GB of RAM, the /LARGEADDRESSAWARE flag must be set in the compiled .EXE. Delphi 6 and earlier don't have this as an option in the IDE, so you must include this line
in your .dpr (project source) file. Putting it in a unit, such as your main form unit is not enough as the linker will not include it unless the unit is recompiled.
I'm not sure if this option is included in D7 or above. Setting that option in the linker options if it's available should be enough.
One last code snippet to format the byte count to something more readable:
So I've written my own function that (hopefully) handles any combination of OS and RAM amount: GetTotalRAM.
Attached is the code required. It's this complex, because Windows NT (and earlier) doesn't have GlobalMemoryStatusEx in it's kernel.
Code:
[b]uses[/b]
Windows;
[b]type[/b]
TWinVersion = (wvUnknown, wv95, wv98, wv98SE, wvNT,
wvME, wv2000, wvXP, wvVista, wv2003, wv7);
TMemoryStatusEx = [b]record[/b]
dwLength: DWORD;
dwMemoryLoad: DWORD;
ullTotalPhys: Int64;
ullAvailPhys: Int64;
ullTotalPageFile: Int64;
ullAvailPageFile: Int64;
ullTotalVirtual: Int64;
ullAvailVirtual: Int64;
ullAvailExtendedVirtual: Int64;
[b]end[/b];
[b]function[/b] GetWinVersion: TWinVersion;
[b]var[/b]
osVerInfo: TOSVersionInfo;
majorVersion, minorVersion: Integer;
[b]begin[/b]
Result := wvUnknown;
osVerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
[b]if[/b] GetVersionEx(osVerInfo) [b]then[/b]
[b]begin[/b]
minorVersion := osVerInfo.dwMinorVersion;
majorVersion := osVerInfo.dwMajorVersion;
[b]case[/b] osVerInfo.dwPlatformId [b]of[/b]
VER_PLATFORM_WIN32_NT:
[b]begin[/b]
[b]if[/b] majorVersion <= [purple]4[/purple] [b]then[/b]
Result := wvNT
[b]else[/b] [b]if[/b] (majorVersion = [purple]5[/purple]) [b]and[/b] (minorVersion = [purple]0[/purple]) [b]then[/b]
Result := wv2000
[b]else[/b] [b]if[/b] (majorVersion = [purple]5[/purple]) [b]and[/b] (minorVersion = [purple]1[/purple]) [b]then[/b]
Result := wvXP
[b]else[/b] [b]if[/b] (majorVersion = [purple]5[/purple]) [b]and[/b] (minorVersion = [purple]2[/purple]) [b]then[/b]
Result := wv2003
[b]else[/b] [b]if[/b] (majorVersion = [purple]6[/purple]) [b]then[/b]
Result := wvVista
[b]else[/b] [b]if[/b] (majorVersion = [purple]7[/purple]) [b]then[/b]
Result := wv7;
[b]end[/b];
VER_PLATFORM_WIN32_WINDOWS:
[b]begin[/b]
[b]if[/b] (majorVersion = [purple]4[/purple]) [b]and[/b] (minorVersion = [purple]0[/purple]) [b]then[/b]
Result := wv95
[b]else[/b] [b]if[/b] (majorVersion = [purple]4[/purple]) [b]and[/b] (minorVersion = [purple]10[/purple]) [b]then[/b]
[b]begin[/b]
[b]if[/b] osVerInfo.szCSDVersion[[purple]1[/purple]] = [teal]'A'[/teal] [b]then[/b]
Result := wv98SE
[b]else[/b]
Result := wv98;
[b]end[/b]
[b]else[/b] [b]if[/b] (majorVersion = [purple]4[/purple]) [b]and[/b] (minorVersion = [purple]90[/purple]) [b]then[/b]
Result := wvME
[b]else[/b]
Result := wvUnknown;
[b]end[/b];
[b]end[/b];
[b]end[/b];
[b]end[/b];
[b]function[/b] GetGlobalMemoryRecord: TMemoryStatusEx;
[b]type[/b]
TGlobalMemoryStatusEx = [b]procedure[/b]([b]var[/b] lpBuffer: TMemoryStatusEx); stdcall;
[b]var[/b]
ms : TMemoryStatus;
h : THandle;
gms : TGlobalMemoryStatusEx;
[b]begin[/b]
Result.dwLength := SizeOf(Result);
[b]if[/b] GetWinVersion [b]in[/b] [wvUnknown, wv95, wv98, wv98SE, wvNT, wvME] [b]then[/b]
[b]begin[/b]
ms.dwLength := SizeOf(ms);
GlobalMemoryStatus(ms);
Result.dwMemoryLoad := ms.dwMemoryLoad;
Result.ullTotalPhys := ms.dwTotalPhys;
Result.ullAvailPhys := ms.dwAvailPhys;
Result.ullTotalPageFile := ms.dwTotalPageFile;
Result.ullAvailPageFile := ms.dwAvailPageFile;
Result.ullTotalVirtual := ms.dwTotalVirtual;
Result.ullAvailVirtual := ms.dwAvailVirtual;
[b]end[/b]
[b]else[/b]
[b]begin[/b]
h := LoadLibrary(kernel32);
[b]try[/b]
[b]if[/b] h <> [purple]0[/purple] [b]then[/b]
[b]begin[/b]
@gms := GetProcAddress(h, [teal]'GlobalMemoryStatusEx'[/teal]);
[b]if[/b] @gms <> [b]nil[/b] [b]then[/b]
gms(Result);
[b]end[/b];
[b]finally[/b]
FreeLibrary(h);
[b]end[/b];
[b]end[/b];
[b]end[/b];
[b]function[/b] GetTotalRAM: Int64;
[b]begin[/b]
Result := GetGlobalMemoryRecord.ullTotalPhys;
[b]end[/b];
You can see from the record structure it is trivial to get other values from the system.
To ensure accurate reporting for systems that have between 2GB and 4GB of RAM, the /LARGEADDRESSAWARE flag must be set in the compiled .EXE. Delphi 6 and earlier don't have this as an option in the IDE, so you must include this line
Code:
[navy][i]{$SetPEFlags $0020} { /LargeAddressAware }[/i][[/navy]
I'm not sure if this option is included in D7 or above. Setting that option in the linker options if it's available should be enough.
One last code snippet to format the byte count to something more readable:
Code:
[navy][i]{ This function returns a formatted string with at the appropriate level of
bytes, kilobytes, megabytes, gigabytes, etc }[/i][/navy]
[b]function[/b] FormatBytes(ABytes: Int64): String;
[b]const[/b]
suffix : [b]array[/b][[purple]0..6[/purple]] [b]of[/b] String = ([teal]'B'[/teal], [teal]'KB'[/teal], [teal]'MB'[/teal], [teal]'GB'[/teal], [teal]'TB'[/teal], [teal]'PB'[/teal], [teal]'EB'[/teal]);
[b]var[/b]
l : Integer;
fr : Double;
[b]begin[/b]
l := [purple]0[/purple];
fr := ABytes;
[b]while[/b] fr >= [purple]1024[/purple] [b]do[/b]
[b]begin[/b]
inc(l);
fr := fr / [purple]1024[/purple];
[b]end[/b];
[b]if[/b] fr >= [purple]1000[/purple] [b]then[/b] [navy][i]// ensures eg. 1022 MB will show 0.99 GB
[/i][/navy] [b]begin[/b]
inc(l);
fr := fr / [purple]1024[/purple];
[b]end[/b];
[b]if[/b] l > High(suffix) [b]then[/b]
Result := [teal]'too large'[/teal]
[b]else[/b]
Result := Format([teal]'%f %s'[/teal], [fr, suffix[l]]);
[b]end[/b];