web-dev-qa-db-ja.com

DllImportを使用してロードされたDLL

C#でDllImportを使用してロードされたDLLをアンロードするにはどうすればよいですか?

31
subbu

[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によって再利用された場合は、コードの一部になります。

22
Mitch Wheat

これにより、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);
        }
    }
}
10
IllidanS4

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);
            }
        }
    }
3
stefan.seeland

パーティーに遅れましたが、私はこれを行うためのツールを作成しました。 Unityで実行することになっていますが、他のC#ソリューションにも採用できると思います。ここから入手できます: https://github.com/mcpiroman/UnityNativeTool

これは本質的にハックであることに注意してください(ただし、頻繁に使用されるハック。 Harmony を参照)。したがって、本番コードで使用することはお勧めしません。

0
mcpiroman