运行时报错找不到 DLL?Dependencies 命令行快速定位依赖链与导入表问题
运行时报错找不到 DLL?Dependencies 命令行快速定位依赖链与导入表问题
【免费下载链接】DependenciesA rewrite of the old legacy software "depends.exe" in C# for Windows devs to troubleshoot dll load dependencies issues.项目地址: https://gitcode.com/gh_mirrors/de/Dependencies
Dependencies 命令行版(Dependencies.exe)是用 C# 重写的 depends.exe 替代品,一条命令导出完整 DLL 依赖链与导入/导出表,支持 JSON 输出,适合排查 Windows 依赖问题、把依赖分析接入 CI 的开发者。
从一个翻车现场说起:程序找不到 DLL
这一节还原最常见的失败现场,说明为什么需要一条命令看清全部依赖。
开发机上跑得好好的程序,一到测试机就崩:The specified module could not be found.顺着错误信息去找那个 DLL——有时它根本不存在,有时它明明在 System32 里躺着,系统却加载了另一个同名文件。靠翻日志猜没有出路,你真正需要三个答案:程序依赖了哪些模块?每个模块按什么顺序、从哪个目录解析到的?断在哪一步?
Dependencies 命令行(下称 CLI)就是干这个的:把 NT Loader(Windows 的可执行文件加载器)的查找过程完整复现并打印出来。
两分钟认识 Dependencies:depends.exe 的 C# 重写版
Dependencies 的定位一句话:老 depends.exe(Dependency Walker)的现代开源重写版,专攻 Windows DLL 加载问题。相比老工具,它跟进现代系统机制——比如 ApiSet 重定向(Windows 8.1 起用一张重定向表把 api-ms-win-*.dll 这类接口集 DLL 指向真实宿主 DLL)——并且能正确处理 x86/x64 混跑环境。
工具分两个可执行文件:Dependencies.exe 是命令行版,给脚本和自动化用;DependenciesGui.exe 是图形界面版,给人交互式排查用。两者共用同一套 PE(Windows 可执行文件格式)解析引擎,核心逻辑在 ClrPhlib/src/unmanaged/UnmanagedPE.cpp。
获取 Dependencies.exe 并跑通第一条命令
这一节解决"怎么拿到能用的工具"。
两种获取方式:
- 源码构建:
git clone https://gitcode.com/gh_mirrors/de/Dependencies,打开 Dependencies.sln 后手动选择 Release 配置和 x64 平台——默认值未必是这两个。 - 下载发布包:从 Releases 页面下载压缩包,解压即用。
⚠️ 两点提示:Dependencies 以 /clr(托管与非托管代码混合编译)方式编译,运行前需安装 Visual C++ Redistributable;二进制未签名,SmartScreen 首次运行弹警告属正常现象。
最简调用格式:
Dependencies.exe [OPTIONS] <FILE>不带参数或加-help会打印完整帮助,文案位于 Dependencies/Program.cs。
按排查场景组织命令:DLL 去哪了、卡在哪个函数
转储参数很多,按参数一个个背没意义——按你遇到的现象分组才好用。下面三个场景覆盖绝大多数排查现场。
场景一:DLL 去哪了——用 -chain 画出完整依赖链
现象:启动失败,错误提示某模块找不到;或发布前想核对全部依赖。
Dependencies.exe -chain MyApp.exe输出:一棵递归展开的树,节点上挂着模块搜索策略——即 NT Loader 查找顺序里哪一步命中的,例如ROOT、ApiSetSchema、WellKnownDlls、System32Folder、Environment、NOT_FOUND,完整枚举在 DependenciesLib/FindPeModule.cs。
该盯的字段:节点上的NOT_FOUND,缺失的模块就是它。树太深时用-depth限制递归深度(默认无限):
Dependencies.exe -chain -depth 2 MyApp.exe补充:-modules输出已解析模块的扁平清单(不带树结构),适合快速核对;-sxsentries列出文件的 SxS(side-by-side)依赖项,解析逻辑见 DependenciesLib/SxsManifest.cs,未找到的依赖会标注???路径。
场景二:卡在哪个函数——用 -imports/-exports 转储导入导出表
现象:DLL 都找到了,但入口崩溃或报"找不到函数";或需要对比两个版本的接口差异。
Dependencies.exe -imports MyApp.exe Dependencies.exe -exports kernel32.dll输出:-imports按模块分组列出全部导入函数,按名字导入与按序数导入(显示为Ordinal_xxx)都覆盖,延迟加载项单独标Delay Import——延迟导入的 DLL 运行时才加载,是常见坑点。-exports列出每个导出的名称、序数、虚拟地址,转发导出会标ForwardedName。
该盯的字段:Delay Import标记和Ordinal_xxx条目。
补充:.NET 程序另有-assemblyrefs(列程序集引用并尝试解析本地版本)和-modulerefs(列模块引用);-manifest转储内嵌 SxS 清单(XML),仓库的回归脚本 test/manifest-regress/Test-ManifestRegress.ps1 就靠它验证清单解析结果。
场景三:系统机制在做什么——-knowndll 与 -apisets
现象:DLL 明明存在,却加载了另一个同名文件;或报错里冒出一堆 api-ms-win-* 接口集 DLL。
-knowndll列出系统 KnownDlls——加载器内置的硬编码白名单,命中它的 DLL 直接从固定目录加载,x86 与 x64 两份都列出来。它能解释"为什么加载了 System32 里那个同名 DLL"。
Dependencies.exe -apisets-apisets转储当前系统的 ApiSet 重定向表(api-ms-win-core-*.dll→ 宿主 DLL)。很多"找不到 api-ms-win-* DLL"的报错,根源就在这张表里。拿到离线样本时用-apisetsdll <FILE>从 apisetschema 文件转储,测试素材可直接用仓库里的 test/apisetschema.v6.dll。
该盯的字段:接口集 DLL 被指向的宿主 DLL 是否存在于目标机器。
把依赖分析搬进 CI:-json 的三个用法
这一节讲怎么让依赖检查在流水线上自动跑。多数命令支持-json,把结果输出为缩进 JSON(序列化逻辑同样在 Dependencies/Program.cs),PowerShell 场景可直接ConvertFrom-Json消费,无需额外依赖。
基线 diff:每次构建导出快照,与基线对比,依赖集悄悄变了立刻发现:
Dependencies.exe -json -chain MyApp.exe > deps.json缺失断言:解析 JSON,只要存在
SearchStrategy: "NOT_FOUND"节点就让流水线失败:Dependencies.exe -json -chain MyApp.exe | ConvertFrom-Json(PowerShell 中递归查找 NOT_FOUND 节点,命中即 exit 1)
产物归档:把快照作为构建产物上传,事后排查有据可查:
Dependencies.exe -json -imports MyApp.exe > imports.json
📌 提醒:
-modules目前不支持 JSON 输出,源码会直接提示 "Json output is not currently supported",自动化脚本请改用-chain或-imports。
仓库的 CI 配置 appveyor.yml 展示了 x86/x64 双平台构建流程,可作为自建流水线的基础模板。
Dependencies 命令行参数速查
这张表覆盖全部参数,重点看两列:是否需要 、是否支持 -json。
| 参数 | 需要 | 支持 -json | 一句话说明 |
|---|---|---|---|
-chain | 是 | 支持 | 递归转储完整依赖链 |
-modules | 是 | 不支持 | 已解析模块的扁平清单 |
-imports | 是 | 支持 | 导入表,含延迟加载标记 |
-exports | 是 | 支持 | 导出表,含转发导出 |
-assemblyrefs | 是 | 支持 | .NET 程序集引用 |
-modulerefs | 是 | 支持 | 模块引用 |
-manifest | 是 | 支持 | 内嵌 SxS 清单 |
-sxsentries | 是 | 支持 | SxS 依赖项 |
-apisetsdll | 是 | 支持 | 从 apisetschema 文件转储 ApiSet 表 |
-knowndll | 否 | 支持 | 系统 KnownDlls 白名单 |
-apisets | 否 | 支持 | 系统 ApiSet 重定向表 |
-depth N | 配合 -chain | — | 限制依赖链递归深度 |
-cache | — | — | 读取时复制文件,防止 DLL 被锁定 |
-help | 否 | — | 打印完整帮助 |
表外再点一次名:-modules是唯一不支持-json的转储类参数,需要结构化数据就用-chain替代。
常见坑清单
部署和自动化时最容易栽的几件事,集中列在这:
⚠️
- /clr 编译,运行 Dependencies 前必须先装 Visual C++ Redistributable
- 二进制未签名,SmartScreen 警告属正常现象
-modules不支持-json,CI 场景改用-chain- 源码构建需手动选 Release + x64,默认配置和平台未必对
-cache会把读取的文件复制一份,磁盘空间紧张时留意
如果你维护 Windows 桌面应用或原生工具,希望"依赖悄悄变了"这件事在上线前被脚本发现、而不是被用户发现,Dependencies 命令行值得放进工具箱。
【免费下载链接】DependenciesA rewrite of the old legacy software "depends.exe" in C# for Windows devs to troubleshoot dll load dependencies issues.项目地址: https://gitcode.com/gh_mirrors/de/Dependencies
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考