C++性能监视(CPU性能, GPU使用率, 磁盘读写速度, 网络速度)

CPerformHelper.h

#pragma once

#include <windows.h>
#include <tchar.h>
#include <string>
#include <pdh.h>
#include <string>
#include <mutex>
#include <thread>
#include <map>

#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif

// CPU 使用率
#define PERFM_PATH_CPU_UTILITY              "\\Processor Information(_Total)\\% Processor Utility"

// CPU 性能
#define PERFM_PATH_CPU_PERFORMANCE          "\\Processor Information(_Total)\\% Processor Performance"

// CPU 主频
#define PERFM_PATH_CPU_FREQUENCY            "\\Processor Information(_Total)\\Processor Frequency"

// 磁盘读写
#define PERFM_PATH_DISK_READ_RATE           "\\PhysicalDisk(_Total)\\Disk Read Bytes/sec"
#define PERFM_PATH_DISK_WRITE_RATE          "\\PhysicalDisk(_Total)\\Disk Write Bytes/sec"

// 网络收发
#define PERFM_PATH_NETWORK_RECV_RATE        "\\Network Interface(*)\\Bytes Received/sec"
#define PERFM_PATH_NETWORK_SENT_RATE        "\\Network Interface(*)\\Bytes Sent/sec"

// GPU
#define PERFM_PATH_GPU_UTILITY              "\\GPU Engine(*)\\Utilization Percentage"

#ifdef UNICODE
using PerfMonInfo = std::map<std::wstring, HCOUNTER> ;
#else
using PerfMonInfo = std::map<std::string, HCOUNTER>;
#endif

class CPerformHelper
{
public:
    CPerformHelper();
    virtual ~CPerformHelper();

    // 初始化
    bool Initialize();
    
    // 反初始化
    void Uninitialize();

    // 添加性能计数器
    bool AddCounter(const _tstring& strCounterPath);

    // 移除性能计数器
    bool RemoveCounter(const _tstring& strCounterPath);

    // 设置性能采集时间间隔
    void SetCollectInterval(DWORD millisecond = 1000);

    // 获取性能计数器数值
    bool GetFormattedCounterValue(const _tstring&  strCounterPath, DWORD dwFormat, PPDH_FMT_COUNTERVALUE pValue);

    // 获取性能计数器数值数组
    bool GetFormattedCounterArray(const _tstring&  strCounterPath, DWORD dwFormat, PPDH_FMT_COUNTERVALUE pValue);

    // 开始采集数据
    bool StartCollect();

private:

    void _Sleep(int millisecond);

private:
    HQUERY m_hQuery;
    bool m_fQuit;
    DWORD m_msCollectInterval;
    std::mutex m_Mutex;
    PerfMonInfo m_hPerfMonInfos;
    std::thread m_task;
};

CPerformHelper.cpp

#include "CPerformHelper.h"
#include <pdh.h>
#include <pdhmsg.h>

#pragma comment(lib, "pdh.lib")

CPerformHelper::CPerformHelper()
    :
    m_fQuit(false),
    m_hQuery(NULL),
    m_msCollectInterval(1000)
{

}

CPerformHelper::~CPerformHelper()
{
    Uninitialize();
}

void CPerformHelper::_Sleep(int millisecond)
{
    do
    {
        const int span = 1;
        if (millisecond < span)
        {
            std::this_thread::sleep_for(std::chrono::milliseconds(millisecond));
            return;
        }

        clock_t tmBegin = clock();
        while (true)
        {
            if (::clock() - tmBegin > millisecond)
            {
                break;
            }

            if (m_fQuit)
            {
                break;
            }

            std::this_thread::sleep_for(std::chrono::milliseconds(span));
        }
    } while (false);
}

bool CPerformHelper::Initialize()
{
    PDH_STATUS status = ERROR_SUCCESS;
    if (NULL == m_hQuery)
    {
        status = PdhOpenQuery(NULL, 0, &m_hQuery);
    }

    if (ERROR_SUCCESS != status)
    {
        return false;
    }

    return true;
}

void CPerformHelper::Uninitialize()
{
    m_fQuit = true;
    if (m_task.joinable())
    {
        m_task.join();
    }
    m_fQuit = false;

    if (m_hQuery)
    {
        ::PdhCloseQuery(m_hQuery);
        m_hQuery = NULL;
    }

    for (auto& item : m_hPerfMonInfos)
    {
        if (NULL != item.second)
        {
            ::PdhRemoveCounter(item.second);
        }
    }

    m_hPerfMonInfos.clear();
}

