Как выгрузить DLL, загруженную с помощью DllImport
в С#?
Выгрузите DLL, загруженную с помощью DllImport
Ответ 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:
Ответ 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);
}