我想得到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;
}
原文由 Johnny Mnemonic 发布,翻译遵循 CC BY-SA 4.0 许可协议
我必须说这个话题是一场彻头彻尾的噩梦。在我得到一个可行的解决方案之前,我花了几个星期和几个头痛的研究和尝试不同的东西。这是我发现的:
从一块硬件获取传感器值需要通过内存映射 的特定于模型的寄存器(MSR) 直接访问该硬件,这不仅在不同的 CPU 中有所不同,而且只能在内核(驱动程序)中完成,而不能在用户中完成-空间应用。这在 Windows 上尤其困难,您需要驱动程序获得 Microsoft 的批准和签名。
Linux 有这样的驱动程序,并通过虚拟文件提供它们的输出,例如
/sys/class/thermal/thermal_zone2/temp
或更复杂的命令行工具,如 lm-sensors 。然而,Windows 在这方面是一个狂野的西部,没有通用且可靠的方法来做到这一点。以下是我尝试过的解决方案:
到处张贴的 WMI 方法不适用于 90% 的硬件,因为它需要制造商的额外工作,而制造商通常不会这样做。
一些硬件供应商提供了自己的 SDK 用于读取 CPU 指标,例如 AMD Ryzen Master Monitoring SDK ,但它们仅适用于特定的 CPU 类型,并且经常过时且未维护。
一些公司提供商业多硬件 SDK,比如 这个,但他们是付费的,他们甚至没有回复我的任何电子邮件,所以这里也很不走运。
有一个用于监控硬件传感器的开源项目,称为 Open Hardware Monitor ,它有几个分支——目前最活跃的(2022 年)是 Libre Hardware Monitor 。它使用 WinRing0 驱动程序通过其 MSR 访问硬件并提取传感器值。
它不是作为库设计的,而是作为图形应用程序设计的。然而,它的安装附带了一个导出重要功能的 DLL。
唯一的问题是它是用 C# 编写的,因此它需要跨语言绑定才能从 C++ 中使用。 OpenRGB 社区 的一个人做了这样的绑定,它可以 在这里找到。构建该版本并不难,但可以在 此处 找到预构建的二进制文件。
所以最后,使用 lhwm-wrapper ,它包装了 LibreHardwareMonitor 的 DLL,它使用 WinRing0 来读取传感器,我可以编写一个用户空间应用程序来读取我的 CPU 的温度,万岁!
但是请注意,安装在您计算机中的其他应用程序也可能在后台读取传感器值,并且过于频繁地读取它会增加您的 CPU 负载并且某些硬件可能不喜欢它。
这就是为什么后来我决定将我的应用程序拆分为 1. 一个 Windows 服务,它每几秒只读取一次传感器并通过套接字发布结果,以及 2. 应用程序的其余部分根据温度。