# GPU-Z Shared Memory C# Wrapper



## JohnnyUT (Apr 12, 2012)

As I got some PNs that the link I've posted in the sticky thread 4 years ago is dead and other users still need the source code, I'll upload it again.  With this source code, C# developers can conveniently access the shared memory (and therefore the data) provided by GPU-Z within their programs.

Here's a link to a newly created .zip archive which includes two visual studio 2010 projects, one that's written in C++ and used to create a .dll and the other one to show how you can access the shared memory via the .dll in C#. Usually including the .dll into your project (such as done in the demo project) will be sufficient, but if that doesn't work, you might try to adjust/compile the .dll project by yourself. I've also compiled a x64 version of the .dll, but normally the 32 bit version should work also on all 64 bit OS.

Here is a short snippet from the demo project, showing how the shared memory can be accessed:

Code:


```
GpuzWrapper gpuz = new GpuzWrapper();
gpuz.Open();
Console.WriteLine(gpuz.DataKey(0) + ": " + gpuz.DataValue(0));
Console.WriteLine(gpuz.SensorName(0) + ": " + gpuz.SensorValue(0) + " " + gpuz.SensorUnit(0));
gpuz.Close();
```

Output:


```
DirectXSupport: 11.0
GPU Core Clock: 732,1149 MHz
```

The C# code is pretty straight forward. Please don't mind that I might have not used some fancy C# stuff that would have made the GpuzWrapper more convenient, but actually I'm a Java developer that programmed the whole thing 4 years ago.. 

Feel free to enjoy the demo and ask if something is unclear.

Here are some links to download it:
http://www.file-upload.net/download-4266506/GpuzShMem.zip.html
http://www.filedropper.com/gpuzshmem
https://github.com/JohnnyUT/GpuzShMem/zipball/master

And here is the link to the github project, if you want to take a look at the sources without downloading the whole archive:
https://github.com/JohnnyUT/GpuzShMem

PS: You might have to update the location of the GpuzShMem.dll file in the GpuzDemo project. I think visual studio uses the absolute path. -.-


----------



## W1zzard (Apr 12, 2012)

thanks. suggestion: put it on github


----------



## JohnnyUT (Apr 12, 2012)

Done. I added the link to the original post.


----------



## Kreij (Apr 12, 2012)

Thanks Johnny !!


----------



## Kreij (Apr 13, 2012)

Okay, I thought I'd try my hand at accessing the shared memory from GPU-Z as I haven't done anything with shared memory before.

I'm using that MemoryMappedFiles namespace they added in .Net 4
I sort of works. I get the version, busy and lastUpdate values okay (at least I think so), but I'm seeing garbage in the names and values of the data array of GPUZ_RECORD.



Spoiler: Code Inside





```
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.IO.MemoryMappedFiles;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            textBox1.Clear();
            GPUZSharedMem sharedMem = new GPUZSharedMem();
            sharedMem.GetSharedMemory();
            textBox1.Text = sharedMem.shMem.version.ToString() + Environment.NewLine;
            textBox1.Text += sharedMem.shMem.busy.ToString() + Environment.NewLine;
            textBox1.Text += sharedMem.shMem.lastUpdate.ToString() + Environment.NewLine;

            string keyarray = new string(sharedMem.shMem.data[2].key);
            string valuearray = new string(sharedMem.shMem.data[2].value);

            textBox1.Text += "2 -- " + keyarray.Trim() + Environment.NewLine;
            textBox1.Text += "2 -- " + valuearray.Trim() + Environment.NewLine;

        }
    }

    public class GPUZSharedMem
    {
        public const int MAX_RECORDS = 128;
        public class GPUZ_RECORD
        {
            public char[] key = new char[256];
            public char[] value = new char[256];
        };

        public class GPUZ_SENSOR_RECORD
        {
            public char[] name = new char[256];
            public char[] unit = new char[8];
            public UInt32 digits;
            public Double value;
        };

        public class GPUZ_SH_MEM
        {
            public UInt32 version;
            public Int64 busy; // C# does not support volatile references to long.
            public UInt32 lastUpdate;
            public GPUZ_RECORD[] data = new GPUZ_RECORD[MAX_RECORDS];
            public GPUZ_SENSOR_RECORD[] sensors = new GPUZ_SENSOR_RECORD[MAX_RECORDS];
        };

        public GPUZ_SH_MEM shMem = new GPUZ_SH_MEM();

        public GPUZSharedMem()
        {
            for (int i = 0; i < MAX_RECORDS; i++) shMem.data[i] = new GPUZ_RECORD();
            for (int i = 0; i < MAX_RECORDS; i++) shMem.sensors[i] = new GPUZ_SENSOR_RECORD();
        }

        public void GetSharedMemory()
        {
            using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting("GPUZShMem"))
            {
                using (MemoryMappedViewStream mmvs = mmf.CreateViewStream())
                {
                    BinaryReader reader = new BinaryReader(mmvs);

                    shMem.version = reader.ReadUInt32();
                    shMem.busy = reader.ReadInt64();
                    shMem.lastUpdate = reader.ReadUInt32();

                    for (int i = 0; i < MAX_RECORDS; i++)
                    {
                        shMem.data[i].key = reader.ReadChars(256);
                        shMem.data[i].value = reader.ReadChars(256);
                    }

                    for (int i = 0; i < MAX_RECORDS; i++)
                    {
                        shMem.sensors[i].name = reader.ReadChars(256);
                        shMem.sensors[i].unit = reader.ReadChars(8);
                        shMem.sensors[i].digits = reader.ReadUInt32();
                        shMem.sensors[i].value = reader.ReadDouble();
                    }
                }
            }
        }
    }
}
```




Maybe a problem with the c# char type and WCHAR ?
Maybe something with mem boundaries of the way structures are stored?
Maybe I don't have a clue what I doing ? <---- most likely scenario 

Any thoughts appreciated.


----------



## W1zzard (Apr 13, 2012)

WCHAR is a 16 bit unicode character

#pragma pack(push, 1) means 1-byte aligned structure members


----------



## Kreij (Apr 13, 2012)

Got a bit farther. Yay !

I forced the BinaryReader to use unicode decoding for text (which I thought was the default, but apparently not)

```
BinaryReader reader = new BinaryReader(stream, Encoding.Unicode);
```

Realized that GPU-Z is saving the busy value (long) as 4 bytes, not 8, so a quick change to ReadInt32 got things back in line. I forgot about "long long" in C++ as C# always makes longs 8 bytes.

... after much code abuse ...

Everything works with no DLLImports of PInvoke calls. WooHooo !!
Now to make it useful. lol


----------

