Inaccurate WMI data - c#

I'm trying to get the total VRAM of a system using WMI calls, I'm testing in my dev machine which has a NVIDIA GTX 1080 8GB GPU but the property AdapterRAM from Win32_VideoController says that my card only has 4 GB of VRAM. Not sure if there's any issue with the property or my code.
Here's the code I'm using
private void GetVideoInfo()
{
foreach (var mgmtObj in GetManagementClassProperties("Win32_VideoController"))
{
VideoInfoLabel.Content = ToUInt64(mgmtObj["AdapterRAM"]) / 1073741824;
}
}
public ManagementObjectCollection GetManagementClassProperties(string id)
{
return new ManagementClass(id).GetInstances();
}
Thanks!

Related

C# how to effectively detect which graphic card is used [duplicate]

My C# application sits on the embedded box which has Intel motherboard and graphics chipset. ATI graphics card is put on to PCI express. Generally graphics card drives the video, but if ATI card fails then the video comes out from graphics chipset.
I have to detect the failure of ATI graphics card for diagnostic purposes.
Any ideas/sample code on how to do this.
Thanks in advance
Raju
This should hopefully get you started.
Add a reference to System.Management, then you can do this:
ManagementObjectSearcher searcher
= new ManagementObjectSearcher("SELECT * FROM Win32_DisplayConfiguration");
string graphicsCard = string.Empty;
foreach (ManagementObject mo in searcher.Get())
{
foreach (PropertyData property in mo.Properties)
{
if (property.Name == "Description")
{
graphicsCard = property.Value.ToString();
}
}
}
In my case, graphicsCard is equal to
NVIDIA GeForce 8400 GS (Microsoft
Corporation - WDDM v1.1)
I'm not a fan of how the selected answer only returns the first video controller. Also, there's no need to loop over all the properties. Just get the ones you need. If CurrentBitsPerPixel is not null, then you're looking at one of the active controllers. I'm using Win32_VideoController as suggested by #bairog, instead of the deprecated Win32_DisplayConfiguration.
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("SELECT * FROM Win32_VideoController");
foreach (ManagementObject mo in searcher.Get())
{
PropertyData currentBitsPerPixel = mo.Properties["CurrentBitsPerPixel"];
PropertyData description = mo.Properties["Description"];
if (currentBitsPerPixel != null && description != null)
{
if (currentBitsPerPixel.Value != null)
System.Console.WriteLine(description.Value);
}
}
My machine has 3 video controllers. The first one is not active (ShoreTel). The second one is active, but is not the video card (Desktop Authority). The third one is my NVidia. This code will print out both the DA controller and the NVidia controller.
Promoted answer works only for single video card system. When I have ATI and Nvidia cards - WMI query returns ATI even if that monitor is plugged into Nvidia card, dxdiag shows Nvidia and games runs on that card (usage).
The only way I could determine right video card was using SlimDX to create DX device and examine what card it used. However that .dll weights over 3Mb.
var graphicsCardName = new Direct3D().Adapters[0].Details.Description;
Your question isn't entirely clear, so I'm not sure if the follwing idea will help or not.
Perhaps something very simple would suffice:
If the two graphics cards run different resolutions check the monitor resolution using:
System.Windows.Forms.SystemInformation.PrimaryMonitorSize
Similarly, if one card supports more than one monitor, check the number of monitors using SystemInformation.MonitorCount.
I tried all the approaches in this question but none gives me a correct answer. However I found it possible to get your current using the Win32_DisplayControllerConfiguration class. Although according to MSDN this class is obsolete, it's the only one returning a correct answer:
using System;
using System.Management;
using System.Windows.Forms;
namespace WMISample
{
public class MyWMIQuery
{
public static void Main()
{
try
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_DisplayControllerConfiguration");
foreach (ManagementObject queryObj in searcher.Get())
{
Console.WriteLine("----------------------------------- ");
Console.WriteLine("Win32_DisplayControllerConfiguration instance");
Console.WriteLine("-----------------------------------");
Console.WriteLine("Name: {0}", queryObj["Name"]);
}
}
catch (ManagementException e)
{
MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
}
}
}
}
(Code generated by WMI Code Creator, a great tool if you are messing with WMI.)
This gives GeForce GTX 1080 on my Windows 10 (RS2) + Intel(R) HD Graphics 4600 + NVIDIA GeForce GTX 1080 system.
Sometimes I need to switch between the Nvidia GPU and onboard GPU. To know which is connected to the monitor, I use the property MinRefreshRate. It works reliably for me, not CurrentBitsPerPixel.
public static void UpdateActiveGpu()
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_VideoController");
foreach (ManagementObject mo in searcher.Get())
{
PropertyData minRefreshRate = mo.Properties["MinRefreshRate"];
PropertyData description = mo.Properties["Description"];
if (minRefreshRate != null && description != null && minRefreshRate.Value != null)
{
Global.Instance.activeGpu = description.Value.ToString();
break;
}
}
}

