I’m working on a new build of TSAdminEx for which I need to query the total amount of physical memory. Locally we can use the GlobalMemoryStatusEx API but there’s no API to do this remotely. It would be possible using WMI but I decided not to use that because I dislike it because of it’s slowness and I need support for older OS versions which might not have WMI.

So I found in the registry the following key:

HKLM\HARDWARE\RESOURCEMAP\System Resources\Physical Memory

It has a value .Translated of type RES_RESOURCE_LIST which seems undocumented besides stating that it exists. Regedit knows how to handle it though. If you doubleclick on the key you will see something like this:

ResourceLists

If we click on the list and choose display we see the following:

Resources

If we sum the Length of all memory blocks we get the total amount of Physical Memory. I wondered how to do this programmatically so I Googled on it but found mostly pages where the values are extracted at fixed offsets rather than knowing the correct structure. I found however that the structure is present in the DDK (wdm.h) and is called CM_RESOURCE_LIST. I was also lucky because Jack van Nuenen had already done a conversion of those headers to Delphi which saved me some work. I did some small modifications to the headers and included them in a new unit into the Jedi Apilib (JwaWdm.pas).

Let’s take a look at the structure:

ANYSIZE_ARRAY is a constant from the Windows PSDK which is meant to make a dummy array, so here we make actually an array[0..0]. However the compiler permits us to do array[1], array[2] if we turn off range checking so this makes it easier to loop through the array.

The CM_FULL_RESOURCE_DESCRIPTOR describes the resource:

And finally points to a CM_PARTIAL_RESOURCE_LIST structure:

Which in turn points to an array of CM_PARTIAL_RESOURCE_DESCRIPTOR structures:

We are interested in the RDD_MEMORY structure which finally gives us the requested information (Length):

So it’s just a matter of looping through the Partial Descriptor array and summing up the Lengths. However on a x64 (64 bit) Windows the memory length is a 8 bytes instead of 4 byte, so we need to account for that. If we use a 64 bit compiler it will handle this automatically because the ULONG type is 8 bytes then. That will make it impossible though to query remote 32 bit systems from 64 bit or vice versa. So I wondered how Taskmanager handled that, the answer is: IT DOESN’T! See the following example:

Querying locally on 32 bit system:

x86Local

Now I query the same machine remotely from a 64 bit system:

x86Remote

I think it can only be solved by using two different structures, one for x86 and one for x64. So I introduced the following structures:

Now we need a generic function to query both x86 and x64 (I use the Environment variable PROCESSOR_ARCHITECTURE to determine if a system is 64bit):