System Delphi

Title: How do I determine the amount of RAM?
It's become more difficult to determine the amount of RAM in a system, since 2GB became more common, and some operating systems don't handle reporting of more than 2GB correctly. The following code should handle any combination of OS and RAM amount.
CODE
// for automatic syntax highlighting see FAQ102-6487: How to include syntax highlighting in code examples.
uses
Windows;
type
TMemoryStatusEx =
record
dwLength: DWORD;
dwMemoryLoad: DWORD;
ullTotalPhys: Int64;
ullAvailPhys: Int64;
ullTotalPageFile: Int64;
ullAvailPageFile: Int64;
ullTotalVirtual: Int64;
ullAvailVirtual: Int64;
ullAvailExtendedVirtual: Int64;

end
;
function
GetGlobalMemoryRecord: TMemoryStatusEx;
type
TGlobalMemoryStatusEx =
procedure
(
var
lpBuffer: TMemoryStatusEx);
stdcall
;
var
ms : TMemoryStatus;
h : THandle;
gms : TGlobalMemoryStatusEx;
begin
Result.dwLength := SizeOf(Result);
h := LoadLibrary(kernel32);

try

if
h
0

then

begin
@gms := GetProcAddress(h,
'GlobalMemoryStatusEx'
);

if
@gms
nil

then
gms(Result)

else

begin
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;

end

end
;

finally
FreeLibrary(h);

end
;
end
;
function
GetTotalRAM: Int64;
begin
Result := GetGlobalMemoryRecord.ullTotalPhys;
end
;
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
{$SetPEFlags $0020} { /LargeAddressAware }
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:
CODE
{ This function returns a formatted string with at the appropriate level of bytes, kilobytes, megabytes, gigabytes, etc }
function
FormatBytes(ABytes: Int64; AShortRounding: Boolean = True): String;
const
suffix :
array
[
0..6
]
of
String = (
'B'
,
'KB'
,
'MB'
,
'GB'
,
'TB'
,
'PB'
,
'EB'
);
var
l : Integer;
f : Double;
begin
l :=
0
;
f := ABytes;

while
(l and
(f =
1024
)
do

begin
inc(l);
f := f /
1024
;

end
;

if
AShortRounding
and
(l and
(f =
1000
)
then

begin

// ensures eg. 1022 MB will show 0.99 GB
inc(l);
f := f /
1024
;

end
;
Result := Format(
'%f %s'
, [f, suffix[l]]);
end
;