I need to log information about how much RAM the user has. My first approach was to use GlobalMemoryStatusEx but that only gives me how much memory is available to windows, not how much is installed. I found this function GetPhysicallyInstalledSystemMemory but its only Vista and later. I need this to work on XP. Is there a fairly simple way of querying the SMBIOS information that GetPhysicallyInstalledSystemMemory was using or is there a registry value somewhere that I can find this out.
One of the values returned by GlobalMemoryStatusEx is ullTotalPhys, which seems to be what you're looking for.
Things like ram used for video memory isn't in there, but I doubt there is a way to get to that at all.
I think WMI may give you this info ...
http://briandesmond.com/blog/getting-total-installed-memory-with-wmi/
EDIT: I'd use steelbytes' answer, but if you can't use WMI For some reason, you can do this:
I don't believe Windows versions prior to Vista track this information -- you'd have to do some system specific BIOS or Motherboard enumeration to find the true value prior to Vista. Your best bet is to call the new API, GetPhysicallyInstalledSystemMemory
, and fail over to GlobalMemoryStatusEx
for XP systems.
You should take a look at the Win32_ComputerSystem Class (WMI) and the TotalPhysicalMemory property. There are ways to access this information via .Net via the System.Management namespace for managed code (I use C#, so I haven't tried using visual studio for c++ development myself). You could also create a script to run WMI directly and have your c++ program call the script.
UPDATE: You may also look at the Win32_PhysicalMemory Class (take a look at the Capacity property). This will alleviate inaccurate readings due to the BIOS using some of the RAM etc.
UPDATE 2:
I've tried this in C# (3.5) and Windows XP (SP 2) and it works. I'm sure you can do something similar with the same WMI classes in C++ (at least through Visual Studio). It works no problem, so it's not a Vista or greater issue. I'm not sure if this is exactly what you are looking for, but this code will return the total physical memory capacity of the system (not how much is free). Hopefully this is what you meant. Anyway here is some sample code that locates each stick of RAM and displays some info about each one (including capacity) and then the total at the bottom:
using System;
using System.Collections.Generic;
using System.Management;
using System.Text;
namespace WmiTest
{
public class RamCounter
{
private List<RamStick> _ramSticks;
private int _totalRam;
private StringBuilder _stringRepresentation;
public RamCounter()
{
_ramSticks = new List<RamStick>();
_totalRam = 0;
_stringRepresentation = new StringBuilder();
}
public void GetRamSticks()
{
_ramSticks.Clear();
_totalRam = 0;
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMemory");
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject mo in queryCollection)
{
_ramSticks.Add(
new RamStick(Convert.ToUInt64(mo.GetPropertyValue("Capacity")),
mo.GetPropertyValue("DeviceLocator").ToString(),
mo.GetPropertyValue("Description").ToString(),
Convert.ToUInt32(mo.GetPropertyValue("FormFactor")),
Convert.ToUInt32(mo.GetPropertyValue("Speed"))));
}
}
public override string ToString()
{
_stringRepresentation.Capacity = 0;
foreach (RamStick rs in _ramSticks)
{
_stringRepresentation.Append(rs.ToString());
_totalRam += rs.CapacityInMB;
}
_stringRepresentation.Append("Total RAM(MB): " + _totalRam);
return _stringRepresentation.ToString();
}
}
public class RamStick
{
private UInt64 _capacity;
private UInt32 _formFactor;
public RamStick(UInt64 capacity, string location, string description, UInt32 formFactor, UInt32 speed)
{
_capacity = capacity;
Location = location;
Description = description;
_formFactor = formFactor;
Speed = speed;
}
public int CapacityInMB
{
get { return Convert.ToInt32(_capacity / (1024 * 1024)); }
}
public string Location
{
get;
private set;
}
public string Description
{
get;
private set;
}
public string GetFormFactor()
{
string formFactor = string.Empty;
switch (_formFactor)
{
case 1:
formFactor = "Other";
break;
case 2:
formFactor = "SIP";
break;
case 3:
formFactor = "DIP";
break;
case 4:
formFactor = "ZIP";
break;
case 5:
formFactor = "SOJ";
break;
case 6:
formFactor = "Proprietary";
break;
case 7:
formFactor = "SIMM";
break;
case 8:
formFactor = "DIMM";
break;
case 9:
formFactor = "TSOP";
break;
case 10:
formFactor = "PGA";
break;
case 11:
formFactor = "RIMM";
break;
case 12:
formFactor = "SODIMM";
break;
case 13:
formFactor = "SRIMM";
break;
case 14:
formFactor = "SMD";
break;
case 15:
formFactor = "SSMP";
break;
case 16:
formFactor = "QFP";
break;
case 17:
formFactor = "TQFP";
break;
case 18:
formFactor = "SOIC";
break;
case 19:
formFactor = "LCC";
break;
case 20:
formFactor = "PLCC";
break;
case 21:
formFactor = "BGA";
break;
case 22:
formFactor = "FPBGA";
break;
case 23:
formFactor = "LGA";
break;
default:
formFactor = "Unknown";
break;
}
return formFactor;
}
public UInt32 Speed
{
get;
private set;
}
public override string ToString()
{
return string.Format("Description:{1}{0}"
+ "Location:{2}{0}"
+ "Form Factor:{3}{0}"
+ "Speed:{4}{0}"
+ "Capacity(MB):{5}{0}{0}",
Environment.NewLine,
Description,
Location,
GetFormFactor(),
Speed,
CapacityInMB);
}
}
}
To use the code:
private void btnRam_Click(object sender, EventArgs e)
{
RamCounter rc = new RamCounter();
rc.GetRamSticks();
MessageBox.Show(rc.ToString());
}
Sample output from my machine:
Description: Physical Memory
Location: J6H1
Format Factor: DIMM
Speed: 667
Capacity(MB): 1024
Description: Physical Memory
Location: J6H2
Format Factor: DIMM
Speed: 667
Capacity(MB): 1024
Description: Physical Memory
Location: J6J1
Format Factor: DIMM
Speed: 667
Capacity(MB): 1024
Total RAM(MB): 3072