C# 动态加载卸载 DLL

本文介绍了如何在C#中通过创建新的AppDomain来动态加载DLL,并在使用完毕后卸载。使用Assembly.Load无法卸载DLL,但通过AppDomain.CreateDomain创建的独立域可以实现DLL的加载与卸载。文中详细展示了创建AppDomain、加载DLL到新域、执行操作以及卸载AppDomain的步骤,确保了程序的内存管理效率。

我最近做的软件,需要检测dllexe是否混淆,需要反射获得类名,这时发现,C#可以加载DLL,但不能卸载DLL。于是在网上找到一个方法,可以动态加载DLL,不使用时可以卸载。

我在写一个WPF 程序,发现可以通过 Assembly.Load 加载 DLL,但是如何卸载DLL?下面就来说下如何卸载。

看到 Assembly.Load 是把 DLL 加载到当前程序集,这句话,我就想到了我们的主程序集和当前的不同,那么可以加载到当前不会影响主程序。那么如何新建一个程序集?他是否可以卸载,答案是可以的。

首先,我们可以通过var appDomain = AppDomain.CreateDomain(appDomainName);创建AppDomain 。他是可以卸载,卸载 AppDomain 使用 AppDomain.Unload ,就可以把加载在 AppDomainDLL 卸载。

于是我们需要把 DLL 加载在 AppDomain ,这样之后可以卸载 AppDomain 动态删掉 加载的DLL

如果要把 DLL 加载在 AppDomain 需要先写一个类,继承MarshalByRefObject

    internal class ApplicationProxy : MarshalByRefObject
    {
        public void DoSomething()
        {
            
        }
    }
    var proxy = appDomain.CreateInstanceAndUnwrap(Assembly.GetAssembly(typeof(ApplicationProxy)).FullName,
                typeof(ApplicationProxy).ToString()) as ApplicationProxy;

我们可以在 DoSomething 函数加载 DLL ,加载的 DLLAppDomain ,不在主程序,所以卸载 AppDomain 可以卸载 DLL

假如是从 文件加载,可以使用 LoadFile

 var assembly  = Assembly.LoadFile(file.FullName);

assembly 可以获得所有的类和方法。

然后需要卸载时,可以使用 AppDomain.Unload(appDomain);

建议写var assembly = Assembly.LoadFile(file.FullName);
try,写 AppDomain.Unload(appDomain);
finally上面的 appDomainName 是我自己给他的。

http://stackoverflow.com/questions/2132649/loading-unloading-assembly-in-different-appdomain

我们可以验证,如果不使用新建一个 AppDomain 加载的 DLL 会在主程序集,如果使用了,就会在我们新建的 AppDomain

首先我们使用 Assembly.LoadFile(file) 加载,再用反射获得当前程序集,然后获取他的所有 type ,当然我们是知道加载的 File 包含的type,一会可以验证使用已经加载他。

System.Reflection.Assembly.LoadFile(file);
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
    //查看type               
}

可以看到 file 包含的 type 在主程序。

我们使用新建 appDomain

const string appDomainName = "ConfuseChecker";
var appDomain = AppDomain.CreateDomain(appDomainName);
var proxy = appDomain.CreateInstanceAndUnwrap(Assembly.GetAssembly(typeof(ApplicationProxy)).FullName,
            typeof(ApplicationProxy).ToString()) as ApplicationProxy;
proxy.DoSomething(new FileInfo(file));
AppDomain.Unload(appDomain);

这时可以看到,我们的主程序没有包含 filetype