bool CPerformHelper::AddCounter(const _tstring& strCounterPath)
{
    HCOUNTER hCounter = NULL;
    PDH_STATUS status = ERROR_SUCCESS;

    status = ::PdhAddCounter(m_hQuery, strCounterPath.c_str(), 0, &hCounter);

    if (ERROR_SUCCESS != status)
    {
        return false;
    }

    m_Mutex.lock();
    m_hPerfMonInfos.insert(std::make_pair(strCounterPath, hCounter));
    m_Mutex.unlock();

    return true;
}

bool CPerformHelper::RemoveCounter(const _tstring& szCounterPath)
{
    bool fResult = false;

    m_Mutex.lock();
    auto itFind = m_hPerfMonInfos.find(szCounterPath);

    if (itFind != m_hPerfMonInfos.end())
    {
        ::PdhRemoveCounter(itFind->second);
        m_hPerfMonInfos.erase(itFind);
        fResult = true;
    }

    m_Mutex.unlock();

    return fResult;
}

void CPerformHelper::SetCollectInterval(DWORD millisecond)
{
    if (millisecond < 100)
    {
        m_msCollectInterval = 100;
    }

    m_msCollectInterval = millisecond;
}

bool CPerformHelper::StartCollect()
{
    PDH_STATUS status = ERROR_SUCCESS;
    status = ::PdhCollectQueryData(m_hQuery);

    if (ERROR_SUCCESS != status)
    {
        return false;
    }

    m_task = std::move(std::thread([&]() {

        PDH_STATUS status = ERROR_SUCCESS;
        while ((ERROR_SUCCESS == status) && !m_fQuit)
        {
            status = ::PdhCollectQueryData(m_hQuery);
            if (ERROR_SUCCESS != status)
            {
                break;
            }

            _Sleep(m_msCollectInterval);
        }

        }));

    return ERROR_SUCCESS == status;
}

bool CPerformHelper::GetFormattedCounterValue(const _tstring& strCounterPath, DWORD dwFormat, PPDH_FMT_COUNTERVALUE pValue)
{
    PDH_STATUS status = ERROR_SUCCESS;

    auto itFind = m_hPerfMonInfos.find(strCounterPath);
    if (m_hPerfMonInfos.end() == itFind)
    {
        return false;
    }

    status = ::PdhGetFormattedCounterValue(
        itFind->second,
        dwFormat,
        (LPDWORD)NULL,
        pValue);

    return ERROR_SUCCESS == status;
}

bool CPerformHelper::GetFormattedCounterArray(const _tstring& strCounterPath, DWORD dwFormat, PPDH_FMT_COUNTERVALUE pValue)
{
    PPDH_FMT_COUNTERVALUE_ITEM pAryValue = NULL;
    PDH_STATUS status = ERROR_SUCCESS;
    DWORD dwBufferSize = 0;
    DWORD dwItemCount = 0;

    auto itFind = m_hPerfMonInfos.find(strCounterPath);
    if (m_hPerfMonInfos.end() == itFind)
    {
        return false;
    }

    do
    {
        status = ::PdhGetFormattedCounterArray(
            itFind->second,
            dwFormat,
            &dwBufferSize,
            &dwItemCount,
            NULL
        );

        if (PDH_MORE_DATA != status)
        {
            break;
        }

        pAryValue = (PPDH_FMT_COUNTERVALUE_ITEM)::HeapAlloc(::GetProcessHeap(), 0, dwBufferSize);
        if (NULL == pAryValue)
        {
            break;
        }

        status = ::PdhGetFormattedCounterArray(
            itFind->second,
            dwFormat,
            &dwBufferSize,
            &dwItemCount,
            pAryValue
        );

        PDH_FMT_COUNTERVALUE value = { 0 };
        for (int i = 0; i < dwItemCount; i++)
        {
            if (PDH_FMT_DOUBLE == dwFormat)
            {
                value.doubleValue += pAryValue[i].FmtValue.doubleValue;
            }
            if (PDH_FMT_LARGE == dwFormat)
            {
                value.largeValue += pAryValue[i].FmtValue.largeValue;
            }
            if (PDH_FMT_LONG == dwFormat)
            {
                value.longValue += pAryValue[i].FmtValue.longValue;
            }
        }

        if (pValue)
        {
            *pValue = value;
        }

    } while (false);

    if (pAryValue)
    {
        ::HeapFree(::GetProcessHeap(), 0, pAryValue);
    }

    return ERROR_SUCCESS == status;
}

