I use a WMI in a couple of places in a few applications but sometimes the application gets stuck at the WMI get method. When this happens nothing seems to be able to recover it except for a machine restart. Stopping debugging / ending process in task manager and then restarting the application causes it to hang at the same point. Once WMI has started hanging no application is able to get any results. Waiting for WMI to recover takes an indefinite amount of time and never seems to amount to any following improvements until a machine restart.
A couple of my code extracts:
GetInstances() is where this code hangs.
public static ChassisTypes GetCurrentChassisType()
{
ManagementClass systemEnclosures = new ManagementClass("Win32_SystemEnclosure");
ManagementObjectCollection results = systemEnclosures.GetInstances();
foreach (ManagementObject obj in results)
{
foreach (int i in (UInt16[])(obj["ChassisTypes"]))
{
if (i > 0 && i < 25)
{
return (ChassisTypes)i;
}
}
}
return ChassisTypes.Unknown;
}
Get() is where this code hangs.
public static string GetOSInfo()
{
System.Management.ManagementObjectSearcher objMOS = new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem");
try
{
foreach (ManagementObject objManagement in objMOS.Get())
{
// Do stuff to build OS version string
}
}
catch (Exception)
{
}
return OSName;
}
How do I stop the calls from hanging and freezing the rest of WMI?
You have to be sure you're using right WMI instructions. Try debugging you app with breakpoints to find out what may be wrong.
Nice WMI usage sample (Task Manager) (sources available for download) on my blog (written in Russian) may help you
I have a method to determine battery level and kept a timer to periodically check the battery level.
void GetBatteryLevel()
{
try
{
//Use this code in next build
//System.Windows.Forms.PowerStatus status = System.Windows.Forms.SystemInformation.PowerStatus;
double batteryLevel;
ManagementObjectSearcher mos = new ManagementObjectSearcher("select EstimatedChargeRemaining from Win32_Battery");
ManagementObjectCollection collection = mos.Get();
foreach (ManagementObject mo in collection)
{
UInt16 remainingPercent = (UInt16)mo["EstimatedChargeRemaining"];
batteryLevel = (double)remainingPercent;
batteryLevel = batteryLevel / 100;
batteryLevel = 1.0 - batteryLevel;
BatteryLevel = new System.Windows.Point(0.0, batteryLevel);
}
}
catch (Exception exp)
{
Logger.LogMessage("EXCEPTION: " + exp.StackTrace);
}
}
Is there a way to register for events when battery level drops or increases by 1%? I have already registered for SystemEvents.PowerModeChanged and that works fine.
Short answer is from the .Net base class library no.
With that said there are power events available but these events reside in kernel32. Microsoft did attempt to give you a hook into some of these events in the SystemEvents class but unfortunately they do not tie into all of them. Looking at the Power Management API there isn't an event that tracks the battery in the way that you desire.
Power Events:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa373162(v=vs.85).aspx
Power Management Services has a method called GetSystemPowerStatus that will get you the information you need. If you have an understanding of working with C++ from within .Net you could query the battery information and when it changes fire your own event.
GetSystemPowerStatus:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa372693(v=vs.85).aspx
This is the code im calling the method in my Form1 constructor:
private void cpuFanSpeed()
{
SelectQuery query =
new SelectQuery("Win32_Fan");
// Instantiate an object searcher
// with this query
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(query);
// Call Get() to retrieve the collection
// of objects and loop through it
foreach (ManagementObject envVar in searcher.Get())
MessageBox.Show(envVar["DesiredSpeed"].ToString());
}
But it's never get to the MessageBox.
What is wrong here ? I tried to read and doing it by the document here: http://msdn.microsoft.com/en-us/library/aa394146(v=vs.85).aspx
And here: http://msdn.microsoft.com/en-us/library/ms257359.aspx
But it's not working.
I want to display my cpu fan speed every second on a label.
This is a screenshot of OpenHardwareMonitor display my cpu fan speed:
And this is the code the function im using in my application to get the CPU temperature:
In class:
public static float? cpuView(bool pause , CpuTemperature cpuTemp , Form1 f1 , List<string> myData , float? myCpuTemp , Button b1)
{
if (pause == true)
{
}
else
{
Computer myComputer = new Computer();
myComputer = new Computer(cpuTemp)
{
CPUEnabled =
true
};
myComputer.Open();
Trace.WriteLine("");
foreach (var hardwareItem in myComputer.Hardware)
{
if (hardwareItem.HardwareType == HardwareType.CPU)
{
hardwareItem.Update();
foreach (IHardware subHardware in hardwareItem.SubHardware)
subHardware.Update();
foreach (var sensor in hardwareItem.Sensors)
{
cpuTemp.SetValue("sensor", sensor.Value.ToString());
if (sensor.SensorType == SensorType.Temperature)
{
sensor.Hardware.Update();
cpuTemp.GetValue("sensor", sensor.Value.ToString());
f1.Invoke(new Action(() => myData.Add("Cpu Temeprature --- " + sensor.Value.ToString())));
myCpuTemp = sensor.Value;
if (sensor.Value > 60)
{
Logger.Write("The Current CPU Temperature Is ===> " + sensor.Value);
b1.Enabled = true;
}
break;
}
}
}
}
}
return myCpuTemp;
}
Not every machine provides this information through WMI. If your computer doesn't, you won't be able to access it. Just because WMI provides a property to access a particular piece of information doesn't mean that information will always be available.
Presumably, the collection you're iterating through in the foreach loop is empty, which is why no MessageBox ever gets displayed.
The only possible fix for this problem would be to obtain an updated driver from your motherboard manufacturer that provides WMI with this information (assuming, of course, that your hardware even includes the sensors required to measure this type of thing in the first place).
Edit: Open Hardware Monitor has apparently written its own drivers to interact directly with your hardware, querying its sensors. This suspicion is confirmed by perusing their web page, which documents specific pieces of hardware that it supports.
It's not using WMI to obtain its information, so this doesn't prove that you'll be able to obtain the information from WMI yourself.
However, the bottom of the above-linked page does contain this interesting remark:
The Open Hardware Monitor publishes all sensor data to WMI (Windows Management Instrumentation). This allows other applications to read and use the sensor information as well. A preliminary documentation of the interface can be found here.
So it appears that you can piggyback on top of Open Hardware Monitor, using its drivers to retrieve information, and then retrieve that information from it inside of your app. That's probably the best solution, since I doubt your hardware manufacturer is going to come through with an updated driver that provides the fan speed to WMI.
I'm developing a small remote task manager application [server/client] on LAN using WCF service lib.
I need to know which way is faster to get processors information:
getting processes info from System.Diagnostics?
getting processes info from WMI?
I'm using the first options now, but if the application is x86, and the process is x64 then I can't access to Process.MainModule, so it forces me to create two versions of my application to get it work on any PC, x86 version and x64.
So if I used WMI would I face the same issue?
public void GetProcesses()
{
foreach (Process p in Process.GetProcesses())
{
try
{
InfoProcess process = new InfoProcess(p.Id, p.MainModule.ModuleName, p.MainModule.FileVersionInfo.FileDescription, p.WorkingSet / 1024);
PrintProcess(process);
}
catch
{ }
}
}
public class InfoProcess
{
public int Id;
public string Name;
public string Description;
public int WorkingSet;
public InfoProcess(int Id, string Name, string Desc, int WorkingSet)
{
this.Id = Id;
this.Name = Name;
this.Description = Desc;
this.WorkingSet = WorkingSet;
}
}
If WMI is better, I need a little help with properties names that gives me:
Process.WorkingSet
Process.MainModule.FileVersionInfo.FileDescription
I would expect WMI to be slower. There are some tricks that you can use to speed up WMI, but in general, performance is often poor.
In your situation I would simply build your app targeting AnyCPU. Then you have a single app that runs as x86 under a 32 bit OS and as x64 under a 64 bit OS. That way you can avoid WMI altogether.
I need to gather some system information for the application I'm developing. The memory available and the CPU load are easy to get using C#. Unfortunately, the CPU temperature it's not that easy. I have tried using WMI, but I couldn't get anything using
Win32_TemperatureProbe
or
MSAcpi_ThermalZoneTemperature
How can I do this? I'm wondering how monitoring programs, as SiSoftware Sandra, can get that information...
Here is the code of the class:
public class SystemInformation
{
private System.Diagnostics.PerformanceCounter m_memoryCounter;
private System.Diagnostics.PerformanceCounter m_CPUCounter;
public SystemInformation()
{
m_memoryCounter = new System.Diagnostics.PerformanceCounter();
m_memoryCounter.CategoryName = "Memory";
m_memoryCounter.CounterName = "Available MBytes";
m_CPUCounter = new System.Diagnostics.PerformanceCounter();
m_CPUCounter.CategoryName = "Processor";
m_CPUCounter.CounterName = "% Processor Time";
m_CPUCounter.InstanceName = "_Total";
}
public float GetAvailableMemory()
{
return m_memoryCounter.NextValue();
}
public float GetCPULoad()
{
return m_CPUCounter.NextValue();
}
public float GetCPUTemperature()
{
//...
return 0;
}
}
For others who may come by here, maybe take a look at : http://openhardwaremonitor.org/
Follow that link and at first you might think, "Hey, that's an application, and that is why it was removed. The question was how to do this from C# code, not to find an application that can tell me the temperature..." This is where it shows you are not willing to invest enough time in reading what "Open Hardware Monitor" also is.
They also include a data interface. Here is the description:
Data Interface
The Open Hardware Monitor publishes all sensor data to
WMI (Windows Management Instrumentation). This allows other
applications to read and use the sensor information as well. A
preliminary documentation of the interface can be found here (click).
When you download it, it contains the OpenHardwareMonitor.exe application, and you're not looking for that one. It also contains the OpenHardwareMonitorLib.dll, and you're looking for that one.
It is mostly, if not 100%, just a wrapper around the WinRing0 API, which you could choose to wrap yourself if you feel like it.
I have tried this out from a C# application myself, and it works. Although it was still in beta, it seemed rather stable. It is also open source, so it could be a good starting point instead.
You can indeed read the CPU temperature very easily in C# by using a WMI approach.
To get the temperature in Celsius, I have created a wrapper that converts the value returned by WMI and wraps it into an easy-to-use object.
Please remember to add a reference to the System.Management.dll in Visual Studio.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
namespace RCoding.Common.Diagnostics.SystemInfo
{
public class Temperature
{
public double CurrentValue { get; set; }
public string InstanceName { get; set; }
public static List<Temperature> Temperatures
{
get
{
List<Temperature> result = new List<Temperature>();
ManagementObjectSearcher searcher = new ManagementObjectSearcher(#"root\WMI", "SELECT * FROM MSAcpi_ThermalZoneTemperature");
foreach (ManagementObject obj in searcher.Get())
{
Double temperature = Convert.ToDouble(obj["CurrentTemperature"].ToString());
temperature = (temperature - 2732) / 10.0;
result.Add(new Temperature { CurrentValue = temperature, InstanceName = obj["InstanceName"].ToString() });
}
return result;
}
}
}
}
I'm pretty sure it's manufacturer dependent, since they will be accessed through an I/O port. If you have a specific board you're trying to work with, try looking through the manuals and/or contacting the manufacturer.
If you want to do this for a lot of different boards, I'd recommend contacting someone at something like SiSoftware or be prepared to read a lot of motherboard manuals.
As another note, not all boards have temperature monitors.
You also might run into problems getting privileged access from the kernel.
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 file from the official source, extract and add a reference to file OpenHardwareMonitorLib.dll in your project.
I extracted the CPU part from Open Hardware Monitor into a separate library, exposing sensors and members normally hidden into OHM.
It also includes many updates (like the support for Ryzen and Xeon) because on Open Hardware Monitor (OHM) they haven't accepted pull requests since 2015.
https://www.nuget.org/packages/HardwareProviders.CPU.Standard/
It's depends on if your computer supports WMI. My computer can't run this WMI demo either.
But I successfully get the CPU temperature via Open Hardware Monitor. Add the Openhardwaremonitor reference in Visual Studio. It's easier. Try this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenHardwareMonitor.Hardware;
namespace Get_CPU_Temp5
{
class Program
{
public class UpdateVisitor : IVisitor
{
public void VisitComputer(IComputer computer)
{
computer.Traverse(this);
}
public void VisitHardware(IHardware hardware)
{
hardware.Update();
foreach (IHardware subHardware in hardware.SubHardware) subHardware.Accept(this);
}
public void VisitSensor(ISensor sensor) { }
public void VisitParameter(IParameter parameter) { }
}
static void GetSystemInfo()
{
UpdateVisitor updateVisitor = new UpdateVisitor();
Computer computer = new Computer();
computer.Open();
computer.CPUEnabled = true;
computer.Accept(updateVisitor);
for (int i = 0; i < computer.Hardware.Length; i++)
{
if (computer.Hardware[i].HardwareType == HardwareType.CPU)
{
for (int j = 0; j < computer.Hardware[i].Sensors.Length; j++)
{
if (computer.Hardware[i].Sensors[j].SensorType == SensorType.Temperature)
Console.WriteLine(computer.Hardware[i].Sensors[j].Name + ":" + computer.Hardware[i].Sensors[j].Value.ToString() + "\r");
}
}
}
computer.Close();
}
static void Main(string[] args)
{
while (true)
{
GetSystemInfo();
}
}
}
}
You need to run this demo as an administrator.
You can see the tutorial in Using Open Hardware Monitor to get CPU temperature in C# and make a fan cooling system.
The mentioned WMI classes were not working for me in the latest version of Windows 10.
On my Dell laptop I could get the CPU temperature in Celsius like this via PowerShell:
$data = Get-WMIObject -Query "SELECT * FROM Win32_PerfFormattedData_Counters_ThermalZoneInformation" -Namespace "root/CIMV2"
#($data)[0].HighPrecisionTemperature
It can be done in your code via WMI. I've found a tool (WMI Code Creator v1.0) from Microsoft that creates code for it.
The WMI Code Creator tool allows you to generate VBScript, C#, and VB
.NET code that uses WMI to complete a management task such as querying
for management data, executing a method from a WMI class, or receiving
event notifications using WMI.