Получите температуру процессора

Я хочу получить температуру процессора. Ниже приводится то, что я сделал с использованием С++ и WMI. Я читаю MSAcpi_ThermalZoneTemperature, но он всегда тот же, и это не температура процессора вообще.

Есть ли способ получить реальную температуру процессора без необходимости писать драйверы? Или есть ли какие-нибудь библиотеки, которые я могу использовать? Заранее благодарю вас.

#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;
}

Ответ 1

По правде говоря, это зависит от оборудования.

Библиотека, которая работает на большинстве аппаратных средств, - OpenHardwareMonitorLib, к сожалению, она не имеет документации и фактически не существует как самостоятельная часть программного обеспечения. это часть программного обеспечения с открытым исходным кодом под названием "Open Hardware Monitor". К счастью, вы можете получить DLL, и графический интерфейс полностью отделен от фактического бэкэнда, который является OpenHardwareMonitorLib. К сожалению, это сделано в .NET C Sharp и, конечно, работает только для Windows. Прочтите этот пост о том, как использовать его из C++

Как вызвать библиотеку С# из Native C++ (используя C++\CLI и 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 в градусах Цельсия и, скорее всего, будет работать для большинства других процессоров AMD и Intel. Необходим OpenHardwareMonitorLib.dll. Вы можете скомпилировать его из источника

С помощью этой библиотеки вы можете получить много другой информации о системе.

Обратите внимание, что процессор пользователя может иметь несколько датчиков температуры. Например, датчик температуры для каждого ядра, поэтому не всегда берите последний, как я сделал в примере выше.

Удачи.

Ответ 2

Ссылка на источник для OpenHardwareMonitorLib, приведенная в Tomer answer, иллюстрирует, что должно происходить на низком уровне для считывания этой информации из разных типов процессоров. Например, класс 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;

Это прямые документы Intel, такие как Мониторинг процессора с помощью DTS/PECI (раздел 16 "Прямой доступ к MSR"). Они также могут быть задокументированы в Руководстве разработчика программного обеспечения Intel, но я не проверял.

OpenHardwareMonitorLib использует Rdmsr и RdmsrTx для получения значений температуры из интересующих MSR.

Соответствующий код AMD corresponding AMD code выглядит так, как будто он получает аналогичную информацию из регистра PCI. У AMD будет где-то эквивалентная документация, которая определит это.

В обоих случаях, по определению, аппаратное обеспечение предоставляет информацию о своих датчиках температуры. Вы можете использовать подобную библиотеку, и она будет делать это под капотом, или вы можете написать собственный эквивалентный код.

Ответ 3

WMI имеет класс Win32_TemperatureProbe:

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

Попробуйте вместо MSAcpi_ThermalZoneTemperature

обн.

Итак, я попробовал код из примера примера MS здесь. Он показывает способ получения информации из классов 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.