返回 导航

其他

hangge.com

C++ - TrafficMonitor插件开发教程(以风扇转速显示插件为例)

作者:hangge | 2025-06-14 09:27
    TrafficMonitor 是一款轻量级的系统监控软件,支持显示 CPU、内存、网络速度等信息(点击查看)。虽然 TrafficMonitor 提供了许多监控项目,但一直没有风扇转速的显示功能。本文以风扇转速显示插件为例,演示如何进行 TrafficMonitor 插件的开发。当然,如果需要直接使用该插件,可以查看我另一篇文章进行下载使用(点击访问)。

1,准备工作

(1)首先我们将 TrafficMonitor 官方的插件模板项目下载到本地:

(2)为了方便后续的开发和管理,我这里将里面自带的模板项目 PluginTemplate 修改成 Fan。关于修改项目名称的具体方法可以参考我之前写的文章:

(3)后面就要在这个模板项目上进行开发。

2,添加 LibreHardwareMonitorLib.dll

(1)我这里是借助 LibreHardwareMonitor 这个第三方的开源硬件监控库来获取风扇转速信息。因此我们首先访问问其官方 GitHub 仓库(点击访问)下载最新的发布版本。

(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 实例的创建,并通过其进行实时获取硬件数据,将其中的风扇转速保存到 CDataManagerm_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();
}

(4)最后编辑 PluginTemplateItem.cpp,在这里面返回监测项的信息以及实时监测数据:
#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)

回到顶部