项目实战:使用Windows API实现程序性能监控
2026/7/13 16:52:13 网站建设 项目流程

目录

1.项目介绍

2.Windows API介绍

3.项目开源


前言

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


项目介绍

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

项目 ├── 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核心/逻辑处理器数量

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:获取当前进程的伪句柄

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

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

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时间

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统计信息

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:获取指定进程的内存使用信息

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

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

8.CreateToolhelp32Snapshot:创建系统快照

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

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

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:获取线程快照中的下一条线程记录

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 对象句柄

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

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询