Выгрузить DLL, загруженную с помощью DllImport - PullRequest
29 голосов
/ 15 марта 2010

Как выгрузить DLL, которая была загружена с помощью DllImport в C #?

Ответы [ 6 ]

22 голосов
/ 15 марта 2010

Самый надежный способ выгрузить неуправляемую DLL из процесса, который был загружен объявлением pinvoke [DllImport], - это загрузить его самостоятельно, снова вызвав LoadLibrary (). Это дает вам надежный дескриптор DLL и работает правильно, даже если имя модуля DLL неоднозначно. Он не оказывает никакого влияния во время выполнения, кроме загрузчика Windows, увеличивая внутренний счетчик ссылок на DLL с 1 до 2.

Затем вы можете вызвать функцию FreeLibrary () дважды , чтобы уменьшить счетчик ссылок до 0, передав ему IntPtr, полученный из LoadLibrary (). Это выгружает DLL, а также любые зависимые DLL, которые были загружены.

Остерегайтесь, что вы получите очень неприятный сбой при попытке снова вызвать любую экспортированную функцию в DLL, любой раз после этого. Маршаллер pinvoke не знает, что DLL больше не существует, и будет вызывать функцию по адресу, который, по ее мнению, все еще действителен. Который бомбит вашу программу с исключением AccessViolation, если вам повезет. Или запускает совершенно случайный бит кода, если вам не так повезло, и адресное пространство, ранее занимаемое DLL, снова использовалось другой DLL. Тогда может случиться что угодно, ничего хорошего.

10 голосов
/ 11 августа 2012

Это должно освободить модуль, ранее загруженный при вызове функции 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 голосов
/ 02 апреля 2015

На основании рекомендации Питерса это работает для меня:

    [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 голосов
/ 10 апреля 2019

Поздно на вечеринку, но я сделал инструмент для этого. Он должен работать в Unity, но я думаю, что он может быть адаптирован к другим решениям C #. Это доступно здесь: https://github.com/mcpiroman/UnityNativeTool.

Обратите внимание, что это по сути хак (но часто используемый хак, см. Harmony ), поэтому я не очень рекомендую использовать его в рабочем коде.

0 голосов
/ 20 января 2017

На всякий случай, если вы поклонник функционального программирования, вы можете использовать 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);
}
0 голосов
/ 19 августа 2015

Поскольку я наткнулся на информацию здесь, пока искал информацию, я полагаю, что я внесу свой вклад в то, что в итоге сделал, чтобы исправить проблему с Sixense SDK для OSX IN UNITY. Там вы увидите реализацию динамической загрузки / выгрузки dylib в OSX:

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

...