项目实战:使用Windows API实现程序性能监控

本文介绍了如何在Windows系统下使用Windows API实现程序性能监控工具的开发。由于Windows系统的开放性限制,作者开发了一个基于Visual Studio和Qt6的可视化监控工具,包含CPU、内存、I/O和线程监控模块。文章详细讲解了10个关键Windows API的使用方法,包括GetSystemInfo、GetProcessTimes、GetProcessMemoryInfo等,并提供了结构体参数说明。项目采用模块化设计,使用者可根据需要选择特定监控模块或整体集成。该工具旨在帮助开发者捕

作者
WildPointer
发布
2026.07.12
专栏
项目实战
阅读
约 11 分钟 / 197 次原文浏览
项目实战:使用Windows API实现程序性能监控

前言

Windows系统区别与Linux系统并没有那么多的开源工具,对系统的开放性也比较差,所以导致很多情况下程序出现问题时,不能很好的定位程序发生问题的地方,而使用Ai或者查阅相关的博客推荐的工具都是Linux系统下的,为了解决这个问题所以博主写了这篇《项目实战:使用Windows API实现程序性能监控》。本篇博客主要是为了使用Windows API来监控程序,防止某些偶发性的Bug导致程序异常时,系统无法提供完善的信息来使我们定位问题。 


项目介绍

        本文初始项目是使用Visual Studio + Qt6编写的,其中Qt作为可视化前端界面输出监控的信息,主要功能则是在systemMonitor类中,其中每一个XXXMonitor文件夹对应监控不同的信息,有进程信息,IO信息,内存信息和CPU信息。如果需要使用对应的监控可以把对应的文件夹迁移到项目中即可,如果需要使用全部的监控功能则只需要拷贝systemMonitor类和XXXMonitor文件夹即可实现监控信息的输出,当前项目的结构如下:

bash
项目 ├── QtMonitor.sln └── QtMonitor     ├── cpuMonitor     │   ├── cpuMonitor.h     │   └── cpuMonitor.cpp     ├── ioMonitor     │   ├── ioMonitor.h     │   └── ioMonitor.cpp     ├── memoryMonitor     │   ├── memoryMonitor.h     │   └── memoryMonitor.cpp     ├── threadMonitor     │   ├── threadMonitor.h     │   └── threadMonitor.cpp     ├── main.cpp     ├── QtMonitor.h     ├── QtMonitor.cpp     ├── QtMonitor.ui     ├── QtMonitor.qrc     ├── systemMonitor.h     ├── systemMonitor.cpp     └── io_test.txt

项目所实现的功能也比较简单,具体如图:

图1.项目概况


Windows API介绍

在当前项目中使用了很多Windows API,本小节则主要讲解这些API和API相关的参数。具体如下:
1.GetSystemInfo:获取CPU核心/逻辑处理器数量

