如何检查 DLL 依赖关系?
Posted
技术标签:
【中文标题】如何检查 DLL 依赖关系?【英文标题】:How to check for DLL dependency? 【发布时间】:2011-11-14 18:58:19 【问题描述】:有时我在做一个小项目时不够小心,不小心添加了一个我不知道的 DLL 依赖项。当我将此程序发送给朋友或其他人时,“它不起作用”,因为缺少“某些 DLL”。这当然是因为程序可以在我的系统上找到 DLL,但在他们的系统上找不到。
有没有办法扫描可执行文件的 DLL 依赖项或在“干净的”无 DLL 环境中执行程序以进行测试以防止这些糟糕情况?
【问题讨论】:
调试器显示在输出窗口中加载的每个 DLL。 Debug + Windows + Modules 显示了它们的列表。确保你能解释所有这些。并像测试代码一样测试安装程序,使用虚拟机。 @Hans Passant:我可以在某处找到标准 Windows DLL 的完整列表吗? 是的,在 c:\windows\system32 中,拥有 Microsoft 版权。 @orlp - 你也可以试试dumpbin /dependents <program>
。我猜该列表将比在%SYSTEM%
或%SYSTEM32%
中列出所有DLL 更相关。另请参阅 MSDN 上的 DUMPBIN Options。
【参考方案1】:
来自 Visual Studio 工具(VC\bin 文件夹)的dumpbin
可以在这里提供帮助:
dumpbin /dependents your_dll_file.dll
【讨论】:
方便的小工具,当您已经安装了 VS 时,无需安装任何新的东西。 是的,dumpbin.exe
对于找出/dependents
和/imports
非常有用。如果您将link.exe
连同它一起复制并确保相应的x86 Visual C++ Runtime Redistributable (msvcr120.dll
for Visual Studio 2013)在目标机器上可用,您也可以在其他机器上使用它。一些选项有额外的依赖关系。 - 顺便说一句,他们搞砸了选项名称,应该是/PREREQUISITES
而不是/DEPENDENTS
,他们应该学过拉丁文。
太棒了,我们在生成最终可执行文件时将其添加到构建系统中作为验证步骤,这样我们就不会依赖发货中未包含的内容。
唯一的缺点是这个方便的工具非常隐蔽:c:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.14.26428\bin\Hostx64\ x64>垃圾箱
@rkachach 如果您打开 Visual Studio 命令行(工具 -> Visual Studio 命令提示符),这将被识别为外部命令,您只需键入“dumpbin”。【参考方案2】:
试试Dependencies(2019 年 12 月),它是对著名的 Dependency Walker 的现代重写(2006 年最后一次更新)
【讨论】:
如果可能,我将只信任原始操作系统提供商,因为 ddl 依赖项应该是操作系统工作。是否有任何 Microsoft 实用程序可以做到这一点?命令行对我来说很好。 @RobinHsu:在 Visual Studio 2005 之前,DependencyWalker 一直随 Visual Studio 一起发布。最新版本包含在 Windows Driver Development Kit 中(不能通过官方网站获得)。仍然不是正式的 Microsoft 工具,但得到了 Microsoft 的认可、推广和宣传。dumpbin
依赖walker。 msdn.microsoft.com/en-us/library/756as972.aspx | ***.com/a/28304716/3543437
现在有部分在 C# 中完成的开源重写,见“Dependencies.exe”:github.com/lucasg/Dependencies。测试印象:有点 beta-ish,但它显然可以处理 API-sets 和 SxS(从 Dependency Walker 中缺失)。
此外,您始终可以使用来自 Sysinternals 的procmon.exe 来调试高级依赖问题(和其他问题)。 See this answer for how to set an include filter for procmon.exe 所以输出是“可消化的”(在这种情况下用于调试 regsvr32.exe 事件)。【参考方案3】:
我可以为 Linux 爱好者推荐有趣的解决方案。在我探索了这个解决方案之后,我已经从 DependencyWalker 切换到了这个。
您可以使用您最喜欢的ldd
而不是与Windows 相关的exe
、dll
。
为此,您需要在 Windows 上安装 Cygwin(基本安装,无需额外的软件包),然后启动 Cygwin Terminal
。现在您可以运行您喜欢的 Linux 命令,包括:
$ ldd your_dll_file.dll
UPD:您也可以通过git bash terminal on Windows 使用ldd
。如果您已经安装了 git,则无需安装 cygwin。
【讨论】:
我刚刚安装了 cygwin,很高兴找到了 linux 命令,但是我无法退出 Cygwin 根目录来访问本地驱动器 (C:) 上的其他文件。这正常吗? 我认为这可以帮助你:***.com/questions/1850920/… 不幸的是,有些依赖项没有通过这种方式找到:$ ldd ./Debug/helloworld.exe ??? => ??? (0x77d60000)
。实用程序 dumpbin 正确显示所有依赖项。
我通过 Windows 上的 GIT BASH 终端使用 ldd 并且工作正常。所以如果你有 git 会很容易,不需要安装 cygwin。示例:borkox@bobipc MINGW64 ~ $ ldd /c/Users/borkox/.javacpp/cache/openblas-0.3.0-1.4.2-windows-x86_64.jar/org/bytedeco/javacpp/windows-x86_64/jniopenblas_nolapack.dll ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7ffe46910000) KERNEL32.DLL => /c/WINDOWS/System32/KERNEL32.DLL (0x7ffe46610000) KERNELBASE.dll => /c/WINDOWS/System32/KERNELBASE。 dll (0x7ffe42d40000) msvcrt.dll => /c/WINDOWS/System32/msvcrt.dll (0x7ffe44120000)
作为已经安装了 git bash 的人,这是一个更可取的解决方案。谢谢!【参考方案4】:
找出您尝试使用的程序集的完整文件路径
按下开始按钮,输入“dev”。启动名为“VS 2017 的开发人员命令提示符”的程序
在打开的窗口中,输入dumpbin /dependents [path]
,其中[path]
是您在步骤1 中计算出的路径
按回车键
Bam,你已经得到了你的依赖信息。窗口应如下所示:
VS 2019 更新:您需要在 VS 安装中使用此软件包:
【讨论】:
"Bam" 你想要的,但我觉得dumpbin
没那么有用,因为它不是递归的。如果任何 DLL 依赖项又依赖于一个不在直接依赖项列表中的 DLL,那么您仍然会被搞砸。最好使用不是半途而废的工具,例如ldd
。【参考方案5】:
-
有一个名为“Depends”的程序
如果你安装了 cygwin,没有比 ldd file.exe 更简单的了
【讨论】:
该工具名为Dependency Walker;它的可执行映像被命名为 depends.exe. Dependency Walker 已过时。它的最后一次建造是在 2008 年!depends
不支持 API 集,因此对 Win7+ 无用。【参考方案6】:
最安全的做法是拥有一些干净的虚拟机,您可以在上面测试您的程序。在您要测试的每个版本上,将 VM 恢复到其初始干净值。然后使用它的设置安装你的程序,看看它是否有效。
DLL 问题有不同的面貌。如果您使用 Visual Studio 并动态链接到 CRT,则必须分发 CRT DLL。更新你的 VS,你必须分发另一个版本的 CRT。仅检查依赖项是不够的,因为您可能会错过这些。在干净的机器上进行完整安装是唯一安全的解决方案,IMO。
如果您不想设置完整的测试环境并使用 Windows 7,则可以使用 XP-Mode 作为初始清理机器,并使用XP-More 复制 VM。
【讨论】:
【参考方案7】:在您的开发机器上,您可以执行程序并运行Sysinternals Process Explorer。在下部窗格中,它将向您显示加载的 DLL 以及它们的当前路径,这出于多种原因很方便。如果您正在执行部署包,它将显示在错误路径中引用了哪些 DLL(即未正确打包)。
目前,我们公司使用 Visual Studio Installer 项目来遍历依赖树,并将程序作为松散文件输出。在 VS2013 中,这现在是一个扩展名:https://visualstudiogallery.msdn.microsoft.com/9abe329c-9bba-44a1-be59-0fbf6151054d。然后,我们将这些松散的文件打包到一个更全面的安装程序中,但至少该安装程序项目所有 dot net 依赖项并将它们放到一个位置,并在丢失时警告您。
【讨论】:
【参考方案8】:Jesse 已经提到过 NDepend(如果您分析 .NET 代码),但让我们准确解释一下它如何提供帮助。
是否有可以扫描可执行文件以查找 DLL 的程序/脚本 依赖项或在“干净”的无 DLL 环境中执行程序 进行测试以防止出现这些 oops 情况?
在 NDepend 项目属性面板中,您可以定义要分析的应用程序集(绿色),NDepend 将推断应用程序使用的第三方程序集(蓝色)。提供了搜索应用程序和第三方程序集的目录列表。
如果在这些目录中找不到第三方程序集,它将处于错误模式。比如我删除.NET Fx目录C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319
,可以看到.NET Fx第三方程序集没有解析:
免责声明:我为 NDepend 工作
【讨论】:
【参考方案9】:在过去(即 WinXP 时代),我曾经依赖/依赖 DLL Dependency Walker (depends.exe),但有时我仍然无法确定 DLL 问题。理想情况下,我们希望在运行前通过检查找出问题,但如果这不能解决问题(或花费太多时间),您可以尝试启用“加载器快照”,如 http://blogs.msdn.com/b/junfeng/archive/2006/11/20/debugging-loadlibrary-failures.aspx 和 https://msdn.microsoft.com/en-us/library/windows/hardware/ff556886(v=vs.85).aspx 中所述并简要提及LoadLibrary fails; GetLastError no help
警告:我过去弄乱了我的 Windows,用 gflag 让它爬到了膝盖上,你已经被预先警告了。
注意:“加载程序快照”是每个进程的,因此 UI 启用不会保持选中状态(使用 cdb 或 glfags -i)
【讨论】:
【参考方案10】:请从以下链接参考 Microsoft 的 SysInternal 工具包, https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer
转到下载文件夹,以管理员权限打开“Procexp64.exe”。 打开查找菜单->“查找句柄或DLL”选项或Ctrl+F快捷键方式。
【讨论】:
【参考方案11】:I wrote a modern C++
command line utility 用于查找递归 DLL
依赖项。它易于使用并输出JSON
,其中包含有关引用的DLL
s、DLL
加载失败和缺少DLL
s 的有价值信息。
【讨论】:
【参考方案12】:请在谷歌中搜索“depends.exe”,这是一个处理这个问题的小工具。
【讨论】:
请注意,dependency walker 已经过时了,并且不能很好地与 64 位配合使用。它将明确显示所有相关的 DLL,这是 OP 正在寻找的,但它也增加了噪音 - 你会发现你是 32 位可执行文件缺少一些 64 位 dll 等等......遗憾的是,仍然没有更好的替代品。 @RestlessC0bra 我不知道,但过去 5 年我一直没有从事 Windows 开发。 Dependency walker 肯定已经死了,很遗憾微软既没有费心更新这个有用的工具,也没有开放它的源代码以便其他人可以让它继续存在。 @RestlessC0bra:Dependency Walker 死了。它从未赶上 64 位模块。如果您仔细观察,大量使用 Dependency Walker 会导致 Stack Overflow 问题,询问为什么会发生某些事情。不过,这件事永远不会发生。这只是一个假阴性/阳性。 Process Monitor 应该是您的首选工具。 "dumpbin" 应该是首选工具。它是一个命令行工具。好处是它甚至可以编写脚本并包含在您的构建过程和预发布验证步骤中。已经从一些错误中拯救了我们。【参考方案13】:如果你有源代码,可以使用ndepend。
http://www.ndepend.com/
它很昂贵,而且比分析依赖关系要多得多,所以它可能对你正在寻找的东西来说有点过头了。
【讨论】:
作为专门为 .NET 量身定制的工具,它是否也分析了原生镜像的依赖关系? 可能不是,@IInspectable。我认为 .NET 没有办法做到这一点,除非可能使用 P-Invoke。 @kayleeFrye_onDeck:解析导入表归结为读取文件。 .NET 可以读取文件。 是的!然而,没有 .NET API 可以做到这一点 :( 你有什么建议?我不是一个真正的 .NET 程序员,只是在较低级别的解决方案不成功时使用它的人。有很多检查工具可供选择在那里,但很少有 Windows 是分布式友好的,更不用说快速了......我希望用它来递归检查未知数量的二进制文件以检测编译时使用的框架,所以我可以用特殊的参数处理它们 ad- hoc. 我可能不得不考虑使用LoadLibraryEx
...
@kayleeFrye_onDeck:Windows API 中也没有读取模块导入表的内容。您必须读取文件并解析内容。本机代码和 .NET 之间没有区别。 LoadLibraryEx
无济于事。【参考方案14】:
pedeps 项目 (https://github.com/brechtsanders/pedeps) 有一个命令行工具 (copypedeps),用于复制您的 .exe(或 .dll)文件及其依赖的所有文件。 如果您在应用程序工作的系统上执行此操作,您应该能够将其与所有依赖 DLL 一起发布。
【讨论】:
【参考方案15】:如果你的 dll 是基于 .net 的,你可以试试JetBrains dotPeek。它是免费的。
【讨论】:
以上是关于如何检查 DLL 依赖关系?的主要内容,如果未能解决你的问题,请参考以下文章
Microsoft Visual C++ - 编译一个没有依赖关系的单个 DLL