1. Welcome to TechPowerUp Forums, Guest! Please check out our forum guidelines for info related to our community.

GPU-Z Shared Memory C# Wrapper

Discussion in 'GPU-Z' started by JohnnyUT, Apr 12, 2012.

  1. JohnnyUT New Member

    Joined:
    Jul 14, 2008
    Messages:
    7 (0.00/day)
    Thanks Received:
    4
    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:

    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:

    Code:
    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.. :D

    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. -.-
     
    Last edited: Apr 12, 2012
    Kreij says thanks.
  2. W1zzard

    W1zzard Administrator Staff Member

    Joined:
    May 14, 2004
    Messages:
    15,008 (3.90/day)
    Thanks Received:
    11,877
    thanks. suggestion: put it on github
     
  3. JohnnyUT New Member

    Joined:
    Jul 14, 2008
    Messages:
    7 (0.00/day)
    Thanks Received:
    4
    Done. I added the link to the original post. ;)
     
  4. Kreij

    Kreij Senior Monkey Moderator Staff Member

    Joined:
    Feb 6, 2007
    Messages:
    13,881 (4.87/day)
    Thanks Received:
    5,616
    Location:
    Cheeseland (Wisconsin, USA)
    Thanks Johnny !! :toast:
     
  5. Kreij

    Kreij Senior Monkey Moderator Staff Member

    Joined:
    Feb 6, 2007
    Messages:
    13,881 (4.87/day)
    Thanks Received:
    5,616
    Location:
    Cheeseland (Wisconsin, USA)
    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.

    Code:
    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 :D

    Any thoughts appreciated.
     
  6. W1zzard

    W1zzard Administrator Staff Member

    Joined:
    May 14, 2004
    Messages:
    15,008 (3.90/day)
    Thanks Received:
    11,877
    WCHAR is a 16 bit unicode character

    #pragma pack(push, 1) means 1-byte aligned structure members
     
    Kreij says thanks.
  7. Kreij

    Kreij Senior Monkey Moderator Staff Member

    Joined:
    Feb 6, 2007
    Messages:
    13,881 (4.87/day)
    Thanks Received:
    5,616
    Location:
    Cheeseland (Wisconsin, USA)
    Got a bit farther. Yay !

    I forced the BinaryReader to use unicode decoding for text (which I thought was the default, but apparently not)
    Code:
    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
     
    Last edited: Apr 13, 2012

Currently Active Users Viewing This Thread: 1 (0 members and 1 guest)

Share This Page