我想获得CPU温度。 以下是我使用C ++和WMI所做的事情。我正在读MSAcpi_ThermalZoneTemperature,但它始终是相同的,根本不是CPU温度。
有没有办法在不必编写驱动程序的情况下获得CPU的实际温度?或者我可以使用任何库吗?提前谢谢。
#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <comdef.h>
#include <Wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
HRESULT GetCpuTemperature(LPLONG pTemperature)
{
if (pTemperature == NULL)
return E_INVALIDARG;
*pTemperature = -1;
HRESULT ci = CoInitialize(NULL);
HRESULT hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
if (SUCCEEDED(hr))
{
IWbemLocator *pLocator;
hr = CoCreateInstance(CLSID_WbemAdministrativeLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*)&pLocator);
if (SUCCEEDED(hr))
{
IWbemServices *pServices;
BSTR ns = SysAllocString(L"root\\WMI");
hr = pLocator->ConnectServer(ns, NULL, NULL, NULL, 0, NULL, NULL, &pServices);
pLocator->Release();
SysFreeString(ns);
if (SUCCEEDED(hr))
{
BSTR query = SysAllocString(L"SELECT * FROM MSAcpi_ThermalZoneTemperature");
BSTR wql = SysAllocString(L"WQL");
IEnumWbemClassObject *pEnum;
hr = pServices->ExecQuery(wql, query, WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pEnum);
SysFreeString(wql);
SysFreeString(query);
pServices->Release();
if (SUCCEEDED(hr))
{
IWbemClassObject *pObject;
ULONG returned;
hr = pEnum->Next(WBEM_INFINITE, 1, &pObject, &returned);
pEnum->Release();
if (SUCCEEDED(hr))
{
BSTR temp = SysAllocString(L"CurrentTemperature");
VARIANT v;
VariantInit(&v);
hr = pObject->Get(temp, 0, &v, NULL, NULL);
pObject->Release();
SysFreeString(temp);
if (SUCCEEDED(hr))
{
*pTemperature = V_I4(&v);
}
VariantClear(&v);
}
}
}
if (ci == S_OK)
{
CoUninitialize();
}
}
}
return hr;
}
int main(int argc, char **argv)
{
LONG temp;
GetCpuTemperature(&temp);
printf("temp=%lf\n", ((double)temp / 10 - 273.15));
getc(stdin);
return 0;
}
答案 0 :(得分:2)
说实话,这取决于硬件。
不幸的是,适用于大多数硬件的库是OpenHardwareMonitorLib, 它没有文档,实际上并没有作为一个独立的软件而存在。它是名为“ Open Hardware Monitor”的开源软件的一部分。它是在.NET C Sharp中完成的,当然,仅适用于Windows。幸运的是,您可以将它作为DLL获得,并且GUI与实际的后端(OpenHardwareMonitorLib)完全分离。
阅读这篇文章,了解如何从C ++使用它
How to call a C# library from Native C++ (using C++\CLI and IJW)
因此,考虑到它没有文档,使用它可能会有点困难。在阅读了一段时间后,这是我的看法:
using OpenHardwareMonitor.Hardware;
...
float? cpu_temperature_celcius = null;
Computer computer= new Computer();
computer.CPUEnabled = true;
computer.Open();
foreach (IHardware hardware in computer.Hardware)
if (hardware.HardwareType == HardwareType.CPU)
foreach (ISensor sensor in hardware.Sensors)
if (sensor.SensorType == SensorType.Temperature)
cpu_temperature_celcius = sensor.Value;
已验证此#C代码可获取Celcius中Intel Haswell CPU的温度,并且很可能适用于AMD和Intel的其他大多数CPU。需要OpenHardwareMonitorLib.dll。您可以从source
进行编译通过此库,您可以获得有关系统的许多其他信息。
请注意,用户的CPU可以具有多个温度传感器。例如,每个核心都有一个温度传感器,因此不要像我在上面的示例中那样总是获取最后一个。
祝你好运。
答案 1 :(得分:1)
Tomer's answer中提供的指向OpenHardwareMonitorLib的源的链接说明了从较低类型的CPU读取此信息必须进行的底层操作。例如,IntelCPU类定义了一些特定于模型的寄存器:
private const uint IA32_THERM_STATUS_MSR = 0x019C; private const uint IA32_TEMPERATURE_TARGET = 0x01A2; private const uint IA32_PERF_STATUS = 0x0198; private const uint MSR_PLATFORM_INFO = 0xCE; private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1; private const uint MSR_RAPL_POWER_UNIT = 0x606; private const uint MSR_PKG_ENERY_STATUS = 0x611; private const uint MSR_DRAM_ENERGY_STATUS = 0x619; private const uint MSR_PP0_ENERY_STATUS = 0x639; private const uint MSR_PP1_ENERY_STATUS = 0x641;
这些直接来自英特尔的文档,例如CPU Monitoring with DTS/PECI(第16节“直接MSR访问”)。它们也可能记录在《英特尔软件开发人员手册》中,但我没有检查。
OpenHardwareMonitorLib使用Rdmsr和RdmsrTx从感兴趣的MSR中获取温度值。
corresponding AMD code似乎从PCI寄存器中获取了类似的信息。 AMD将在某个地方定义等效的文档。
在两种情况下,按照定义,这就是硬件如何公开有关其温度传感器的信息。您可以使用像这样的库,它将在后台进行,也可以编写自己的等效代码。
答案 2 :(得分:0)
提到的 WMI 类在最新的 Windows 10 中对我不起作用。 在我的戴尔笔记本电脑上,我可以在这里获得以摄氏度为单位的 CPU 温度:
ROOT_CIMV2\Win32_PerfFormattedData_Counters_ThermalZoneInformation\HighPrecisionTemperature
答案 3 :(得分:-1)
WMI具有Win32_TemperatureProbe类:
http://msdn.microsoft.com/en-us/library/aa394493%28VS.85%29.aspx
尝试使用它代替MSAcpi_ThermalZoneTemperature
<强> UPD。强>
所以,我尝试了MS示例页面here中的代码。它显示了从WMI类检索信息的方法。
它通常与您的相同,但是类名和属性名称。所以改变行
BSTR query = SysAllocString(L"SELECT * FROM MSAcpi_ThermalZoneTemperature");
到
BSTR query = SysAllocString(L"SELECT * FROM Win32_TemperatureProbe");
或其父类
BSTR query = SysAllocString(L"SELECT * FROM CIM_TemperatureSensor");
然后将属性名称更改为&#34; CurrentReading&#34;
但不幸的是,检索此参数的代码可能未在主板驱动程序或MS驱动程序中实现。在这种情况下,VARIANT类型的结果将设置为NULL。