main.cpp

#include <iostream>
#include "Win32Utils/CDeviceHelper.h"
#include "Win32Utils/CWmiQueryHelper.h"
#include "CPerformHelper.h"

#include "Win32Utils/CDeviceHelper.h"

// 数据单位
enum eUnitType
{
    eUT_Auto,   // 自动
    eUT_b,      // (2 ^ 000) Bit
    eUT_Kb,     // (2 ^ 010) Bit
    eUT_Mb,     // (2 ^ 020) Bit
    eUT_Gb,     // (2 ^ 030) Bit
    eUT_Tb,     // (2 ^ 040) Bit
    eUT_Pb,     // (2 ^ 050) Bit
    eUT_Eb,     // (2 ^ 060) Bit
    eUT_Zb,     // (2 ^ 070) Bit
    eUT_Yb,     // (2 ^ 080) Bit
    eUT_Bb,     // (2 ^ 090) Bit
    eUT_Nb,     // (2 ^ 100) Bit
    eUT_Db,     // (2 ^ 110) Bit
    eUT_Cb,     // (2 ^ 120) Bit
    eUT_Xb,     // (2 ^ 130) Bit

    eUT_B,      // Byte          2 ^ 000 Byte
    eUT_KB,     // Kilobyte      2 ^ 010 Byte 
    eUT_MB,     // Megabyte      2 ^ 020 Byte 
    eUT_GB,     // Gigabyte      2 ^ 030 Byte 
    eUT_TB,     // Terabyte      2 ^ 040 Byte 
    eUT_PB,     // Petabyte      2 ^ 050 Byte 
    eUT_EB,     // Exabyte       2 ^ 060 Byte 
    eUT_ZB,     // Zettabyte     2 ^ 070 Byte 
    eUT_YB,     // Yottabyte     2 ^ 080 Byte 
    eUT_BB,     // Brontobyte    2 ^ 090 Byte 
    eUT_NB,     // NonaByte      2 ^ 100 Byte 
    eUT_DB,     // DoggaByte     2 ^ 110 Byte 
    eUT_CB,     // corydonbyte   2 ^ 120 Byte 
    eUT_XB,     // Xerobyte      2 ^ 130 Byte
    eUT_Max
};

typedef struct _DATA_UNIT_INFO
{
    double value;           // 数值
    eUnitType eUnit;        // 单位
    _tstring strUnitStr;    // 单位字符串
    _tstring strOutput;     // 内容(数值 + 单位字符串)
}DATA_UNIT_INFO;

static DATA_UNIT_INFO FormatByteSize(
    double nBytesSize,                                      // 输入值
    eUnitType eSrcUnit = eUnitType::eUT_Auto,               // 原始单位
    eUnitType eDestUnit = eUnitType::eUT_Auto,              // 目标单位
    bool fHasUnits = true,                                  // 结果字符串数值添加单位
    bool fSpace = true,                                     // 结果字符串数值与单位之间添加空格
    int nInteger = 1,                                       // 整数部分长度
    int nPrecision = 1                                      // 小数部分长度
);

void ConsoleOutput(LPCTSTR pFormat, ...);
void ConsoleClear();

