C++ - TrafficMonitor插件开发教程(以风扇转速显示插件为例)
作者:hangge | 2025-06-14 09:27
TrafficMonitor 是一款轻量级的系统监控软件,支持显示 CPU、内存、网络速度等信息(点击查看)。虽然 TrafficMonitor 提供了许多监控项目,但一直没有风扇转速的显示功能。本文以风扇转速显示插件为例,演示如何进行 TrafficMonitor 插件的开发。当然,如果需要直接使用该插件,可以查看我另一篇文章进行下载使用(点击访问)。
1,准备工作
(1)首先我们将 TrafficMonitor 官方的插件模板项目下载到本地:
(2)为了方便后续的开发和管理,我这里将里面自带的模板项目 PluginTemplate 修改成 Fan。关于修改项目名称的具体方法可以参考我之前写的文章:

2,添加 LibreHardwareMonitorLib.dll

(2)将下载下来的压缩包解压后,里面的 LibreHardwareMonitorLib.dll 就是我们后面需要用到的 dll 文件。

(3)然后我们将这个 dll 文件复制到 Fan 项目目录下。

(4)然后在 Fan 项目上右键点击选择“属性”,接着在弹出的属性页中将配置切换成“所有配置”,点击“高级”,将公共语言运行时支持改成“.NET Framework 运行时支持(/clr)”

