diff --git a/src/BizHawk.Common/IImportResolver.cs b/src/BizHawk.Common/IImportResolver.cs
index 4862ccbd2b..e9fde5f51a 100644
--- a/src/BizHawk.Common/IImportResolver.cs
+++ b/src/BizHawk.Common/IImportResolver.cs
@@ -25,11 +25,22 @@ namespace BizHawk.Common
});
private IntPtr _p;
+ private bool _eternal;
- public DynamicLibraryImportResolver(string dllName)
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// If true, the DLL will never be unloaded, even by god. Use this when you need lifetime semantics similar to [DllImport]
+ ///
+ public DynamicLibraryImportResolver(string dllName, bool eternal = false)
{
static string ResolveFilePath(string orig) => orig[0] == '/' ? orig : asdf.Value.Select(dir => dir + orig).FirstOrDefault(File.Exists) ?? orig;
_p = OSTailoredCode.LinkedLibManager.LoadOrThrow(OSTailoredCode.IsUnixHost ? ResolveFilePath(dllName) : dllName);
+ _eternal = eternal;
+ if (eternal)
+ GC.SuppressFinalize(this);
}
public IntPtr GetProcAddrOrZero(string entryPoint) => OSTailoredCode.LinkedLibManager.GetProcAddrOrZero(_p, entryPoint);
@@ -38,7 +49,8 @@ namespace BizHawk.Common
private void DisposeHelper()
{
- if (_p == IntPtr.Zero) return; // already freed
+ if (_eternal || _p == IntPtr.Zero)
+ return;
OSTailoredCode.LinkedLibManager.FreeByPtr(_p);
_p = IntPtr.Zero;
}
diff --git a/src/BizHawk.Emulation.Common/Sound/SpeexResampler.cs b/src/BizHawk.Emulation.Common/Sound/SpeexResampler.cs
index e8c6b5d02d..f047ee28ce 100644
--- a/src/BizHawk.Emulation.Common/Sound/SpeexResampler.cs
+++ b/src/BizHawk.Emulation.Common/Sound/SpeexResampler.cs
@@ -15,11 +15,11 @@ namespace BizHawk.Emulation.Common
public class SpeexResampler : IDisposable, ISoundProvider
{
private static readonly LibSpeexDSP NativeDSP;
- private static readonly IImportResolver NativeDLL;
static SpeexResampler()
{
- NativeDLL = new DynamicLibraryImportResolver(OSTailoredCode.IsUnixHost ? "libspeexdsp.so.1" : "libspeexdsp.dll");
- NativeDSP = BizInvoker.GetInvoker(NativeDLL, CallingConventionAdapters.Native);
+ var resolver = new DynamicLibraryImportResolver(
+ OSTailoredCode.IsUnixHost ? "libspeexdsp.so.1" : "libspeexdsp.dll", eternal: true);
+ NativeDSP = BizInvoker.GetInvoker(resolver, CallingConventionAdapters.Native);
}
// to accept an ISyncSoundProvider input
diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs
index aeac7d2417..5119166544 100644
--- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs
+++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs
@@ -27,8 +27,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
{
static QuickNES()
{
- Resolver = new DynamicLibraryImportResolver($"libquicknes{(OSTailoredCode.IsUnixHost ? ".dll.so.0.7.0" : ".dll")}");
- QN = BizInvoker.GetInvoker(Resolver, CallingConventionAdapters.Native);
+ var resolver = new DynamicLibraryImportResolver(
+ $"libquicknes{(OSTailoredCode.IsUnixHost ? ".dll.so.0.7.0" : ".dll")}", eternal: true);
+ QN = BizInvoker.GetInvoker(resolver, CallingConventionAdapters.Native);
QN.qn_setup_mappers();
}
@@ -81,7 +82,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
}
static readonly LibQuickNES QN;
- static readonly DynamicLibraryImportResolver Resolver;
public IEmulatorServiceProvider ServiceProvider { get; }