【问题标题】:Get CPU Temperature获取 CPU 温度
【发布时间】:2014-06-12 10:52:06
【问题描述】:

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

【问题讨论】:

  • 您是否将您的温度与任何监控软件(superuser.com/a/395437/15484)进行了比较?开尔文-摄氏度转换呢? (PS:您可以重用 RealTemp 或其他项目的驱动程序)
  • 我正在进行转换(temp / 10 - 273.15),但结果始终为 70.05,Core Temp 显示不同的温度。
  • 你看过openhardwaremonitor.org吗?
  • @Housy 不是重复的,因为这个问题肯定是关于通过 Windows API 进行的,而您链接的问题是关于通过托管代码进行的。

标签: c++ windows winapi cpu temperature


【解决方案1】:

说实话,这取决于硬件。

适用于大多数硬件的库是 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 代码已确认成功获取 Intel Haswell CPU 在 Celcius 中的温度。它很可能适用于 AMD 和 Intel 的大多数其他 CPU。需要 OpenHardwareMonitorLib.dll。你可以从source编译它

您可以使用此库获得有关系统的许多其他信息。

请注意,用户的 CPU 可以有多个温度传感器。例如,每个内核都有一个温度传感器,所以不要像我在上面的例子中那样总是选择最后一个。

祝你好运。

【讨论】:

    【解决方案2】:

    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 将在某个地方提供相应的文档来定义这一点。

    在这两种情况下,根据定义,这些都是硬件如何公开有关其温度传感器的信息。您可以使用这样的库,它会在后台执行此操作,或者您可以编写自己的等效代码。

    【讨论】:

    • 请注意,rdmsr 需要内核驱动程序,这不能从用户模式代码中完成。
    【解决方案3】:

    在最新的 Windows 10 中,上述 WMI 类不适用于我。 在我的戴尔笔记本电脑上,我可以在此处获取以摄氏度为单位的 CPU 温度:

    ROOT_CIMV2\Win32_PerfFormattedData_Counters_ThermalZoneInformation\HighPrecisionTemperature
    

    【讨论】:

      【解决方案4】:

      WMI 有 Win32_TemperatureProbe 类:

      http://msdn.microsoft.com/en-us/library/aa394493%28VS.85%29.aspx

      用它代替 MSAcpi_ThermalZoneTemperature

      更新。

      所以,我尝试了 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");
      

      然后将属性名称更改为“CurrentReading”

      但不幸的是,用于检索此参数的代码可能未在主板驱动程序或 MS 驱动程序中实现。在这种情况下,VARIANT 类型的结果将被设置为 NULL。

      【讨论】:

      • 从这些文档中,无法从 SMBIOS 表中提取 CurrentReading 属性的实时读数。出于这个原因,WMI 的当前实现不填充 CurrentReading 属性。 由于 op 正在寻找当前的 CPU 温度,我相信这个 WMI 类需要一个有效的CurrentReading 属性来完成这项工作。
      • 这对你有用吗?它对我不起作用,正如computerfreaker 所说,根据文档CurrentReading 没有填充。
      • 是的,它有效。反正CIM_TemperatureSensor类也实现了,试试吧。
      • 我在调用 IEnumWbemClassObject::Next() 时收到 0x80041010 错误。有没有人让他的任何建议奏效?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-02
      • 1970-01-01
      • 2020-10-18
      • 1970-01-01
      相关资源
      最近更新 更多