dll文件的加载

少于 1 分钟读完

程序的运行要去加载所需要的dll文件,在程序运行的时候往往会遇到dll找不到的问题,或者不能确定所加载的dll文件是否是自己所需要的dll,遇到dll出问题的时候往往会不知所措,但是一旦知道了dll的加载顺序,按这个去查找解决就会方便和得心应手了。

(1)先搜索可执行文件所在路径,再搜索系统路径:%PATH%(环境变量所配置的路径)

一般Path中的值为:%SystemRoot%\system32;%SystemRoot%;

(2)然后按下列顺序搜索 DLL:

1、当前进程的可执行模块所在的目录。

2、当前目录。

3、Windows 系统目录。GetSystemDirectory 函数检索此目录的路径。

4、Windows 目录。GetWindowsDirectory 函数检索此目录的路径。

5、PATH 环境变量中列出的目录。

有时候确定了加载的dll文件确实是自己所想加载的dll文件,但是还会发生错误的可能原因,就是dll文件被损坏,此时需要重新替换现有的dll文件;或者dll文件和所用的头文件(.h文件)不匹配,即是头文件中的函数,在dll文件中没有实现,这样的话,找到对应的dll文件就ok了。

AssemblyLoadContext

基本上AssemblyLoadContext是AppDomain的继承者,它提供相同而且更多的功能-除了安全边界(隔离)。最小的安全边界是进程,因此你将需要使用进程间通信来正确隔离数据和代码执行。

官网文档中提到Appdomain已经过时了,为了兼容旧的版本,提供了部分功能。建议在.NET Core3.0及更高的版本使用AssemblyLoadContext。

从AppDomain迁移到AssemblyLoadContext

也许你仍在应用程序中使用AppDomain。现在,以下代码显示如何用AssemblyLoadContext的相应方法去替换掉AppDomain方法:

  • 获取所有程序集
var assembliesInAppDomain = AppDomain.CurrentDomain.GetAssemblies();
var assembliesInAssemblyLoadContext = AssemblyLoadContext.Default.Assemblies;
  • 加载一个程序集
AppDomain.CurrentDomain.Load(AssemblyName.GetAssemblyName("path"));
AssemblyLoadContext.Default.LoadFromAssemblyName(AssemblyName.GetAssemblyName("path"));
  • 加载一个程序集 路径或者字节数组:
AppDomain.CurrentDomain.Load(File.ReadAllBytes("path"));
AssemblyLoadContext.Default.LoadFromStream(File.OpenRead("path"));// orAssemblyLoadContext.Default.LoadFromAssemblyPath("path");
  • 测试封装的获取程序集方法GetAssemblies

准备工作:

  1. 创建一个控制台程序
  2. 添加一个类库项目,命名为AA.Service

在控制台应用程序,添加一个类TypeFinder代码如下:

public class TypeFinder
    {
        /// <summary>
        /// 获取物理路径 
        /// </summary>
        /// <returns>\bin\Debug\netcoreapp3.0</returns>
        public virtual string GetBinDirectory()
        {
            return AppContext.BaseDirectory;
        }
        /// <summary>
        /// 获取程序集
        /// </summary>
        /// <returns></returns>
        public IList<Assembly> GetAssemblies()
        {
            var binPath = GetBinDirectory();
            var addedAssemblyNames = new List<string>();
            var assemblies = new List<Assembly>();

            //
            foreach (var assembly in AssemblyLoadContext.Default.Assemblies.Where(a=>IsNotSysAssembly(a.FullName)))
            {
                if (addedAssemblyNames.Contains(assembly.FullName))
                    continue;
                addedAssemblyNames.Add(assembly.FullName);
            }

            foreach (var dllPath in Directory.GetFiles(binPath, "*.dll",
                 SearchOption.TopDirectoryOnly))
            {
                try
                {
                    var an = AssemblyName.GetAssemblyName(dllPath);
                    if (!addedAssemblyNames.Contains(an.FullName))
                    {
                        AssemblyLoadContext.Default.LoadFromAssemblyName(an);
                    }
                }
                catch (BadImageFormatException ex)
                {
                    Trace.TraceError(ex.ToString());
                }
            }

            foreach (var assembly in AssemblyLoadContext.Default.Assemblies.Where(a => IsNotSysAssembly(a.FullName)))
            {
                if (addedAssemblyNames.Contains(assembly.FullName))
                    continue;

                assemblies.Add(assembly);
            }
            return assemblies;
        }

        /// <summary>
        /// 排除系统程序集
        /// </summary>
        /// <param name="assemblyName"></param>
        /// <returns></returns>
        private bool IsNotSysAssembly(string assemblyName) 
        {
            return !assemblyName.StartsWith("Microsoft.")
                      && !assemblyName.StartsWith("System.")
                      && !assemblyName.StartsWith("Newtonsoft.")
                      && assemblyName != "netstandard";
        }
    }

在控制台应用程序添加引用AA.Service类库,生成查看bin文件,出现了AA.Service.dll

img

调用代码输出(排除系统dll以Microsoft、system开头的)程序集:

var assemblies= new TypeFinder().GetAssemblies();        
foreach (var a in assemblies)             
{                
Console.WriteLine(a.FullName);            
}

输出

img

分类:

更新时间:

留下评论