int main()
{
    setlocale(LC_ALL, "");

    std::vector<VIDEO_ADAPTER_DESC_INFO> vResult = CDeviceHelper::GetAllVideoAdapterDesc();

    CDeviceHelper obj;

    clock_t tmBegin = ::clock();
    DEVICE_INFO info = obj.GetDeviceInfo();
    clock_t tmEnd = ::clock();

    ConsoleOutput(_T("cost time: %d\r\n"), tmEnd - tmBegin);

    CPerformHelper perfmon;

    perfmon.Initialize();
    perfmon.SetCollectInterval(1000);
    perfmon.AddCounter(_T(PERFM_PATH_CPU_UTILITY));
    perfmon.AddCounter(_T(PERFM_PATH_DISK_READ_RATE));
    perfmon.AddCounter(_T(PERFM_PATH_DISK_WRITE_RATE));
    perfmon.AddCounter(_T(PERFM_PATH_CPU_PERFORMANCE));
    perfmon.AddCounter(_T(PERFM_PATH_CPU_FREQUENCY));
    perfmon.AddCounter(_T(PERFM_PATH_NETWORK_RECV_RATE));
    perfmon.AddCounter(_T(PERFM_PATH_NETWORK_SENT_RATE));
    perfmon.AddCounter(_T(PERFM_PATH_GPU_UTILITY));
    perfmon.AddCounter(_T(PERFM_PATH_GPU_MEMORY_DEDICATED_USAGE_UTILITY));
    perfmon.AddCounter(_T(PERFM_PATH_GPU_MEMORY_SHARE_USAGE_UTILITY));
    perfmon.AddCounter(_T(PERFM_PATH_GPU_MEMORY_TOTAL_COMMITTED_USAGE_UTILITY));
    perfmon.StartCollect();

    PDH_FMT_COUNTERVALUE value = { 0 };

    SIZE_T DedicatedVideoMemory = vResult[0].AdapterDesc.DedicatedVideoMemory;
    SIZE_T DedicatedSystemMemory = vResult[0].AdapterDesc.DedicatedSystemMemory;
    SIZE_T SharedSystemMemory = vResult[0].AdapterDesc.SharedSystemMemory;

    MEMORYSTATUSEX memStatus = { 0 };
    memStatus.dwLength = sizeof(MEMORYSTATUSEX);

    double lfFrequency = 0.0f;
    while (true)
    {
        ::GlobalMemoryStatusEx(&memStatus);

        ConsoleClear();
        ::SetConsoleCursorPosition(::GetStdHandle(STD_OUTPUT_HANDLE), { 0, 0 });

        //获取CPU占用率
        if (perfmon.GetFormattedCounterArray(_T(PERFM_PATH_CPU_UTILITY), PDH_FMT_DOUBLE, &value))
        {
            ConsoleOutput(_T("CPU 利用率: %.2lf%% "), value.doubleValue);
            //ConsoleOutput(_T("\r\n"));
        }

        //获取CPU性能
        if (perfmon.GetFormattedCounterArray(_T(PERFM_PATH_CPU_FREQUENCY), PDH_FMT_DOUBLE, &value))
        {
            lfFrequency = value.doubleValue;
        }

        //获取CPU性能
        if (perfmon.GetFormattedCounterArray(_T(PERFM_PATH_CPU_PERFORMANCE), PDH_FMT_DOUBLE, &value))
        {
            ConsoleOutput(_T("当前主频: %.2lf Ghz "), value.doubleValue / 100.0f * lfFrequency / 1000.0f);
            ConsoleOutput(_T("基准频率: %.2lf Ghz"), lfFrequency / 1000.0f);
            ConsoleOutput(_T("\r\n"));
        }

        //物理内存
        ConsoleOutput(_T("内存: %.1lf"), FormatByteSize(memStatus.ullTotalPhys - memStatus.ullAvailPhys, eUnitType::eUT_B, eUnitType::eUT_GB).value);
        ConsoleOutput(_T("/"));
        ConsoleOutput(_T("%s "), FormatByteSize(memStatus.ullTotalPhys, eUnitType::eUT_B, eUnitType::eUT_GB).strOutput.c_str());
        ConsoleOutput(_T("%.2lf%%"), (double)(memStatus.ullTotalPhys - memStatus.ullAvailPhys) * 100 /(double)memStatus.ullTotalPhys);
        ConsoleOutput(_T("\r\n"));


        //获取GPU占用率
        if (perfmon.GetFormattedCounterArray(_T(PERFM_PATH_GPU_UTILITY), PDH_FMT_DOUBLE, &value))
        {
            ConsoleOutput(_T("GPU 利用率: %.1lf%%"), value.doubleValue);
            ConsoleOutput(_T("\r\n"));
        }

        if (perfmon.GetFormattedCounterArray(_T(PERFM_PATH_GPU_MEMORY_DEDICATED_USAGE_UTILITY), PDH_FMT_DOUBLE, &value))
        {
            ConsoleOutput(_T("专用 GPU 内存: %0.1lf"), FormatByteSize(value.doubleValue, eUnitType::eUT_B, eUnitType::eUT_GB).value);
            ConsoleOutput(_T("/%s"), FormatByteSize(DedicatedVideoMemory).strOutput.c_str());
            ConsoleOutput(_T("\r\n"));
        }

        if (perfmon.GetFormattedCounterArray(_T(PERFM_PATH_GPU_MEMORY_SHARE_USAGE_UTILITY), PDH_FMT_DOUBLE, &value))
        {
            ConsoleOutput(_T("共享 GPU 内存: %0.1lf"), FormatByteSize(value.doubleValue, eUnitType::eUT_B, eUnitType::eUT_GB).value);
            ConsoleOutput(_T("/%s"), FormatByteSize(SharedSystemMemory).strOutput.c_str());
            ConsoleOutput(_T("\r\n"));
        }

        //获取硬盘读速度
        if (perfmon.GetFormattedCounterArray(_T(PERFM_PATH_DISK_READ_RATE), PDH_FMT_DOUBLE, &value))
        {
            ConsoleOutput(_T("磁盘 读取: %s/s "), FormatByteSize(value.doubleValue).strOutput.c_str());
        }

        //获取硬盘写速度
        if (perfmon.GetFormattedCounterArray(_T(PERFM_PATH_DISK_WRITE_RATE), PDH_FMT_DOUBLE, &value))
        {
            ConsoleOutput(_T("磁盘 写入: %s/s"), FormatByteSize(value.doubleValue).strOutput.c_str());
            ConsoleOutput(_T("\r\n"));
        }

        //获取网络读速度
        if (perfmon.GetFormattedCounterArray(_T(PERFM_PATH_NETWORK_RECV_RATE), PDH_FMT_DOUBLE, &value))
        {
            ConsoleOutput(_T("网络 接收: %sps "), FormatByteSize(value.doubleValue).strOutput.c_str());
        }

        //获取网络写速度
        if (perfmon.GetFormattedCounterArray(_T(PERFM_PATH_NETWORK_SENT_RATE), PDH_FMT_DOUBLE, &value))
        {
            ConsoleOutput(_T("网络 发送: %sps"), FormatByteSize(value.doubleValue).strOutput.c_str());
            ConsoleOutput(_T("\r\n"));
        }

        ConsoleOutput(_T("\r\n"));
        ::Sleep(1000);
    }

    return 0;
}

