行业资讯
📅 2026/9/1 2:53:17
易语言调用NVAPI读取NVIDIA显卡温度:DLL封装实战
简介面向易语言开发者的N卡温度读取源码包专注于通过NVAPI接口获取NVIDIA显卡实时温度适用于系统监控、游戏优化与硬件检测等场景。资源共5个文件压缩包仅132KB包含32位与64位NVAPI导入库、硬件交互DLL、易语言程序源码文件及nvapi头文件可直接调用或二次修改。已有197人学习下载。源码演示了初始化NVAPI、枚举GPU、读取温度及错误处理等关键流程并配套底层硬件访问支持能帮开发者绕开繁琐的API声明快速集成显卡温度监测功能。适合具备一定易语言基础、希望开发硬件状态工具或学习NVAPI调用方法的开发者参考。 前阵子帮朋友验收一批二手显卡每张卡都要测待机温度和满载温度。插到机器上、开软件、看数字、拔卡一套流程下来十几分钟几十张卡直接把我测到怀疑人生。当时我就想要一个轻量小工具启动后直接显示当前NVIDIA显卡温度最好还能顺带看风扇转速。翻了一圈现成软件要么太臃肿要么全是英文界面干脆自己拿易语言写了一个顺便还把读取N卡温度的核心源码整理了出来。这篇东西就把整个实现过程讲透从为什么用易语言、底层走什么接口到DLL怎么封装、易语言侧怎么调用再到我实际踩过的坑。无论你是纯易语言玩家还是只会一点C/C想快速做个硬件监测小工具照着抄都能跑起来。1. 需求拆解这个小工具到底要做什么1.1 我为什么会写这个工具先说场景。显卡散热测试这活儿听起来简单做起来琐碎。你需要长时间盯着温度曲线看它是否稳定、有没有突然飙升。人工盯屏幕上几十个数据眼睛迟早要瞎。更麻烦的是测试环境用的是32位老系统Win7很多新出的监控软件装上就报错有些还强制联网。我需要的功能其实特别朴素一个极简窗口能显示当前N卡核心温度有刷新频率控制不带任何花哨的图表。这时候易语言反而成了最顺手的选择——语法直接编译出来是独立的exe体积小、免安装、绿色运行。我用它写桌面小工具不是一回两回了像这种单窗口、一个定时器、一个标签的活儿半小时到一小时就能出成品。另外我特意做成源码形式是因为这种工具每家需求都不一样。有人想显示在系统托盘里有人想叠加到游戏画面上有人还想在温度过高时自动拉满风扇。给出源码大家按需改比自己从零研究底层接口省事太多。1.2 四条技术路线先对比再动手读显卡温度业内有几种常见做法我把它们拉出来逐个对比了一下方案实现难度精度实时性依赖条件备注NVAPINVIDIA官方SDK中高能读到多传感器好需要封装DLL官方推荐信息最全WMI查询MSAcpi_ThermalZoneTemperature低低多数拿不到显卡温度一般无需额外SDK实测兼容性较差不推荐调用nvidia-smi命令行低中差需要轮询进程需要新版驱动只是权宜之计直接读驱动IOCTL/总线数据高高好涉及底层协议开发成本过高不现实先说WMI。这个方案我最早试过root\WMI命名空间下有一个MSAcpi_ThermalZoneTemperature类能读出温度但读到的多半是CPU或主板温度跟显卡没什么关系而且不同主板的ACPI实现差异很大这台机器能读到下一台就返回空值。它的优点只有一个——不用写DLL但缺点太致命撑不起“取N卡温度”这个需求。再说nvidia-smi。NVIDIA显卡驱动自带的这个命令行工具确实能输出核心温度但问题是它跟驱动强绑定驱动版本太老就没有而且每刷新一次就要启动一次进程解析文本输出100毫秒的实时监视根本谈不上。偶尔手动跑一下没问题做成持续运行的监控程序体验很差。最底层的IOCTL方案理论上能直接和驱动通信拿到所有传感器数据但需要逆向驱动协议普通开发者搞这个纯属给自己挖坑。直接排除。1.3 为什么最终选了NVAPI这条路对比下来NVAPI基本是唯一兼顾“官方可靠”和“拿到真实传感器数据”的路径。它是NVIDIA提供的C语言SDK动态链接库nvapi64.dll64位系统或nvapi.dll32位系统在你的Windows系统里本来就有——只要装了显卡驱动就带着它。我们不需要额外安装运行时只需要调用它的导出函数。NVAPI能读到的信息非常丰富核心温度、显存温度、风扇转速、功耗、核心频率、显存频率、电压一应俱全。对于温度读取它还能区分多个传感器GPU核心、显存、VRM供电模块、热管末端等。这比任何第三方工具都精确。代价只有一个——它是C接口易语言不能直接调用。解决方案也很简单用C写一个薄封装DLL把复杂的NVAPI结构体、内存分配问题都收进DLL内部对外只暴露几个整数型接口给易语言。这正好也是我擅长的配合方式C负责底层数据易语言负责界面和逻辑。2. NVAPI调用原理与DLL封装实战2.1 读懂NVAPI的三步调用流程NVAPI的调用套路非常固定核心就三步初始化、枚举物理显卡、查询热传感器数据。搞懂这三步后面写代码就是套模板。第一步NvAPI_Initialize()。这个函数必须在所有其他NVAPI调用之前执行作用是加载驱动通信通道。如果返回NVAPI_OK说明初始化成功返回其他值就说明驱动有问题比如显卡驱动未装好或者当前进程没有权限。第二步NvAPI_EnumPhysicalGPUs()。这个函数会返回系统里所有NVIDIA物理GPU的句柄数组。注意它不区分“逻辑显卡”和“物理GPU”SLI多卡或者笔记本双显卡都能正确枚举。返回的句柄是后续所有查询操作的前置参数。第三步NvAPI_GPU_GetThermalSettings()。这个函数传入物理GPU句柄和传感器选择标志返回一个填充了温度数据的结构体。结构体里有一个传感器数组每个元素都包含传感器类型、当前温度、最高温度、最低温度等信息。这里有一个非常关键的细节NVAPI返回的温度单位是毫摄氏度m°C不是摄氏度。也就是说数值50000代表50°C。我第一次用的时候没注意单位直接把50000显示成50000°C差点以为显卡要炸了。必须除以1000再显示这是所有新手必踩的坑。2.2 直接抄作业封装温度读取DLL的完整代码我的方案是用Visual Studio2019或2022都行创建一个Dynamic-Link Library (DLL)工程然后在dllmain.cpp里写导出函数。这里我贴一个可以直接编译的版本#include windows.h #include nvapi.h #pragma comment(lib, nvapi.lib) // 导出返回系统中NVIDIA显卡数量 extern C __declspec(dllexport) int __stdcall GetGpuCount() { NvPhysicalGpuHandle handles[64] { 0 }; NvU32 count 0; NvAPI_Status status NvAPI_EnumPhysicalGPUs(handles, count); if (status ! NVAPI_OK) return 0; return (int)count; } // 导出获取指定索引显卡的平均温度单位统一转换为摄氏度 extern C __declspec(dllexport) int __stdcall GetGpuTemp(int index) { NvPhysicalGpuHandle handles[64] { 0 }; NvU32 count 0; if (NvAPI_EnumPhysicalGPUs(handles, count) ! NVAPI_OK) return -1; if (index 0 || index (int)count) return -1; NV_GPU_THERMAL_SETTINGS thermal { 0 }; thermal.version NV_GPU_THERMAL_SETTINGS_VER; NvAPI_Status status NvAPI_GPU_GetThermalSettings( handles[index], NVAPI_THERMAL_TARGET_ALL, thermal); if (status ! NVAPI_OK) return -1; // 遍历所有有效传感器取平均温度 int total 0; int validCount 0; for (int i 0; i NVAPI_MAX_THERMAL_SENSORS_PER_GPU; i) { if (thermal.sensor[i].controller ! NVAPI_THERMAL_CONTROLLER_NONE) { total thermal.sensor[i].currentTemp; // 毫摄氏度 validCount; } } if (validCount 0) return -1; return (total / validCount) / 1000; // 转成摄氏度 } // 导出获取指定索引显卡的名称写入调用方提供的缓冲区 extern C __declspec(dllexport) void __stdcall GetGpuName(int index, char* buffer, int bufferSize) { NvPhysicalGpuHandle handles[64] { 0 }; NvU32 count 0; if (NvAPI_EnumPhysicalGPUs(handles, count) ! NVAPI_OK) { buffer[0] \0; return; } NvAPI_ShortString name { 0 }; if (NvAPI_GPU_GetFullName(handles[index], name) ! NVAPI_OK) { buffer[0] \0; return; } lstrcpynA(buffer, name, bufferSize); }几个重要的工程配置点头文件和lib文件需要先到NVIDIA官网下载NVAPI SDK解压后把inc和lib\x64等目录配置到VS工程里。SDK是免费的不用注册不用申请直接下就行。导出函数全部用__stdcall调用约定。易语言默认的DLL调用约定就是stdcall两边必须一致否则栈平衡崩掉程序可能直接闪退。字符串返回不用char*返回值的形式而是让调用方传入缓冲区。这是易语言DLL调用的老传统了直接返回char*指针易语言里要么收不到要么乱码传缓冲区反而干净利落。2.3 编译三步走版本、位数、路径一个都不能错这里必须说一句带血泪的提醒易语言编译出来的程序默认是32位进程所以DLL必须编译成x86Win32版本不是x64版本。我在第一次做这类工程时顺手编译了个x64的DLL结果易语言怎么调用都失败一度以为代码写错了排查了半天才发现是位数不匹配。具体操作打开VS菜单栏的配置管理器把活动解决方案平台改成x86或者直接在项目属性 → 链接器 → 高级里设置目标计算机为MachineX86。然后编译生成的DLL体积大概几十KB非常小。编译完成后把nvtemp.dll名字你自己定放到易语言程序的EXE同目录下。易语言程序会先找程序目录再找系统目录所以放在旁边最稳。另外一个容易被忽略的细节NVAPI SDK的lib文件分lib\x86和lib\x64如果链接时报unresolved external symbol多半是lib路径配错了。VS的链接器里32位目标就用x86版的lib64位目标就用x64版的lib千万别搞混。3. 易语言界面调用从DLL声明到温度上屏3.1 DLL命令声明怎么写才不报错DLL编译好了接下来是易语言侧。先创建新窗口程序然后按下CtrlF2或菜单里插入→DLL命令声明我们刚写的三个接口.版本 2 .DLL命令 GetGpuCount, 整数型, nvtemp.dll, GetGpuCount .参数 无 .DLL命令 GetGpuTemp, 整数型, nvtemp.dll, GetGpuTemp .参数 index, 整数型 .DLL命令 GetGpuName, 整数型, nvtemp.dll, GetGpuName .参数 index, 整数型 .参数 buffer, 字节集 .参数 bufferSize, 整数型声明DLL命令要特别留意三点第一nvtemp.dll这个字符串写的是DLL文件名如果你把DLL放在了系统目录或者某个固定路径可以写完整路径不然建议就放程序目录只写文件名。第二GetGpuName的字符串参数用字节集类型接收。因为C侧写入的是ASCII字符数组易语言的字节集能直接容纳原始字节再通过到文本()转成文本显示。第三不要勾选“传址”。整数参数直接传值就行传址反而会把温度值的地址传进去DLL解引用时拿到的是完全错误的数据。3.2 定时刷新界面的两种思路界面这块我用三个组件一个标签显示显卡名称一个标签显示温度值一个时钟组件控制刷新频率。启动窗口时写初始化代码.版本 2 .程序集 窗口程序集_启动窗口 .子程序 __启动窗口_创建完毕 局部变量 显卡数量, 整数型 局部变量 名称缓冲区, 字节集 显卡数量 GetGpuCount () 如果 (显卡数量 0) 标签_信息.标题 “未检测到NVIDIA显卡” 返回 否则 标签_显卡名.标题 “检测到 ” 到文本 (显卡数量) “ 张NVIDIA显卡” 如果结束 初始化第一个显卡的名称缓冲 名称缓冲区 取空白字节集 (256) GetGpuName (0, 名称缓冲区, 256) 标签_显卡名.标题 指针到文本 (取变量数据地址 (名称缓冲区)) 上面这行只是示例实际用 到文本 处理字节集更直观 时钟_刷新.时钟周期 1000 每1000毫秒刷新一次刷新频率我实测下来1000毫秒就够用了。N卡传感器内部并不是每毫秒都在更新驱动层面的采样频率一般也就几百毫秒一次你设置100毫秒只会白白增加CPU占用。真要追求极致实时性500毫秒也是合理区间低于300毫秒意义不大。时钟周期事件里温度显示就这么简单.子程序 时钟_刷新_周期事件 局部变量 温度, 整数型 局部变量 分钟, 整数型 局部变量 秒数, 整数型 温度 GetGpuTemp (0) 0代表第一张显卡 如果 (温度 0) 标签_温度.标题 “读取失败” 返回 如果结束 标签_温度.标题 到文本 (温度) “ °C”3.3 温度分色显示顺带把风扇转速也加上只显示数字有点单调我给它加了一个颜色分档逻辑这样扫一眼就知道状态如果 (温度 50) 标签_温度.文本颜色 #绿色 否则 如果 (温度 70) 标签_温度.文本颜色 #黄色 否则 标签_温度.文本颜色 #红色 如果结束 如果结束这个阈值不是随便定的。考虑到GFP游戏、视频渲染等负载场景50°C以内算很凉快50到70属于正常负载区间超过70就要留意散热问题了。当然不同型号显卡的散热设计差异很大笔记本GPU和台式机GPU标准就不一样这只是我个人的默认值你可以按自己显卡的规格调整。顺带说一句如果还想显示风扇转速NVAPI结构体里其实就带着数据。在DLL里再加一个导出函数读取thermal.sensor[0].currentCoolingLevel或者用NvAPI_GPU_GetCoolerSettings获取转速百分比。做法和GetGpuTemp几乎是复制粘贴改两行就能实现。我把这个作为扩展功能留在源码里大家有兴趣可以自己加上。4. 排错实录我把踩过的坑整理成了速查表4.1 最常见的5个报错与排查方法现象可能原因解决方案易语言程序编译后提示“无法找到指定DLL”DLL不在程序目录或文件名不匹配确认nvtemp.dll在EXE同目录且DLL声明的文件名完全一致调用GetGpuTemp返回-1显卡驱动未初始化或NVAPI初始化失败确认驱动正常安装可在易语言启动时先调用一次检测温度一直显示0直接把毫摄氏度当成摄氏度用了检查DLL里的除以1000逻辑程序一运行就闪退DLL是64位的易语言是32位进程把DLL重新编译为x86版本多卡场景下温度读错索引对应错乱先调用GetGpuCount确认数量再逐个GetGpuName打印验证4.2 多显卡和笔记本双显卡场景怎么处理很多笔记本是“核显N卡独显”的双显卡配置。这时候NVAPI只能枚举到NVIDIA的独显这是正常的。如果你插了两张N卡做SLI或者挖矿主板插了多张卡GetGpuCount会正确返回数量GetGpuTemp的index参数就用来指定第几张卡。我的界面里做成下拉框或者直接加个“上一张/下一张”的切换按钮每次切换时更新底下的名称和温度。这在显卡翻新检测场景里太有用了批量看卡不用插拔一张张切着看就行。4.3 容易被忽略的两个细节关于驱动版本。我用NVAPI读取温度其实和你驱动版本没有直接关系因为NVAPI是向后兼容的——只要装的是NVIDIA官方驱动不管新旧nvapi64.dll都在系统里接口也是稳定的。但如果驱动过于古老10年前那种NVAPI可能没有实现温度查询接口调NvAPI_GPU_GetThermalSettings会返回NVAPI_NOT_SUPPORTED。遇到这种情况升级驱动基本都能解决。关于杀软误报。易语言在这方面的名声真的一言难尽很多杀软会直接把易语言编译出来的程序当成风险程序。这有一定历史原因因为很多灰产工具都用易语言写。但你这个工具是健康合规的绿色软件解决办法有三个一是给DLL签名二是把编译选项里的“压缩资源”关掉三是写清楚软件说明误报提交给杀软厂商白名单。我在分发这种内部小工具时一般会直接用压缩包发避免单文件触发一些敏感的行为检测。最后说两句做这类硬件信息读取的小工具真正的核心从来不是易语言本身而是底层接口的掌握。NVAPI几百个结构体摆在头文件里一开始看确实头皮发麻但实际用到的通常就两三个函数。搞定了初始化、枚举、查传感器这“三板斧”温度、风扇、功耗这些数据都能顺手读出来。我现在这个工具已经用了一年多中间还扩展过一次把风扇转速读取也加了进去偶尔还拿它给朋友远程看显卡状态。整个过程下来最大的感受是工具小归小但“易语言搭界面 C封装底层接口”这个组合在Windows平台做硬件工具真的又快又稳。如果你最终做出来并加了自己的功能不妨也分享一版让更多人少走点弯路。本文还有配套的精品资源点击获取