代码之家  ›  专栏  ›  技术社区  ›  subbu

卸载使用dllimport加载的dll

  •  28
  • subbu  · 技术社区  · 16 年前

    如何卸载已使用 DllImport 在C?

    5 回复  |  直到 8 年前
        1
  •  22
  •   Hans Passant    14 年前

    从由[dllimport]pinvoke声明加载的进程中卸载非托管dll的最可靠方法是再次通过pinvoking loadlibrary()亲自加载它。这为您提供了一个可靠的dll句柄,即使dll的模块名不明确,也能正常工作。它在运行时没有任何影响,只是windows加载程序将dll上的内部引用计数从1增加到2。

    然后您可以使用pinvoke freelibrary() 两次 若要将引用计数减少到0,请将从loadlibrary()获得的intptr传递给它。卸载dll以及加载的任何依赖dll。

    当心,当你试着去品沃克的时候,你会得到非常严重的失败。 任何 再次导出dll上的函数, 任何 做了这些之后。pinvoke封送拆收器不知道dll已经不存在了,将在它认为仍然有效的地址调用该函数。如果你幸运的话,它会用一个accessviolation异常来轰炸你的程序。或者运行完全随机的代码位,如果你不是那么幸运的话,以前由dll占用的地址空间被另一个dll重新使用。那时候什么事都有可能发生,都不好。

        2
  •  9
  •   IS4    14 年前

    这将释放以前调用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
  •  3
  •   stefan.seeland    11 年前

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

        [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);
                }
            }
        }
    
        4
  •  -1
  •   Amir Ebrahimi    11 年前

    因为我在四处寻找信息时发现了这里的信息,我想我会贡献我最终所做的事情来修复Unity中OSX上SixenseSDK的一个问题。您将看到在osx上动态加载/卸载dylib的实现:

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

        5
  •  -2
  •   RBT    8 年前

    如果你是函数式编程的爱好者,那么你可以使用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);
    }