void ConsoleOutput(LPCTSTR pFormat, ...)
{
    size_t nCchCount = MAX_PATH;
    _tstring strResult(nCchCount, 0);
    va_list args;

    va_start(args, pFormat);

    do
    {
        //格式化输出字符串
        int nSize = _vsntprintf_s(&strResult[0], nCchCount, _TRUNCATE, pFormat, args);
        if (-1 != nSize)
        {
            HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
            CONSOLE_SCREEN_BUFFER_INFOEX ScreenBuffer = { 0 };
            ScreenBuffer.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);

            ::GetConsoleScreenBufferInfoEx(console, &ScreenBuffer);

            // 如果在行开头写入文本, 则先清空当前行内容
            if (0 == ScreenBuffer.dwCursorPosition.X)
            {
                DWORD dwNumberOfCharsWritten = 0;
                ::FillConsoleOutputCharacter(
                    console, 
                    _T(' '), 
                    ScreenBuffer.dwMaximumWindowSize.X, 
                    { 0, ScreenBuffer.dwCursorPosition.Y },
                    &dwNumberOfCharsWritten
                );
            }

            ::WriteConsole(console, strResult.c_str(), nSize, NULL, NULL);
            break;
        }

        //缓冲大小超限终止
        if (nCchCount >= INT32_MAX)
        {
            break;
        }

        //重新分配缓冲
        nCchCount *= 2;
        strResult.resize(nCchCount);

    } while (true);

    va_end(args);
}

void ConsoleClear()
{
    HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFOEX ScreenBuffer = { 0 };
    ScreenBuffer.cbSize = sizeof(CONSOLE_SCREEN_BUFFER_INFOEX);

    ::GetConsoleScreenBufferInfoEx(console, &ScreenBuffer);

    for (SHORT i = ScreenBuffer.dwCursorPosition.Y; i < ScreenBuffer.dwMaximumWindowSize.Y; i++)
    {
        DWORD dwNumberOfCharsWritten = 0;
        ::FillConsoleOutputCharacter(
            console, 
            _T(' '), 
            ScreenBuffer.dwMaximumWindowSize.X, 
            { 0, ScreenBuffer.dwCursorPosition.Y },
            &dwNumberOfCharsWritten
        );
    }
}

