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; }