C#でDllImport
を使用してロードされたDLLをアンロードするにはどうすればよいですか?
[DllImport] pinvoke宣言によってロードされたプロセスからアンマネージDLLをアンロードする最も信頼できる方法は、LoadLibrary()をピンボークすることによって自分でロードすることです。これにより、信頼性が高くなります。 DLLを処理し、DLLのモジュール名があいまいな場合でも、正しく機能します。実行時は、Windows以外には影響しません。 DLLの内部参照カウントを1から2に増やすローダー。
次に、FreeLibrary()twiceをピンボークして、参照カウントを0に減らし、LoadLibrary()から取得したIntPtrを渡します。これにより、DLLと、ロードされた依存DLLがアンロードされます。
anyエクスポートされた関数をDLLにもう一度、anyを実行しようとすると、非常に厄介なエラーが発生することに注意してください。pinvokeマーシャラーは認識していません。 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);
}
}
}
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);
}
}
}
パーティーに遅れましたが、私はこれを行うためのツールを作成しました。 Unityで実行することになっていますが、他のC#ソリューションにも採用できると思います。ここから入手できます: https://github.com/mcpiroman/UnityNativeTool 。
これは本質的にハックであることに注意してください(ただし、頻繁に使用されるハック。 Harmony を参照)。したがって、本番コードで使用することはお勧めしません。