cpp
void GetSystemInfo(    LPSYSTEM_INFO lpSystemInfo // 输出参数);SYSTEM_INFO 结构体说明:typedef struct _SYSTEM_INFO {    union {        DWORD dwOemId;                         // 旧版本字段,现代代码通常不直接使用        struct {            WORD wProcessorArchitecture;       // 处理器架构,例如 x86、x64、ARM            WORD wReserved;                    // 保留字段        };    };    DWORD     dwPageSize;                      // 内存页大小,单位为字节    LPVOID    lpMinimumApplicationAddress;     // 应用程序可访问的最低内存地址    LPVOID    lpMaximumApplicationAddress;     // 应用程序可访问的最高内存地址    DWORD_PTR dwActiveProcessorMask;           // 当前活动处理器掩码    DWORD     dwNumberOfProcessors;            // 当前系统逻辑处理器数量    DWORD     dwProcessorType;                 // 处理器类型,旧字段,通常不再推荐依赖    DWORD     dwAllocationGranularity;         // 虚拟内存分配粒度,单位为字节    WORD      wProcessorLevel;                 // 处理器级别    WORD      wProcessorRevision;              // 处理器版本} SYSTEM_INFO;

2.GetCurrentProcess:获取当前进程的伪句柄

cpp
HANDLE GetCurrentProcess(void);返回值类型 HANDLE:   返回当前进程的伪句柄。该句柄只代表当前进程,不需要调用CloseHandle关闭   是Windows对系统对象的句柄类型,例如进程、线程、快照等

3.GetProcessTimes:获取指定进程的时间信息,项目中用于计算当前进程CPU占用率

cpp
BOOL GetProcessTimes(    HANDLE     hProcess,        // 进程句柄    LPFILETIME lpCreationTime,  // 接收进程创建时间    LPFILETIME lpExitTime,      // 接收进程退出时间;进程未退出时通常无有效退出时间    LPFILETIME lpKernelTime,    // 接收进程在内核态消耗的CPU时间    LPFILETIME lpUserTime       // 接收进程在用户态消耗的CPU时间);返回值FILETIME结构体说明:    返回非0表示调用成功。    返回0表示调用失败,可通过GetLastError获取错误原因    项目中使用lpKernelTime + lpUserTime的增量计算当前进程CPU使用率    typedef struct _FILETIME {        DWORD dwLowDateTime;    // 64位时间值的低32位        DWORD dwHighDateTime;   // 64位时间值的高32位    } FILETIME;

4.GetSystemTimes:获取系统整体CPU时间

cpp
BOOL GetSystemTimes(    LPFILETIME lpIdleTime,    // 接收系统空闲时间    LPFILETIME lpKernelTime,  // 接收系统内核态时间,该值包含空闲时间    LPFILETIME lpUserTime     // 接收系统用户态时间);返回值FILETIME结构体:    返回非0表示调用成功    返回0表示调用失败,可通过GetLastError获取错误原因    typedef struct _FILETIME {        DWORD dwLowDateTime;    // 64位时间值的低32位        DWORD dwHighDateTime;   // 64位时间值的高32位    } FILETIME;

5.GetProcessIoCounters:获取指定进程的I/O统计信息

cpp
BOOL GetProcessIoCounters(    HANDLE       hProcess,    // 进程句柄    PIO_COUNTERS lpIoCounters // 指向IO_COUNTERS结构体,函数会写入进程I/O计数);返回值IO_COUNTERS结构体说明:    返回非0表示调用成功    返回0表示调用失败,可通过GetLastError获取错误原因    typedef struct _IO_COUNTERS {        ULONGLONG ReadOperationCount;    // 读操作次数        ULONGLONG WriteOperationCount;   // 写操作次数        ULONGLONG OtherOperationCount;   // 其他 I/O 操作次数        ULONGLONG ReadTransferCount;     // 读传输字节总数        ULONGLONG WriteTransferCount;    // 写传输字节总数        ULONGLONG OtherTransferCount;    // 其他 I/O 传输字节总数    } IO_COUNTERS;

6.GetProcessMemoryInfo:获取指定进程的内存使用信息

cpp
BOOL GetProcessMemoryInfo(    HANDLE                   Process,           // 进程句柄    PPROCESS_MEMORY_COUNTERS ppsmemCounters,    // 指向PROCESS_MEMORY_COUNTERS或 PROCESS_MEMORY_COUNTERS_EX结构体    DWORD                    cb                 // 结构体大小);返回值PROCESS_MEMORY_COUNTERS_EX结构体说明:    返回非0表示调用成功    返回0表示调用失败,可通过 GetLastError 获取错误原因    typedef struct _PROCESS_MEMORY_COUNTERS_EX {        DWORD  cb;                           // 结构体大小        DWORD  PageFaultCount;               // 页面错误次数        SIZE_T PeakWorkingSetSize;           // 峰值工作集大小,单位为字节        SIZE_T WorkingSetSize;               // 当前工作集大小,单位为字节        SIZE_T QuotaPeakPagedPoolUsage;      // 分页池配额峰值        SIZE_T QuotaPagedPoolUsage;          // 当前分页池配额使用量        SIZE_T QuotaPeakNonPagedPoolUsage;   // 非分页池配额峰值        SIZE_T QuotaNonPagedPoolUsage;       // 当前非分页池配额使用量        SIZE_T PagefileUsage;                // 当前提交/页面文件使用量,单位为字节        SIZE_T PeakPagefileUsage;            // 峰值提交/页面文件使用量,单位为字节        SIZE_T PrivateUsage;                 // 当前进程私有提交内存,单位为字节    } PROCESS_MEMORY_COUNTERS_EX;

7.GetCurrentProcessId:获取当前进程ID

cpp
DWORD GetCurrentProcessId(void);返回值DWORD类型说明:    返回当前进程的进程 ID。    typedef unsigned long DWORD;    // Windows常用的32位无符号整数类型

8.CreateToolhelp32Snapshot:创建系统快照

cpp
HANDLE CreateToolhelp32Snapshot(    DWORD dwFlags,        // 采集系统线程快照    DWORD th32ProcessID   // 进程ID,集线程快照时该参数通常传0);返回值说明:    成功时返回快照句柄    失败时返回INVALID_HANDLE_VALUE    该函数返回的是真实句柄,使用完成后必须调用CloseHandle关闭

9.Thread32First:获取线程快照中的第一条线程记录

cpp
BOOL Thread32First(    HANDLE          hSnapshot,    // CreateToolhelp32Snapshot返回的线程快照句柄    LPTHREADENTRY32 lpte          // 指向THREADENTRY32结构体,调用前必须设置lpte->dwSize = sizeof(THREADENTRY32)。);返回值THREADENTRY32结构体说明:    返回TRUE表示成功获取第一条线程记录    返回FALSE表示失败,可能是快照为空或句柄无效    typedef struct tagTHREADENTRY32 {        DWORD dwSize;               // 结构体大小,调用Thread32First前必须设置        DWORD cntUsage;             // 线程引用计数,通常不使用        DWORD th32ThreadID;         // 线程ID        DWORD th32OwnerProcessID;   // 拥有该线程的进程ID        LONG  tpBasePri;            // 线程基础优先级        LONG  tpDeltaPri;           // 线程优先级增量,通常不使用        DWORD dwFlags;              // 保留字段    } THREADENTRY32;

10.Thread32Next:获取线程快照中的下一条线程记录

cpp
BOOL Thread32Next(    HANDLE          hSnapshot,  // CreateToolhelp32Snapshot返回的线程快照句柄    LPTHREADENTRY32 lpte        // 指向THREADENTRY32结构体,用于接收下一条线程记录);返回值THREADENTRY32结构体说明:    返回TRUE表示成功获取下一条线程记录    返回FALSE表示没有更多线程记录或调用失败    typedef struct tagTHREADENTRY32 {        DWORD dwSize;              // 结构体大小        DWORD cntUsage;            // 线程引用计数,通常不使用        DWORD th32ThreadID;        // 线程ID        DWORD th32OwnerProcessID;  // 拥有该线程的进程ID        LONG  tpBasePri;           // 线程基础优先级        LONG  tpDeltaPri;          // 线程优先级增量,通常不使用        DWORD dwFlags;             // 保留字段    } THREADENTRY32;

11.CloseHandle:关闭一个已打开的 Windows 对象句柄

cpp
BOOL CloseHandle(    HANDLE hObject    // 需要关闭的对象句柄);返回值说明:    返回非0表示关闭成功。    返回0表示关闭失败,可通过GetLastError获取错误原因    注意:CreateToolhelp32Snapshot返回的快照句柄需要CloseHandle          GetCurrentProcess返回的是当前进程伪句柄,不需要CloseHandle

项目开源
https://github.com/3020Xmy/QtMonitorhttps://github.com/3020Xmy/QtMonitor

6次原文点赞;这里的喜欢仅保存在本机
WildPointer

专注系统编程、工程实践与底层技术,记录 C++、Qt、OpenCV 与 VTK 的学习和实践。