【问题标题】:How to programmatically get DLL dependencies如何以编程方式获取 DLL 依赖项
【发布时间】:2010-10-01 19:00:07
【问题描述】:

如何获取给定 DLL 或 EXE 文件的所有 DLL 依赖项的列表?

换句话说,我希望以编程方式执行与“Dependency walker”工具相同的操作。

什么是 Windows(最好是 .NET)API?

【问题讨论】:

    标签: dll dependencies


    【解决方案1】:

    如果您不想在程序中加载程序集,可以使用 DnSpy (https://www.nuget.org/packages/dnSpyLibs):

    var assemblyDef = dnlib.DotNet.AssemblyDef.Load("yourDllName.dll");
    var dependencies = assemblyDef.ManifestModule.GetAssemblyRefs();
    

    请注意,您可以在“ManifestModule”属性中找到所需的所有信息。

    【讨论】:

      【解决方案2】:

      您可以使用EnumProcessModules 函数。 kaanbardak 建议的托管 API 不会为您提供原生模块列表。

      例如参见 MSDN 上的this page

      如果您需要静态分析您的 dll,您必须深入了解 PE format 并了解导入表。有关详细信息,请参阅此excellent tutorial

      【讨论】:

      【解决方案3】:

      虽然这个问题已经有一个公认的答案,但其他答案中引用的文档(如果没有损坏)是旧的。我的做法是:

      C:\UnxUtils\usr\local\wbin>strings.exe E:\the-directory-I-wanted-the-info-from\*.dll > E:\TEMP\dll_strings.txt
      

      这让我可以使用 Notepad++ 或 gvim 或其他任何东西来搜索仍然依赖于 dll 名称末尾带有 120.dll 的 MS dll 的 dll,这样我就可以找到需要更新的那些。

      这可以很容易地用您喜欢的语言编写脚本。

      鉴于我搜索此信息时考虑到了 VS 2015,并且此问题是 Google 搜索的最高结果,因此我提供此答案可能对寻找相同信息的其他人有用东西。

      【讨论】:

        【解决方案4】:

        注意:根据下面帖子中的 cmets,我想这也可能会错过非托管依赖项,因为它依赖于反射。

        这是由来自 bytes.com 的 Jon Skeet 在.NET Dependency Walker.NET Dependency Walker 上编写的一个小型 c# 程序

        using System;
        using System.Reflection;
        using System.Collections;
        
        public class DependencyReporter
        {
            static void Main(string[] args)
            {
                //change this line if you only need to run the code one:
                string dllToCheck = @"";
        
                try
                {
                    if (args.Length == 0)
                    {
                        if (!String.IsNullOrEmpty(dllToCheck))
                        {
                            args = new string[] { dllToCheck };
                        }
                        else
                        {
                            Console.WriteLine
                                ("Usage: DependencyReporter <assembly1> [assembly2 ...]");
                        }
                    }
        
                    Hashtable alreadyLoaded = new Hashtable();
                    foreach (string name in args)
                    {
                        Assembly assm = Assembly.LoadFrom(name);
                        DumpAssembly(assm, alreadyLoaded, 0);
                    }
                }
                catch (Exception e)
                {
                    DumpError(e);
                }
        
                Console.WriteLine("\nPress any key to continue...");
                Console.ReadKey();
            }
        
            static void DumpAssembly(Assembly assm, Hashtable alreadyLoaded, int indent)
            {
                Console.Write(new String(' ', indent));
                AssemblyName fqn = assm.GetName();
                if (alreadyLoaded.Contains(fqn.FullName))
                {
                    Console.WriteLine("[{0}:{1}]", fqn.Name, fqn.Version);
                    return;
                }
                alreadyLoaded[fqn.FullName] = fqn.FullName;
                Console.WriteLine(fqn.Name + ":" + fqn.Version);
        
                foreach (AssemblyName name in assm.GetReferencedAssemblies())
                {
                    try
                    {
                        Assembly referenced = Assembly.Load(name);
                        DumpAssembly(referenced, alreadyLoaded, indent + 2);
                    }
                    catch (Exception e)
                    {
                        DumpError(e);
                    }
                }
            }
        
            static void DumpError(Exception e)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Error: {0}", e.Message);
                Console.WriteLine();
                Console.ResetColor();
            }
        }
        

        【讨论】:

        • 此代码不会显示非托管模块。 Mono.Cecil 将是托管代码更好的解决方案,因为它不需要您将程序集加载到 AppDomain 中(并且您以后无法卸载程序集)
        • 添加了额外的 try/catch,如果一个程序集失败,则应列出其他程序集。为异常添加了颜色并输入,因此更易于阅读。当您只想运行 F5 以进行快速概览时添加了一个字符串字段(比将其添加到构建设置更容易)。
        【解决方案5】:

        要读取正在运行的 exe 加载的 DLL(模块),请使用 ToolHelp32 函数 Tool help Documentation on MSDN

        不确定运行 .Net 的 exe 会显示什么(我从未尝试过)。但是,它确实显示了加载 DLL 的完整路径。通常,这是我在尝试解决 DLL 问题时需要的信息。 .Net 应该已经消除了使用这些函数的需要(查找 DLL Hell 以获取更多信息)。

        【讨论】:

          【解决方案6】:

          要获取本地模块依赖关系,我认为从 PE 文件的导入表中获取它应该是可以的,这里有 2 个链接可以深入解释:

          http://msdn.microsoft.com/en-us/magazine/bb985992.aspx

          http://msdn.microsoft.com/en-us/magazine/cc301808.aspx

          要获取 .NET 依赖项,我们可以使用 .NET 的 API,例如 Assembly.Load。

          要获取 .NET 模块的所有依赖项,如何结合这两种方式 - .NET 程序集只是带有元数据的 PE 文件。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-02-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-10-10
            • 1970-01-01
            • 2014-08-05
            • 1970-01-01
            相关资源
            最近更新 更多