enumprocesses仅返回pid列表,需配合openprocess、enumprocessmodulesex(需sedebugprivilege)获取进程名和全模块信息;句柄枚举依赖未公开ntquerysysteminformation;必须管理员权限、正确处理32/64位兼容性及psapi符号动态加载。

用 EnumProcesses 获取所有进程 ID 和基本信息
Windows 提供了 Psapi.dll 中的 EnumProcesses 函数,能一次性拿到当前所有进程的 PID 列表。注意它只返回 PID 数组,不带进程名或路径——想查名字得后续调用 OpenProcess + GetModuleBaseName(需注意权限和 32/64 位兼容性)。
常见坑:EnumProcesses 返回的数组大小单位是 DWORD 个数,不是字节数;缓冲区不够会失败并返回所需大小,必须循环重试或预分配足够空间(比如 1024 个 PID)。另外,某些受保护进程(如 csrss.exe、smss.exe)即使以管理员身份运行,OpenProcess 仍可能返回 ERROR_ACCESS_DENIED,这时跳过即可,别硬卡住。
示例关键步骤:
- 调用
EnumProcesses获取 PID 数组 - 对每个 PID 调用
OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid) - 成功后用
EnumProcessModules+GetModuleBaseName取主模块名 - 记得
CloseHandle每个打开的进程句柄
用 EnumProcessModulesEx 遍历进程加载的所有 DLL
EnumProcessModules 只能枚举默认访问权限下的模块,漏掉很多系统 DLL 或高完整性进程的模块。真正可靠的是 EnumProcessModulesEx,它支持 LIST_MODULES_ALL 标志,能列出 32/64 位混合环境下的全部模块(包括内核模式驱动映射进来的部分)。
使用前提:必须在启用 SeDebugPrivilege 的上下文中运行(否则多数非本进程模块无法枚举),且链接 Psapi.lib 并在 Win7+ 系统上才可用。若目标进程是 WoW64 子系统中的 32 位进程,而你的程序是 64 位,EnumProcessModulesEx 仍可工作,但返回的模块基址是 32 位地址,需用 GetModuleInformation 配合判断大小。
典型错误现象:GetModuleFileNameEx 对某些模块返回空字符串或乱码——这是因为模块已卸载但句柄未失效,或路径被截断。稳妥做法是用 K32GetModuleFileNameEx(来自 Kernel32.dll)替代,并确保缓冲区至少为 MAX_PATH。
通过 SSH 隧道从 Android 设备在互联网上对 Windows PC 实现完整远程控制的设置与使用指南,适用于远程桌面访问、安全 RDP 等。
用 NtQuerySystemInformation 枚举句柄(需要 ntdll.lib)
Windows 没有公开的 API 直接列出某进程所有句柄,唯一可行方案是调用未文档化的 NtQuerySystemInformation,传入 SystemHandleInformation(值为 16)。它返回全局句柄表快照,包含所有进程的句柄信息(PID、句柄值、对象类型、访问掩码等)。
风险点很明确:该函数属于 NT 内部接口,微软不承诺兼容性,Win11 22H2 后部分字段结构微调过;而且返回数据无排序、无索引,需手动遍历过滤出目标进程的句柄。更麻烦的是,你只能拿到句柄的 ObjectTypeNumber,要转成字符串名(如 File、Event、Section)得查 ObTypeIndexTable 或硬编码映射表(常见类型编号可查 WDK 文档或 winnt.h 中的 OBJECT_TYPE_INFORMATION 定义)。
实操建议:
- 用
#pragma comment(lib, "ntdll.lib")链接,声明NtQuerySystemInformation类型 - 首次调用先传 NULL 缓冲区获取所需大小,再分配内存重试
- 逐项检查
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX结构体中的UniqueProcessId - 对感兴趣句柄调用
ZwDuplicateObject复制为可查询句柄,再用GetFinalPathNameByHandle或NtQueryObject查路径或名称
权限、UAC 和 32/64 位交叉问题必须前置处理
没管理员权限,90% 以上跨进程操作都会失败——不是报错,而是静默跳过或返回空结果。必须在 manifest 中声明 requireAdministrator,且程序启动时触发 UAC 提权。仅靠 IsUserAnAdmin() 判断不够,要检查实际 token 是否含 SeDebugPrivilege(用 OpenProcessToken + GetTokenInformation)。
32/64 位混用是另一个高频雷区:64 位进程无法用 OpenProcess 打开 32 位进程的某些句柄(尤其涉及 GUI 对象时),反之亦然。最稳方案是写两个版本程序,或统一用 64 位编译(覆盖绝大多数现代系统),并在代码里用 IsWow64Process 区分对待。
还有个容易被忽略的点:Psapi.dll 在 Windows 10 之后默认不导出 EnumProcessModulesEx 符号,必须用 GetProcAddress 动态获取,否则链接时报错或运行时崩溃。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










