卸载使用DllImport加载的DLL

问题描述 投票:28回答:6

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

c# dllimport
6个回答
22
投票

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

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

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


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);
        }
    }
}

3
投票

根据彼得斯的建议,这对我有用:

    [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);
            }
        }
    }

0
投票

晚了,但我已经做了一个工具来做到这一点。它应该在Unity中运行,但我认为它可以被其他C#解决方案采用。它可以在这里找到:https://github.com/mcpiroman/UnityNativeTool

请注意,它本质上是一个黑客(但经常使用hack,请参阅Harmony),所以我不建议在生产代码中使用它。


-1
投票

由于我在浏览信息时遇到了这些信息,因此我想我会回过头来解决OSX IN UNITY上的Sixense SDK问题。您将在那里看到在OSX上动态加载/卸载dylib的实现:

https://gist.github.com/amirebrahimi/d7b02c01bcd3ca7da144


-2
投票

如果您是函数式编程的粉丝,那么您可以使用LINQ来实现@IllidanS4建议的内容:

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

public static void UnloadModule(string moduleName)
{
   var loadedAssemblyModule =
            Process.GetCurrentProcess().Modules.OfType<ProcessModule>()
                .FirstOrDefault(x => x.ModuleName == moduleName);

   if (loadedAssemblyModule != null)
       FreeLibrary(loadedAssemblyModule.BaseAddress);
}
© www.soinside.com 2019 - 2024. All rights reserved.