运行时报错找不到 DLL?Dependencies 命令行快速定位依赖链与导入表问题

发布时间:2026/11/4 2:00:58
运行时报错找不到 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 并跑通第一条命令

这一节解决"怎么拿到能用的工具"。

两种获取方式:

  1. 源码构建:git clone https://gitcode.com/gh_mirrors/de/Dependencies,打开 Dependencies.sln 后手动选择 Release 配置和 x64 平台——默认值未必是这两个。
  2. 下载发布包:从 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消费,无需额外依赖。

  1. 基线 diff:每次构建导出快照,与基线对比,依赖集悄悄变了立刻发现:

    Dependencies.exe -json -chain MyApp.exe > deps.json

  2. 缺失断言:解析 JSON,只要存在SearchStrategy: "NOT_FOUND"节点就让流水线失败:

    Dependencies.exe -json -chain MyApp.exe | ConvertFrom-Json

    (PowerShell 中递归查找 NOT_FOUND 节点,命中即 exit 1)

  3. 产物归档:把快照作为构建产物上传,事后排查有据可查:

    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),仅供参考