Подтвердить что ты не робот

Выгрузите DLL, загруженную с помощью DllImport

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

Основываясь на рекомендации Peters, это работает для меня:

    [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

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

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

Ответ 5

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