views:

9643

answers:

7

I'm wanting to get the total amount of RAM my computer has using C#. Using the PerformanceCounter I can get the amount of Available ram, by setting:

counter.CategoryName = "Memory";
counter.Countername = "Available MBytes";

But I can't seem to find a way to get the total amount of memory. How would I go about doing this?

Update:

MagicKat: I saw that when I was searching, but it doesn't work - "Are you missing an assembly or reference?". I've looked to add that to the References, but I don't see it there.

A: 

.net has a limit to the amount of memory it can access of the total. Theres a percentage, and then 2 GB in xp was the hard ceiling.

You could have 4 GB in it, and it would kill the app when it hit 2GB.

Also in 64 bit mode, there is a percentage of memory you can use out of the system, so I'm not sure if you can ask for the whole thing or if this is specifically guarded against.

From its perspective, total is what its allowed to have.

DevelopingChris
/No/. Total physical memory means the actual memory physically installed.
Matthew Flaschen
Actually, DevelopingChris is correct. If you call GlobalMemoryStatusEx on a XP machine with 4 Gig of Ram, it will report that there is only 3 Gig installed.
epotter
Also, using WMI to query TotalPhysicalMemory in Win32_ComputerSystem or Win32_LogicalMemoryConfiguration also produces the wrong result.
epotter
thank you, its not that I don't understand the question its that you have to use a different source for the information other than a .net library.
DevelopingChris
+17  A: 

Add a reference to Microsoft.VisualBasic and a using Microsoft.VisualBasic.Devices. The ComputerInfo class has all the information that you need.

MagicKat
Why on earth was this voted down? Voted back up! This is the easiest way to do it, and yes you can this from C#.
Paul Batum
+1: Some people have an aversion to referencing the Microsoft.VisualBasic namespace from C#, even though it's really just another assembly that's installed as a part of everything else.
Bevan
Thanks for the tip, I also noticed there's a bunch of other goodies in the Microsoft.VisualBasic.Devices namespace :)
DSO
I never new that namespace had system info in it. I'm a C# developer so I completely missed. Thanks so much MagicKat!
jlafay
+1  A: 

You could use WMI. Found a snippit.

Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" _ 
& strComputer & "\root\cimv2") 
Set colComputer = objWMIService.ExecQuery _
("Select * from Win32_ComputerSystem")

For Each objComputer in colComputer 
  strMemory = objComputer.TotalPhysicalMemory
Next
CodeRot
+11  A: 

The p/invoke way EDIT : Changed to GlobalMemoryStatusEx to give accurate results (heh)

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  private class MEMORYSTATUSEX
  {
     public uint dwLength;
     public uint dwMemoryLoad;
     public ulong ullTotalPhys;
     public ulong ullAvailPhys;
     public ulong ullTotalPageFile;
     public ulong ullAvailPageFile;
     public ulong ullTotalVirtual;
     public ulong ullAvailVirtual;
     public ulong ullAvailExtendedVirtual;
     public MEMORYSTATUSEX()
     {
        this.dwLength = (uint)Marshal.SizeOf(typeof(NativeMethods.MEMORYSTATUSEX));
     }
  }


  [return: MarshalAs(UnmanagedType.Bool)]
  [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);

Then use like:

ulong installedMemory;
MEMORYSTATUSEX memStatus = new MEMORYSTATUSEX();
if( GlobalMemoryStatusEx( memStatus))
{ 
   installedMemory = memStatus.ulTotalPhys;
}

Or you can use WMI (managed but slower) to query "TotalPhysicalMemory" in the "Win32_ComputerSystem" class.

Edit fixed code per comment from joel-llamaduck.blogspot.com

Philip Rieck
This is working! Thanks.One thing though - TotalPhysical is giving how much is in use, AvailablePhysical is giving how much is left. So get the real total, you have to add those up. Thanks!
Joel
That's not working...long ramuse = (long)stat.TotalPhysical;long ramavailable = (long)stat.AvailablePhysical;long ramtotal = ramavailable + ramuse;int percent = (int)( (float)ramuse / ramtotal * 100);percent is telling me "70" and total is constantly changing, give or take 100. should be 72%
Joel
Changed to GlobalMemoryStatusEx - GlobalMemoryStatus used uint and had problems - over 4GB would simply give garbage, but from 2GB-4GB would be rounded down to 2G for both avail and total.
Philip Rieck
The code works, only you dont need to use 'NativeMethods' to get the size of the object, you simply can say like this: `this.dwLength = (uint)Marshal.SizeOf(this);` and it works the same (I had trouble with using NativeMethods so this fix now works).
Cipi
"NativeMethods" is the namespace of the type. The call to SizeOf can be changed if you prefer.
Philip Rieck
+6  A: 

Add a reference to Microsoft.VisualBasic.dll, as someone mentioned above. Then getting total physical memory is as simple as this (yes, I tested it):

static ulong GetTotalMemoryInBytes()
{
    return new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory;
}
Kyralessa
+2  A: 

If you happen to be using Mono, then you might be interested to know that Mono 2.8 (to be released later this year) will have a performance counter which reports the physical memory size on all the platforms Mono runs on (including Windows). You would retrieve the value of the counter using this code snippet:

using System;
using System.Diagnostics;

class app
{
   static void Main ()
   {
       var pc = new PerformanceCounter ("Mono Memory", "Total Physical Memory");
       Console.WriteLine ("Physical RAM (bytes): {0}", pc.RawValue);
   }
}

If you are interested in C code which provides the performance counter, it can be found here.

grendel