How to get total GPU RAM (over 4gb memory)?

I am trying to get total GPU memory value. I tried with WMI but it returns not higher value than 4gb.
After reading few articles I found out Cudafy.
public static ulong GetGpuMemory()
{
GPGPU gpu = CudafyHost.GetDevice(CudafyModes.Target, CudafyModes.DeviceId);
var c = gpu.GetDeviceProperties(true);
var p = c.TotalMemory;
return p;
}
For some reason it is returning max ulong value.
Any ideas?
Do you know any other way to get correct GPU memory value from both - NVIDIA and AMD GPUs? What about taking hex value from registry and then converting it? I tried to write some code but without success. Thanks for any help in advance
This should work:
using Microsoft.Win32;
...
long getvideomem()
{
try
{
using (RegistryKey key = Registry.LocalMachine.OpenSubKey(#"SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0000"))
{
if (key != null)
{
object o = key.GetValue("HardwareInformation.qwMemorySize");
if (o != null)
return (long)o;
}
}
}
catch { }
return 0;
}
Multiple GPU systems would need some tweaks however.

Controlling Application's Volume & VU Meter

I am using NAudio for a screen recording software I am designing and I need to know if it's possible to not only control the specific application's volume but also display a VU Meter for the application's sound.
I've Googled all over the place and it seems I can only get a VU Meter for the devices currently on my computer and set the volume for those devices.
Even though I am using NAudio, I am open to other solutions.
I asked the question in more detail after this question. I have since found the answer so I will leave the answer here for those who stumble upon it. Trying to use NAudio & CSCore has gotten me quite familiar with so please ask if you need further assistance.
This block of code uses CSCore and is a modified and commented version of the answer found here:Getting individual windows application current volume output level as visualized in audio Mixer
class PeakClass
{
static int CurrentProcessID = 0000;
private static void Main(string[] args)
{
//Basically gets your default audio device and session attached to it
using (var sessionManager = GetDefaultAudioSessionManager2(DataFlow.Render))
{
using (var sessionEnumerator = sessionManager.GetSessionEnumerator())
{
//This will go through a list of all processes uses the device
//the code got two line above.
foreach (var session in sessionEnumerator)
{
//This block of code will get the peak value(value needed for VU Meter)
//For whatever process you need it for (I believe you can also check by name
//but I found that less reliable)
using (var session2 = session.QueryInterface<AudioSessionControl2>())
{
if(session2.ProcessID == CurrentProcessID)
{
using (var audioMeterInformation = session.QueryInterface<AudioMeterInformation>())
{
Console.WriteLine(audioMeterInformation.GetPeakValue());
}
}
}
//Uncomment this block of code if you need the peak values
//of all the processes
//
//using (var audioMeterInformation = session.QueryInterface<AudioMeterInformation>())
//{
// Console.WriteLine(audioMeterInformation.GetPeakValue());
//}
}
}
}
}
private static AudioSessionManager2 GetDefaultAudioSessionManager2(DataFlow dataFlow)
{
using (var enumerator = new MMDeviceEnumerator())
{
using (var device = enumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia))
{
Console.WriteLine("DefaultDevice: " + device.FriendlyName);
var sessionManager = AudioSessionManager2.FromMMDevice(device);
return sessionManager;
}
}
}
}
The following code block will allow you to change the volume of the device using NAudio
MMDevice VUDevice;
public void SetVolume(float vol)
{
if(vol > 0)
{
VUDevice.AudioEndpointVolume.Mute = false;
VUDevice.AudioEndpointVolume.MasterVolumeLevelScalar = vol;
}
else
{
VUDevice.AudioEndpointVolume.Mute = true;
}
Console.WriteLine(vol);
}
I have code from two different libraries only to answer the question I posted directly which was how to both set the volume and get VU Meter values (peak values). CSCore and NAudio are very similar so most of the code here is interchangeable.

Getting individual windows application current volume output level as visualized in audio Mixer

I am trying to write a C# code that outputs the current audio output level from each of the windows application accessing the sound output (as shown with constantly changing green bars of the Volume mixer).
The program will check every 10 ms, and outputs sth like this: Windows Media Player: 30, Mozilla Firefox: 0, Adobe Flash Player: 35 (as per the figure)
I am using Windows 7, and trying it in C# (as Java cannot achieve this).
I have found ways to get and set the Master Volume (the handle bar which shows 65% for Windows Media Player) for a running application, is there a way to get the green fluctuating level data?
Thank you!
You can use CSCore.
There is a wrapper for the CoreAudioAPI-Audiosessions. Use something like that (for more details take a look at the unittests: AudioSession-UnitTests):
private static void Main(string[] args)
{
using (var sessionManager = GetDefaultAudioSessionManager2(DataFlow.Render))
{
using (var sessionEnumerator = sessionManager.GetSessionEnumerator())
{
foreach (var session in sessionEnumerator)
{
using (var audioMeterInformation = session.QueryInterface<AudioMeterInformation>())
{
Console.WriteLine(audioMeterInformation.GetPeakValue());
}
}
}
}
Console.ReadKey();
}
private static AudioSessionManager2 GetDefaultAudioSessionManager2(DataFlow dataFlow)
{
using (var enumerator = new MMDeviceEnumerator())
{
using (var device = enumerator.GetDefaultAudioEndpoint(dataFlow, Role.Multimedia))
{
Debug.WriteLine("DefaultDevice: " + device.FriendlyName);
var sessionManager = AudioSessionManager2.FromMMDevice(device);
return sessionManager;
}
}
}
To control an applications volume, take a look at the unit-tests here.
Here is a sample application which displays the audio levels from running applications in a graph. There are two versions, one in WPF and one in Windows.Forms. They use the method from Florian's answer to get the audio levels.
https://github.com/jeske/SoundLevelMonitor

CPU temperature monitoring

For a programming project I would like to access the temperature readings from my CPU and GPUs. I will be using C#. From various forums I get the impression that there is specific information and developer resources you need in order to access that information for various boards. I have a MSI NF750-G55 board. MSI's website does not have any of the information I am looking for. I tried their tech support and the rep I spoke with stated they do not have any such information. There must be a way to obtain that info.
Any thoughts?
For at least the CPU side of things, you could use WMI.
The namespace\object is root\WMI, MSAcpi_ThermalZoneTemperature
Sample Code:
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\WMI",
"SELECT * FROM MSAcpi_ThermalZoneTemperature");
ManagementObjectCollection collection =
searcher.Get();
foreach(ManagementBaseObject tempObject in collection)
{
Console.WriteLine(tempObject["CurrentTemperature"].ToString());
}
That will give you the temperature in a raw format. You have to convert from there:
kelvin = raw / 10;
celsius = (raw / 10) - 273.15;
fahrenheit = ((raw / 10) - 273.15) * 9 / 5 + 32;
The best way to go for hardware related coding on windows is by using WMI which is a Code Creator tool from Microsoft, the tool will create the code for you based on what you are looking for in hardware related data and what .Net language you want to use.
The supported langauges currently are: C#, Visual Basic, VB Script.
Note that MSAcpi_ThermalZoneTemperature does not give you the temperature of the CPU but rather the temperature of the motherboard. Also, note that most motherboards do not implement this via WMI.
You can give the Open Hardware Monitor a go, although it lacks support for the latest processors.
internal sealed class CpuTemperatureReader : IDisposable
{
private readonly Computer _computer;
public CpuTemperatureReader()
{
_computer = new Computer { CPUEnabled = true };
_computer.Open();
}
public IReadOnlyDictionary<string, float> GetTemperaturesInCelsius()
{
var coreAndTemperature = new Dictionary<string, float>();
foreach (var hardware in _computer.Hardware)
{
hardware.Update(); //use hardware.Name to get CPU model
foreach (var sensor in hardware.Sensors)
{
if (sensor.SensorType == SensorType.Temperature && sensor.Value.HasValue)
coreAndTemperature.Add(sensor.Name, sensor.Value.Value);
}
}
return coreAndTemperature;
}
public void Dispose()
{
try
{
_computer.Close();
}
catch (Exception)
{
//ignore closing errors
}
}
}
Download the zip from the official source, extract and add a reference to OpenHardwareMonitorLib.dll in your project.

Categories

Resources