发布时间:2026/9/3 3:49:02
项目实战:使用Windows API实现程序性能监控 目录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获取当前进程IDDWORD 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

相关新闻

2026/9/2 0:34:43

【大数据课程设计/毕业设计】基于spring 的新冠肺炎疫情实时监控系统的设计与实现 基于spring 的疫情数据可视化分析系统的设计与实现【附源码、数据库、万字文档】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

2026/9/3 3:47:19

MATLAB车辆运动目标跟踪:从背景建模到多目标跟踪的工程实践

简介:本资源是一个面向本科毕业设计与课程设计的MATLAB车辆运动目标跟踪检测实践项目,聚焦视频流中车辆目标的实时检测与连续跟踪,涵盖图像预处理、背景建模、运动检测、目标分割、卡尔曼/粒子滤波跟踪、HOG/SIFT特征匹配等核心计算机视觉技术…

2026/9/3 3:47:19

从自举开发到工程闭环:OpenClaw如何用智能体开发智能体

在 AI Agent 开发领域,判断一个框架是否真正做到工程可用,有一个比功能清单更硬的指标:这个团队自己是否在用自家智能体开发自己。OpenClaw 团队的“自举”开发,指的就是智能体开始参与编写、测试和维护智能体框架本身的代码。这种…

2026/9/3 3:47:19

Unity Mesh VFX实战:让角色特效真正贴合模型的技术解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/3 3:47:19

Java进销存ERP源码:业务规则与数据一致性的工程实践

简介:这是一套基于SpringBoot开发的Java进销存ERP管理系统源码,面向Java初学者、企业信息化开发者及毕业设计学习者,提供可直接运行的中小型商贸企业管理解决方案。系统覆盖零售、采购、销售、仓库、财务、报表与系统管理等核心模块&#xff…

2026/9/3 3:42:19

STM32 USB复合设备实战:HID+CDC设计要点与调试经验

简介:这是一份基于STM32F103ZE与Keil 5实现的USB复合设备工程,将HID与CDC功能融合于同一USB接口,适用于需要同时进行人机交互与虚拟串口通信的嵌入式开发场景。资源使用STD标准库并基于官方例程修改,实测可在电脑上同时识别HID和C…

2026/9/1 16:02:17

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/2 9:00:32

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/2 8:41:06

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/3 0:02:06

零基础装 OpenClaw 小龙虾 AI:Windows 一键部署教程与避坑要点

Windows 部署 OpenClaw 完整教程|本地 AI 智能体 5 分钟落地,环境配置一次搞定 版本说明:Windows 3.1.0 / Mac 2.7.9 写在前面 近两年开源 AI 领域有一款被称作「数字员工」的工具持续走热,它就是 OpenClaw,圈内人更习…

2026/9/3 0:02:06

Hermes Agent 本地部署新方案:Windows 整合包减少依赖报错

Windows 本地部署 Hermes 太麻烦?这版一键包 5 分钟快速跑通 很多人想体验 Hermes Agent,但真正开始部署时,往往会卡在环境配置这一步。 需要安装各类依赖、调试运行环境、处理路径问题,还容易遇到命令行报错、系统拦截、文件缺…

2026/9/3 0:02:06

实测 OpenClaw 一键包,5 分钟完成本地自动化环境搭建

OpenClaw 本地 AI 自动化工具部署指南|使用一键包规避环境配置难题 痛点:部署 AI 自动化工具常常要处理 Python、Node.js 各类依赖,版本冲突、环境配置耗费大量时间,OpenClaw 提供一键安装包,降低部署门槛。 适配系统&…

2026/9/2 1:15:22

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/2 1:15:22

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/2 1:15:20

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…