获取CPU温度

时间:2014-04-26 18:24:57

标签: c++ windows winapi cpu temperature

我想获得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;
}

4 个答案:

答案 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。