<think>好的,我现在需要回答用户关于动态加载卸载DLL文件的方法及实现步骤的问题。首先,我需要回顾一下自己对这个主题的了解,并参考用户提供的引用内容,确保回答准确。 动态加载DLL通常涉及在运行时根据需要加载库,而不是在编译时静态链接。这可以通过不同的编程语言和API实现。用户提供的引用中提到了C#和Unity中的方法,还有使用Windows API进行远程线程注入和卸载的例子。我需要将这些信息整合起来,分步骤说明。 首先,动态加载DLL的方法。在C#中,可以使用Assembly.LoadFrom(),如引用[2]提到的。而在更底层的Windows API中,可能需要使用LoadLibrary函数。Unity中创建DLL加载的步骤在引用[1]中有说明,比如生成DLL后放在Plugins文件夹。此外,引用[4]提到使用CreateRemoteThread和LoadLibrary进行远程注入,这也属于动态加载的一种方式。 接下来是卸载DLL。在C#中,直接卸载程序集可能比较复杂,因为AppDomain的管理。引用[2]和[3]提到了使用FreeLibrary和CreateRemoteThread来卸载DLL,特别是在远程进程中的情况。需要注意卸载DLL的风险,比如资源未正确释放导致的问题。 然后,我需要组织步骤,分加载卸载两部分。每个步骤需要具体说明,并指出注意事项,比如平台依赖、权限问题等。同时,要确保提到不同方法的适用场景,比如在Unity中的处理与普通C#程序的区别,或者远程注入的特殊情况。 可能还需要补充一些用户未提到的点,比如使用P/Invoke在C#中调用LoadLibrary和FreeLibrary,或者使用AppDomain来加载卸载程序集,尽管AppDomain在.NET Core中的支持有限。此外,要强调正确卸载的重要性,避免内存泄漏或程序崩溃。 最后,生成相关问题时要考虑用户可能进一步想知道的内容,比如具体API的使用示例、不同方法的优缺点、常见错误处理等。</think>### 动态加载卸载DLL的方法及实现步骤 #### 一、动态加载DLL的方法 1. **使用C#的`Assembly.LoadFrom()`方法** 在已知DLL文件路径时,可直接加载程序集: ```csharp Assembly sampleDll = Assembly.LoadFrom("C:\\Sample.dll"); ``` 此方法适用于需要直接调用DLL中的类或函数的情况[^2]。 2. **通过Windows API `LoadLibrary()`** 在C/C++或C#(通过P/Invoke)中调用系统API动态加载: ```csharp [DllImport("kernel32.dll")] public static extern IntPtr LoadLibrary(string dllPath); IntPtr dllHandle = LoadLibrary("Sample.dll"); ``` 需注意路径问题和依赖库的加载顺序。 3. **Unity中加载DLL的特殊处理** - 将编译好的DLL文件放置在Unity项目的`Assets/Plugins`目录下。 - 通过`DllImport`特性调用DLL中的函数: ```csharp [DllImport("SampleDll")] public static extern int Add(int a, int b); ``` 需确保DLL的平台兼容性(如x86/x64)[^1]。 4. **远程线程注入加载** 通过`CreateRemoteThread`在目标进程中调用`LoadLibrary`: - 获取目标进程句柄(`OpenProcess`)。 - 在目标进程中分配内存写入DLL路径(`VirtualAllocEx` + `WriteProcessMemory`)。 - 创建远程线程执行`LoadLibrary`加载DLL[^4]。 #### 二、动态卸载DLL的方法 1. **使用Windows API `FreeLibrary()`** 配合`LoadLibrary`返回的句柄卸载: ```csharp [DllImport("kernel32.dll")] public static extern bool FreeLibrary(IntPtr hModule); FreeLibrary(dllHandle); // 传入LoadLibrary返回的句柄 ``` 2. **远程线程卸载DLL** 类似注入过程,但调用`FreeLibrary`: - 获取目标进程中已加载DLL的句柄。 - 通过`CreateRemoteThread`创建线程执行`FreeLibrary`[^3]。 3. **C#中通过AppDomain卸载** (仅限.NET Framework,.NET Core不支持): ```csharp AppDomain newDomain = AppDomain.CreateDomain("TempDomain"); newDomain.Load("Sample.dll"); AppDomain.Unload(newDomain); // 卸载整个域内的所有程序集 ``` 此方法会卸载整个应用程序域,可能影响其他资源。 #### 三、关键注意事项 1. **依赖关系** 动态加载DLL需满足依赖链完整,否则会触发`DllNotFoundException`。 2. **线程安全** 卸载DLL时需确保无代码正在执行其函数,否则可能导致崩溃。 3. **跨平台差异** Windows使用`LoadLibrary`/`FreeLibrary`,Linux需通过`dlopen`/`dlclose`实现类似功能。 4. **资源释放** 若DLL内部申请了内存或句柄,需在卸载前显式释放,避免资源泄漏。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值