(5)最后切换到“生成后事件”,在命令行一栏填写如下内容,然后应用。这个配置是为了让 LibreHardwareMonitorLib.dll 文件能自动复制到生成的 .exe 所在的文件夹里,避免手动复制。
Copy /Y "$(SolutionDir)fan\*.dll" "$(TargetDir)"
3,编写代码
(1)首先编辑 DataManager.h,在里面添加一个存储风扇转速的属性 m_fan_speed。
#pragma once
#include <string>
#include <map>
#include "resource.h"
#define g_data CDataManager::Instance()
struct SettingData
{
//TODO: 在此添加选项设置的数据
};
class CDataManager
{
private:
CDataManager();
~CDataManager();
public:
static CDataManager& Instance();
void LoadConfig(const std::wstring& config_dir);
void SaveConfig() const;
const CString& StringRes(UINT id); //根据资源id获取一个字符串资源
void DPIFromWindow(CWnd* pWnd);
int DPI(int pixel);
float DPIF(float pixel);
int RDPI(int pixel);
HICON GetIcon(UINT id);
SettingData m_setting_data;
float m_fan_speed; // 存储风扇转速
private:
static CDataManager m_instance;
std::wstring m_config_path;
std::map<UINT, CString> m_string_table;
std::map<UINT, HICON> m_icons;
int m_dpi{ 96 };
};
(2)接着编辑 PluginTemplate.h,在里面引入 LibreHardwareMonitorLib 库,并增加一个 Computer 的指针以及获取硬件信息的私有方法。
#pragma once
#include "PluginInterface.h"
#include "PluginTemplateItem.h"
#include <string>
#using "LibreHardwareMonitorLib.dll"
using namespace LibreHardwareMonitor::Hardware;
class CPluginTemplate : public ITMPlugin
{
private:
CPluginTemplate();
// 获取硬件监控信息
int GetHardwareInfo(IHardware^ hardware);
public:
static CPluginTemplate& Instance();
virtual IPluginItem* GetItem(int index) override;
virtual const wchar_t* GetTooltipInfo() override;
virtual void DataRequired() override;
virtual OptionReturn ShowOptionsDialog(void* hParent) override;
virtual const wchar_t* GetInfo(PluginInfoIndex index) override;
virtual void OnExtenedInfo(ExtendedInfoIndex index, const wchar_t* data) override;
private:
private:
static CPluginTemplate m_instance;
CPluginTemplateItem m_item;
std::wstring m_tooltip_info;
// 将 LibreHardwareMonitorLib 的 computer 声明为指针
gcroot<Computer^> computer;
};
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllexport) ITMPlugin* TMPluginGetInstance();
#ifdef __cplusplus
}
#endif
(3)然后编辑 PluginTemplate.cpp,增加 Computer 实例的创建,并通过其进行实时获取硬件数据,将其中的风扇转速保存到 CDataManager 的 m_fan_speed 变量中。
#include "pch.h"
#include "PluginTemplate.h"
#include "DataManager.h"
#include "OptionsDlg.h"
CPluginTemplate CPluginTemplate::m_instance;
CPluginTemplate::CPluginTemplate()
{
// 初始化 LibreHardwareMonitorLib 的 computer
computer = gcnew Computer();
computer->IsCpuEnabled = true;
computer->IsGpuEnabled = true;
computer->IsMemoryEnabled = true;
computer->IsMotherboardEnabled = true;
computer->IsStorageEnabled = true;
computer->IsNetworkEnabled = true;
computer->IsBatteryEnabled = true;
computer->Open(); // 打开硬件监控
}
CPluginTemplate& CPluginTemplate::Instance()
{
return m_instance;
}
IPluginItem* CPluginTemplate::GetItem(int index)
{
switch (index)
{
case 0:
return &m_item;
default:
break;
}
return nullptr;
}
const wchar_t* CPluginTemplate::GetTooltipInfo()
{
return m_tooltip_info.c_str();
}
void CPluginTemplate::DataRequired()
{
// 重置风扇转速值
CDataManager::Instance().m_fan_speed = -1;
// 遍历所有硬件并获取信息
for (int i = 0; i < computer->Hardware->Count; i++) {
IHardware^ hardware = computer->Hardware[i];
GetHardwareInfo(hardware);
std::string fan_speed_str = std::to_string(CDataManager::Instance().m_fan_speed);
OutputDebugStringA((fan_speed_str + "\n").c_str());
}
}
// 获取硬件监控信息
int CPluginTemplate::GetHardwareInfo(IHardware^ hardware) {
hardware->Update(); // 更新硬件数据
switch (hardware->HardwareType) {
case HardwareType::SuperIO: { // SuperIO 信息
// 计算风扇转速
if (CDataManager::Instance().m_fan_speed < 0) {
for (int i = 0; i < hardware->Sensors->Length; i++)
{
//找到风扇
if (hardware->Sensors[i]->SensorType == SensorType::Fan)
{
//String^ name = hardware->Sensors[i]->Name;
float speed = System::Convert::ToSingle(hardware->Sensors[i]->Value);
//保存每个风扇的转速
//m_all_fan_speed[ClrStringToStdWstring(name)] = speed;
if (speed > CDataManager::Instance().m_fan_speed)
CDataManager::Instance().m_fan_speed = speed;
}
}
}
break;
}
default: // 未知硬件类型
break;
}
// 如果硬件有子硬件,递归调用该函数处理子硬件信息
for (int i = 0; i < hardware->SubHardware->Length; i++) {
GetHardwareInfo(hardware->SubHardware[i]);
}
return 0; // 操作成功
}
ITMPlugin::OptionReturn CPluginTemplate::ShowOptionsDialog(void* hParent)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CWnd* pParent = CWnd::FromHandle((HWND)hParent);
COptionsDlg dlg(pParent);
dlg.m_data = g_data.m_setting_data;
if (dlg.DoModal() == IDOK)
{
g_data.m_setting_data = dlg.m_data;
return ITMPlugin::OR_OPTION_CHANGED;
}
return ITMPlugin::OR_OPTION_UNCHANGED;
}
const wchar_t* CPluginTemplate::GetInfo(PluginInfoIndex index)
{
static CString str;
switch (index)
{
case TMI_NAME:
return L"风扇转速";
case TMI_DESCRIPTION:
return L"返回电脑风扇实时转速信息(若有多个风扇,返回最大值)";
case TMI_AUTHOR:
return L"航歌";
case TMI_COPYRIGHT:
return L"Copyright (C) by hangge.com 2025";
case ITMPlugin::TMI_URL:
return L"http://www.hangge.com";
break;
case TMI_VERSION:
//TODO: 在此修改插件的版本
return L"1.00";
default:
break;
}
return L"";
}
void CPluginTemplate::OnExtenedInfo(ExtendedInfoIndex index, const wchar_t* data)
{
switch (index)
{
case ITMPlugin::EI_CONFIG_DIR:
//从配置文件读取配置
g_data.LoadConfig(std::wstring(data));
break;
default:
break;
}
}
ITMPlugin* TMPluginGetInstance()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return &CPluginTemplate::Instance();
}
#include "pch.h"
#include "PluginTemplateItem.h"
#include "DataManager.h"
const wchar_t* CPluginTemplateItem::GetItemName() const
{
return L"风扇转速";
}
const wchar_t* CPluginTemplateItem::GetItemId() const
{
//TODO: 在此返回插件的唯一ID,建议只包含字母和数字
return L"fan001";
}
const wchar_t* CPluginTemplateItem::GetItemLableText() const
{
return L"风扇";
}
const wchar_t* CPluginTemplateItem::GetItemValueText() const
{
static wchar_t buffer[64]; // 静态缓冲区,返回指针时需要保持有效
// 格式化为宽字符串
swprintf(buffer, sizeof(buffer) / sizeof(wchar_t), L"%.0f转/分",
CDataManager::Instance().m_fan_speed);
return buffer;
}
const wchar_t* CPluginTemplateItem::GetItemValueSampleText() const
{
return L"1888转/分";
}
bool CPluginTemplateItem::IsCustomDraw() const
{
//TODO: 根据是否由插件自绘返回对应的值
return false;
}
int CPluginTemplateItem::GetItemWidthEx(void* hDC) const
{
//绘图句柄
CDC* pDC = CDC::FromHandle((HDC)hDC);
//TODO: 如果插件需要自绘,则在此修改显示区域的宽度
return 60;
}
void CPluginTemplateItem::DrawItem(void* hDC, int x, int y, int w, int h, bool dark_mode)
{
//绘图句柄
CDC* pDC = CDC::FromHandle((HDC)hDC);
//矩形区域
CRect rect(CPoint(x, y), CSize(w, h));
//TODO: 在此添加绘图代码
}
4,编译测试
(1)在这个解决方案下有个 PluginTester 项目可以方便地进行插件地加载测试,我们右键点击解决方案,选择属性。将启动项设置为“PluginTester”并应用。

(2)然后点击顶部菜单栏“生成”->“生成解决方案”会自动编译解决方案中所有的插件,并生成对应的 dll。

(3)接着运行插件测试程序:

(4)在插件测试器中我们选择风扇转速插件 fan.dll,下方就会自动显示运行效果。

5,插件使用
要使用该插件,我们只要将这个 fan.dll 文件放到 TrafficMonitor 安装目录下的 Plugins 文件夹中即可,具体可以参考我之前写的文章:TrafficMonitor - 风扇转速显示插件安装使用教程
注意:LibreHardwareMonitorLib.dll 不需要复制过去,因为 TrafficMonitor 本身就引入了 LibreHardwareMonitor 库,插件可以直接调用。
全部评论(0)