[英]Unload a DLL loaded using DllImport
如何卸載在C#中使用DllImport
加載的DLL?
從[DllImport] pinvoke聲明加載的進程中卸載非托管DLL的最可靠方法是通過pinvoking LoadLibrary()再次自己加載它。 這為DLL提供了可靠的DLL處理,即使DLL的模塊名稱不明確也能正常工作。 它在運行時沒有任何影響,除了Windows加載器將DLL的內部引用計數從1增加到2。
然后,您可以將FreeLibrary() 兩次旋轉以將引用計數減少為0,並將其從LoadLibrary()傳遞給IntPtr。 卸載DLL,以及任何加載的依賴DLL。
要注意的是,當你嘗試這樣做后,再次的PInvoke的DLL 任何導出函數, 任何時候你會得到非常討厭失敗。 pinvoke marshaller不知道DLL不再存在,並且會在它認為仍然有效的地址處調用該函數。 如果幸運的話,哪些程序會使用AccessViolation異常對您的程序進行轟炸。 或者運行一個完全隨機的代碼,如果你不是那么幸運,以前DLL占用的地址空間被另一個DLL重用。 任何事情都可能發生,沒有一件好事。
這應該釋放先前在您調用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);
}
}
}
根據彼得斯的建議,這對我有用:
[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);
}
}
}
晚了,但我已經做了一個工具來做到這一點。 它應該在Unity中運行,但我認為它可以被其他C#解決方案采用。 它可以在這里找到: https : //github.com/mcpiroman/UnityNativeTool 。
請注意,它本質上是一個黑客(但經常使用hack,請參閱Harmony ),所以我不建議在生產代碼中使用它。
由於我在瀏覽信息時遇到了這些信息,因此我想我會回過頭來解決OSX IN UNITY上的Sixense SDK問題。 您將在那里看到在OSX上動態加載/卸載dylib的實現:
如果您是函數式編程的粉絲,那么您可以使用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);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.