DATA_UNIT_INFO FormatByteSize(
    double nBytesSize,
    eUnitType eSrcUnit/* = eUnitType::eUT_Auto*/,
    eUnitType eDestUnit/* = eUnitType::eUT_Auto*/,
    bool fHasUnits/* = true*/,
    bool fSpace/* = true*/,
    int nInteger/* = 1*/,
    int nPrecision/* = 3*/
)
{
    TCHAR szFormatBuf[MAX_PATH] = { 0 };
    TCHAR szResultBuf[MAX_PATH] = { 0 };
    DATA_UNIT_INFO dataUnitInfo;
    bool fSrcBit = false;
    bool fDestBit = false;

    LPCTSTR strUnitByteName[] = {
        _T("B"),
        _T("KB"),
        _T("MB"),
        _T("GB"),
        _T("TB"),
        _T("PB"),
        _T("EB"),
        _T("ZB"),
        _T("YB"),
        _T("BB"),
        _T("NB"),
        _T("DB"),
        _T("CB"),
        _T("XB"),
    };

    LPCTSTR strUnitBitName[] = {
        _T("b"),
        _T("Kb"),
        _T("Mb"),
        _T("Gb"),
        _T("Tb"),
        _T("Pb"),
        _T("Eb"),
        _T("Zb"),
        _T("Yb"),
        _T("Bb"),
        _T("Nb"),
        _T("Db"),
        _T("Cb"),
        _T("Xb"),
    };

    // 原始单位 比特 -> 字节
    if (eSrcUnit >= eUnitType::eUT_b && eSrcUnit < eUnitType::eUT_B)
    {
        fSrcBit = true;
        eSrcUnit = (eUnitType)(eSrcUnit + (eUnitType::eUT_B - eUnitType::eUT_b));
    }

    // 目标单位 比特 -> 字节
    if (eDestUnit >= eUnitType::eUT_b && eDestUnit < eUnitType::eUT_B)
    {
        fDestBit = true;
        eDestUnit = (eUnitType)(eDestUnit + (eUnitType::eUT_B - eUnitType::eUT_b));
    }

    // 原始单位转换
    for (int i = eUnitType::eUT_B; i < eSrcUnit; i++)
    {
        nBytesSize *= 1024.0f;
    }

    // 自动
    int nUnitTypeIndex = eUnitType::eUT_B;
    if (eUnitType::eUT_Auto == eDestUnit)
    {
        double nCurUnitSize = 1.0f;
        double nNextUnitSize = 1024.0f;
        int nUnitTypeMaxIndex = eUnitType::eUT_Max - 1;
        for (int i = 0; i < _countof(strUnitByteName) && nUnitTypeIndex < nUnitTypeMaxIndex; i++)
        {
            if ((nBytesSize >= nCurUnitSize && nBytesSize < nNextUnitSize) || 0 == nNextUnitSize || 0 == nBytesSize)
            {
                break;
            }

            nCurUnitSize *= 1024.0f;
            nNextUnitSize *= 1024.0f;
            nUnitTypeIndex++;
        }
        eDestUnit = (eUnitType)nUnitTypeIndex;
    }

    {
        ::_stprintf_s(szFormatBuf, _countof(szFormatBuf), _T("%%%d.%dlf"), nInteger + nPrecision + 1, nPrecision);
        double fUnitSize = 1.0f;
        for (int i = eUnitType::eUT_B; i < eDestUnit; i++)
        {
            fUnitSize *= 1024.0f;
        }

        if (fSrcBit)
        {
            fUnitSize *= 8.0f;
        }

        if (fDestBit)
        {
            nBytesSize *= 8.0f;
        }

        double lfResult = nBytesSize / fUnitSize;
        ::_stprintf_s(szResultBuf, _countof(szResultBuf), szFormatBuf, lfResult);
        dataUnitInfo.strOutput = szResultBuf;
        dataUnitInfo.value = lfResult;

        if (fHasUnits)
        {
            if (fSpace)
            {
                dataUnitInfo.strOutput += _T(" ");
            }

            if (fDestBit)
            {
                dataUnitInfo.strOutput += strUnitBitName[eDestUnit - eUnitType::eUT_B];
                dataUnitInfo.strUnitStr = strUnitBitName[eDestUnit - eUnitType::eUT_B];
                dataUnitInfo.eUnit = (eUnitType)(eDestUnit + (eUnitType::eUT_B - eUnitType::eUT_b));
            }
            else
            {
                dataUnitInfo.strOutput += strUnitByteName[eDestUnit - eUnitType::eUT_B];
                dataUnitInfo.strUnitStr = strUnitByteName[eDestUnit - eUnitType::eUT_B];
                dataUnitInfo.eUnit = eDestUnit;
            }
        }
    }

    return dataUnitInfo;
}

 仓库 

https://gitee.com/flame_cyclone/c_device_utils

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值