Reputation: 11
i'm making a program to monitor hardware components and I am trying to get the RAM capacity of the desktop using the WMI Win32_ComptuterSystem
class. I managed to get the amount of total RAM but it is displayed in bits instead of GB, I know i have to make a conversion but I have no idea how to go about it.
private void GetRamCapacity()
{
var wmi = new ManagementClass("Win32_ComputerSystem");
var providers = wmi.GetInstances();
foreach (var provider in providers)
{
var ramCapacity = Convert.ToInt32(provider["TotalPhysicalMemory"]);
lblRAMCapacity.Text = ramCapacity.ToString();
}
}
Upvotes: 0
Views: 1122
Reputation: 32223
Note that TotalPhysicalMemory returns an UInt64
value.
Convert it to ulong
instead of Int32
. Also, the value is expressed in Bytes
:
But you should probably use the value returned by the Capacity
property of the Win32_PhysicalMemory class. The Capacity
value is provided per Memory Bank.
The reason is explained in a note:
Be aware that, under some circumstances, this property may not return an accurate value for the physical memory. For example, it is not accurate if the BIOS is using some of the physical memory.
From GetPhysicallyInstalledSystemMemory:
The BIOS and some drivers may reserve memory as I/O regions for memory-mapped devices, making the memory unavailable to the operating system and applications.
The sum of the values returned by Win32_PhysicalMemory.Capacity
is the same value returned by GetPhysicallyInstalledSystemMemory
(the latter is expressed in kilobytes).
A machine must have the SMBIOS feature available (Windows XP and later), otherwise these functions won't return a value.
An example:
ulong totalMemory = WMIGetTotalPhysicalMemory();
string memory = $"{totalMemory / Math.Pow(1024, 3):N2} GB";
The WMIGetTotalPhysicalMemory()
method uses the WMI
Win32_PhysicalMemory
class per-bank Capacity
value, summing each bank's installed memory size.
public static ulong WMIGetTotalPhysicalMemory()
{
var mScope = new ManagementScope($@"\\{Environment.MachineName}\root\CIMV2");
var mQuery = new SelectQuery("SELECT * FROM Win32_PhysicalMemory");
mScope.Connect();
ulong installedMemory = 0;
using (var moSearcher = new ManagementObjectSearcher(mScope, mQuery))
{
foreach (ManagementObject moCapacity in moSearcher.Get()) {
installedMemory += (UInt64)moCapacity["Capacity"];
}
}
return installedMemory;
}
A comparison method using GetPhysicallyInstalledSystemMemory()
:
(This value and the value returned by WMIGetTotalPhysicalMemory
must be the same)
ulong totalMemory = WinAPIGetTotalPhysicalMemory();
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetPhysicallyInstalledSystemMemory(out ulong MemInKilobytes);
public static ulong GetTotalPhysicalInstalledMemory()
{
ulong totalMemory = 0UL;
bool result = GetPhysicallyInstalledSystemMemory(out totalMemory);
if (!result) totalMemory = 0UL;
return totalMemory * 1024;
}
If GetPhysicallyInstalledSystemMemory
fails, totalMemory
will be 0
.
This function fails if the SMBIOS data is not considered valid or it's less than the value returned by the GlobalMemoryStatusEx() function.
In this case, GetLastError will return ERROR_INVALID_DATA = 13
.
GlobalMemoryStatusEx
returns a MEMORYSTATUSEX
structure which references the current state of both physical and virtual memory, plus the approximate percentage of physical memory that is in use.
Note that these values are volatile an will change between calls: the Memory status changes constantly.
See the MSDN notes about the meaning of these values.
MEMORYSTATUSEX memoryStatus = GetSystemMemoryStatus();
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class MEMORYSTATUSEX
{
public uint dwLength;
/// <summary> Number between 0 and 100 that specifies the approximate percentage of physical memory that is in use (0 indicates no memory use and 100 indicates full memory use). </summary>
public uint dwMemoryLoad;
/// <summary> Total size of physical memory, in bytes. </summary>
public ulong ullTotalPhys;
/// <summary> Size of physical memory available, in bytes. </summary>
public ulong ullAvailPhys;
/// <summary> Size of the committed memory limit, in bytes. This is physical memory plus the size of the page file, minus a small overhead. </summary>
public ulong ullTotalPageFile;
/// <summary> Size of available memory to commit, in bytes. The limit is ullTotalPageFile. </summary>
public ulong ullAvailPageFile;
/// <summary> Total size of the user mode portion of the virtual address space of the calling process, in bytes. </summary>
public ulong ullTotalVirtual;
/// <summary> Size of unreserved and uncommitted memory in the user mode portion of the virtual address space of the calling process, in bytes. </summary>
public ulong ullAvailVirtual;
/// <summary> Size of unreserved and uncommitted memory in the extended portion of the virtual address space of the calling process, in bytes. </summary>
public ulong ullAvailExtendedVirtual;
/// <summary> Initializes a new instance of the MEMORYSTATUSEX class. </summary>
public MEMORYSTATUSEX() => this.dwLength = (uint)Marshal.SizeOf<MEMORYSTATUSEX>();
}
public static MEMORYSTATUSEX GetSystemMemoryStatus()
{
var memoryStatus = new MEMORYSTATUSEX();
GlobalMemoryStatusEx(memoryStatus);
return memoryStatus;
}
Upvotes: 3