Получите температуру процессора
Я хочу получить температуру процессора.
Ниже приводится то, что я сделал с использованием С++ и 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.