EnumProcessModules是Windows下获取当前进程模块列表最直接可靠的方式,需用GetCurrentProcess()、动态分配缓冲区并链接psapi.lib;Linux用/proc/self/maps解析,macOS用_dyld_image_count();均无法获取延迟加载模块和调试符号文件。

Windows 下用 EnumProcessModules 获取当前进程模块列表
在 Windows 平台,EnumProcessModules 是最直接、可靠的方式获取当前进程已加载的 DLL(以及 EXE 本身)模块句柄。它返回的是 HMODULE 列表,配合 GetModuleFileNameEx 或 GetModuleBaseName 可拿到路径或文件名。
常见错误是传入错误的进程句柄——必须用 GetCurrentProcess(),不能用 OpenProcess 打开自己(权限冗余且可能失败);另一个坑是缓冲区大小估算:模块数量动态变化,首次调用应先用 0 长度缓冲触发 ERROR_INSUFFICIENT_BUFFER,再分配足够空间。
- 需链接
psapi.lib(VS 中项目属性 → 链接器 → 输入 → 附加依赖项) - Win10 1703+ 推荐用
EnumProcessModulesEx,支持过滤(如只取 32/64 位模块或仅用户模式模块) -
GetModuleFileNameEx在低权限进程(如被提权保护的浏览器渲染进程)中可能失败,此时可降级用GetMappedFileName+QueryFullProcessImageName
Linux/macOS 下读取 /proc/self/maps 解析映射段
类 Unix 系统没有“模块枚举”系统调用,标准做法是解析 /proc/self/maps —— 它列出当前进程所有内存映射区域,其中以磁盘路径结尾的行即为加载的共享库(.so)和可执行文件。
注意:该文件每行格式固定但字段间空格不等宽,不能简单 std::getline + std::string::find 拆分;更稳的方式是用 sscanf 匹配前 5 字段(地址范围、权限、偏移、设备号、inode),剩余部分作为路径;路径可能为空(匿名映射)或带 [stack]、[vdso] 等伪名称,需跳过。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 路径字段可能含空格(如
/usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.30),务必从第 6 字段起取整个剩余字符串 - 同一库可能因不同
mmap标志出现多次(如 r-x 和 rw- 分开),按 inode + 路径去重 - macOS 不提供
/proc,得用_dyld_image_count()+_dyld_get_image_name(i)(需包含<dlfcn.h>)
跨平台封装时别绕过 GetModuleHandle(nullptr) 的陷阱
有人想用 GetModuleHandle(nullptr) 拿到主模块句柄,再反复调用 EnumDependentModules(不存在!)递归查依赖——这是典型误解。GetModuleHandle 只返回已加载模块的句柄,不提供依赖关系图;Windows 本身也不维护运行时模块依赖链表。
若真需要完整依赖树(比如做热更新或符号解析),必须走静态分析:dumpbin /dependents(Windows)、readelf -d 或 objdump -p(Linux)、otool -L(macOS)预处理二进制,或在加载时钩住 LoadLibrary/dlopen 记录调用栈。
-
GetModuleHandle(nullptr)返回的是主模块(EXE)句柄,不是“所有模块”的代理 - 模块卸载后句柄失效,
EnumProcessModules结果是快照,不保证实时性 - C++ 无标准 ABI 级模块枚举接口,所有方案都依赖平台 API 或 procfs/dyld,无法纯标准库实现
调试符号与延迟加载模块容易被漏掉
用 EnumProcessModules 或 /proc/self/maps 都能捕获到“已映射”的模块,但两类情况常被忽略:一是仅带 PDB/DSYM 但未实际加载的调试模块(它们不占内存页);二是启用延迟加载(/DELAYLOAD)的 DLL,在首次调用其函数前不会出现在模块列表中。
前者根本不可见——调试信息是独立文件,不在进程地址空间;后者需额外监控 __delayLoadHelper2 或使用 ETW/Event Tracing(Windows)或 LD_DEBUG=libs(Linux)观察运行时加载事件。
- 延迟加载模块首次触发时,会调用系统 loader,此时才真正进入
EnumProcessModules结果 - 用
GetModuleHandle查某个延迟 DLL 在调用前会返回nullptr,这是正常行为,不代表未声明依赖 - 符号服务器(如 Microsoft Symbol Server)下载的 PDB 不改变模块枚举结果,仅影响调试器解析
实际写的时候,模块列表只是起点——路径是否可读、是否被 ASLR 重定位、有无调试信息、是否由 dlmopen 隔离(Linux)……这些细节比“怎么列出来”更影响后续操作。

















