卸载使用DllImport加载的DLL

sub*_*bbu 31 c# dllimport

如何卸载已DllImport在C#中加载的DLL ?

Mit*_*eat 23

从[DllImport] pinvoke声明加载的进程中卸载非托管DLL的最可靠方法是通过pinvoking LoadLibrary()再次自己加载它.这为DLL提供了可靠的DLL处理,即使DLL的模块名称不明确,也能正常工作.它在运行时没有任何影响,除了Windows加载器将DLL的内部引用计数从1增加到2.

然后,您可以将FreeLibrary()两次旋转以将引用计数减少为0,并将其从LoadLibrary()传递给IntPtr.卸载DLL,以及任何加载的依赖DLL.

要注意的是,当你尝试的PInvoke你会得到非常讨厌失败的任何再次对DLL导出功能,任何这样做之后的时间.pinvoke marshaller不知道DLL不再存在,并且会在它认为仍然有效的地址处调用该函数.如果幸运的话,哪些程序会使用AccessViolation异常对您的程序进行轰炸.或者运行一个完全随机的代码,如果你不是那么幸运,以前DLL占用的地址空间被另一个DLL重用.任何事情都可能发生,没有一件好事.

  • 你仍然没有回答subbu的问题.他问的是如何卸载由DllImport加载的DLL,而不是通过LoadLibrary()手动加载它. (4认同)
  • @Ants,这将卸载 DllImport 加载的 DLL。Mitch 通过尝试加载(已经加载的)DLL 来获取 DLL 句柄。然后您调用 FreeLibrary() 两次以删除您刚刚添加的(否则无用的)引用和 DllImport 具有的引用。 (2认同)

Ill*_*ack 10

这应该释放先前在您调用P/Invoke函数时加载的模块.

[DllImport("kernel32", SetLastError=true)]
static extern bool FreeLibrary(IntPtr hModule);

public static void UnloadModule(string moduleName)
{
    foreach(ProcessModule mod in Process.GetCurrentProcess().Modules)
    {
        if(mod.ModuleName == moduleName)
        {
            FreeLibrary(mod.BaseAddress);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这通常*会起作用.但模块名称可能不明确,它可能会释放错误的DLL. (3认同)

ste*_*and 6

根据彼得斯的推荐,这对我有用:

    [DllImport("kernel32", SetLastError = true)]
    private static extern bool FreeLibrary(IntPtr hModule);

    public static void UnloadImportedDll(string DllPath)
    {
        foreach (System.Diagnostics.ProcessModule mod in System.Diagnostics.Process.GetCurrentProcess().Modules)
        {
            if (mod.FileName == DllPath)
            {
                FreeLibrary(mod.BaseAddress);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)