From 580aa2eaf90ee12925973bf7397d5fb215925d9a Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Thu, 19 Dec 2019 14:16:42 +1000 Subject: [PATCH] Refactoring and cleanup of dynamic lib loading Also fixed error reporting in WindowsLLManager, and fixed bug in MednaDisc.CheckLibrary --- .../CustomControls/Win32.cs | 3 - BizHawk.Client.EmuHawk/Input/GamePad360.cs | 46 ++++--- BizHawk.Common/BizHawk.Common.csproj | 2 - BizHawk.Common/BizInvoke/BizExvoker.cs | 9 +- BizHawk.Common/BizInvoke/BizInvoker.cs | 4 +- .../BizInvoke/DynamicLibraryImportResolver.cs | 78 ----------- BizHawk.Common/IImportResolver.cs | 126 +++++++++++++----- BizHawk.Common/InstanceDll.cs | 90 ------------- BizHawk.Common/OSTailoredCode.cs | 87 ++++++------ .../N64/NativeApi/mupen64plusAudioApi.cs | 11 +- .../N64/NativeApi/mupen64plusCoreApi.cs | 70 +++++----- .../N64/NativeApi/mupen64plusInputApi.cs | 13 +- .../N64/NativeApi/mupen64plusVideoApi.cs | 15 +-- .../Consoles/SNK/DualNeoGeoPort.cs | 6 +- .../Consoles/Sega/gpgx64/GenDbgHlp.cs | 30 ++--- .../Libretro/LibretroApi.cs | 12 +- BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs | 15 +-- BizHawk.Emulation.Cores/Waterbox/PeRunner.cs | 35 +++-- BizHawk.Emulation.Cores/Waterbox/PeWrapper.cs | 11 +- BizHawk.Emulation.DiscSystem/API_MednaDisc.cs | 26 +--- 20 files changed, 270 insertions(+), 419 deletions(-) delete mode 100644 BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs delete mode 100644 BizHawk.Common/InstanceDll.cs diff --git a/BizHawk.Client.EmuHawk/CustomControls/Win32.cs b/BizHawk.Client.EmuHawk/CustomControls/Win32.cs index d849bafec7..7d3e93b534 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/Win32.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/Win32.cs @@ -7,9 +7,6 @@ namespace BizHawk.Client.EmuHawk { public static unsafe class Win32 { - [DllImport("kernel32.dll")] - public static extern IntPtr LoadLibrary(string dllToLoad); - [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct RECT { diff --git a/BizHawk.Client.EmuHawk/Input/GamePad360.cs b/BizHawk.Client.EmuHawk/Input/GamePad360.cs index e28a5d6833..930069de4a 100644 --- a/BizHawk.Client.EmuHawk/Input/GamePad360.cs +++ b/BizHawk.Client.EmuHawk/Input/GamePad360.cs @@ -1,6 +1,9 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; + +using BizHawk.Common; + using SlimDX.XInput; #pragma warning disable 169 @@ -43,32 +46,33 @@ namespace BizHawk.Client.EmuHawk { try { - //some users wont even have xinput installed. in order to avoid spurious exceptions and possible instability, check for the library first - HasGetInputStateEx = true; - LibraryHandle = Win32.LoadLibrary("xinput1_3.dll"); - if(LibraryHandle == IntPtr.Zero) - LibraryHandle = Win32.LoadLibrary("xinput1_4.dll"); - if(LibraryHandle == IntPtr.Zero) + // some users won't even have xinput installed. in order to avoid spurious exceptions and possible instability, check for the library first + var llManager = OSTailoredCode.LinkedLibManager; + var libraryHandle = llManager.LoadOrNull("xinput1_3.dll") ?? llManager.LoadOrNull("xinput1_4.dll"); + if (libraryHandle != null) + { + HasGetInputStateEx = true; + XInputGetStateExProc = (XInputGetStateExProcDelegate) Marshal.GetDelegateForFunctionPointer( + Win32Imports.GetProcAddressOrdinal(libraryHandle.Value, new IntPtr(100)), + typeof(XInputGetStateExProcDelegate) + ); + } + else { - LibraryHandle = Win32.LoadLibrary("xinput9_1_0.dll"); HasGetInputStateEx = false; + libraryHandle = llManager.LoadOrNull("xinput9_1_0.dll"); } + _isAvailable = libraryHandle != null; + LibraryHandle = libraryHandle ?? IntPtr.Zero; - if (LibraryHandle != IntPtr.Zero) - { - if (HasGetInputStateEx) - { - var proc = BizHawk.Common.Win32Imports.GetProcAddressOrdinal(LibraryHandle, new IntPtr(100)); - XInputGetStateExProc = (XInputGetStateExProcDelegate)Marshal.GetDelegateForFunctionPointer(proc, typeof(XInputGetStateExProcDelegate)); - } - - //don't remove this code. it's important to catch errors on systems with broken xinput installs. - //(probably, checking for the library was adequate, but lets not get rid of this anyway) - var test = new SlimDX.XInput.Controller(UserIndex.One).IsConnected; - _isAvailable = true; - } + // don't remove this code. it's important to catch errors on systems with broken xinput installs. + // (probably, checking for the library was adequate, but let's not get rid of this anyway) + if (_isAvailable) _ = new Controller(UserIndex.One).IsConnected; + } + catch + { + // ignored } - catch { } } public static void Initialize() diff --git a/BizHawk.Common/BizHawk.Common.csproj b/BizHawk.Common/BizHawk.Common.csproj index 17c37d26de..f5d7df420b 100644 --- a/BizHawk.Common/BizHawk.Common.csproj +++ b/BizHawk.Common/BizHawk.Common.csproj @@ -65,7 +65,6 @@ - @@ -84,7 +83,6 @@ - diff --git a/BizHawk.Common/BizInvoke/BizExvoker.cs b/BizHawk.Common/BizInvoke/BizExvoker.cs index 2a12630349..d1e0f1ed56 100644 --- a/BizHawk.Common/BizInvoke/BizExvoker.cs +++ b/BizHawk.Common/BizInvoke/BizExvoker.cs @@ -95,12 +95,9 @@ namespace BizHawk.Common.BizInvoke } } - public IntPtr Resolve(string entryPoint) - { - IntPtr ret; - EntryPoints.TryGetValue(entryPoint, out ret); - return ret; - } + public IntPtr? GetProcAddrOrNull(string entryPoint) => EntryPoints.TryGetValue(entryPoint, out var ret) ? ret : default; + + public IntPtr GetProcAddrOrThrow(string entryPoint) => GetProcAddrOrNull(entryPoint) ?? throw new InvalidOperationException($"could not find {entryPoint} in exports"); } static readonly Dictionary Impls = new Dictionary(); diff --git a/BizHawk.Common/BizInvoke/BizInvoker.cs b/BizHawk.Common/BizInvoke/BizInvoker.cs index 0369c0ded4..1acd86f7f2 100644 --- a/BizHawk.Common/BizInvoke/BizInvoker.cs +++ b/BizHawk.Common/BizInvoke/BizInvoker.cs @@ -268,7 +268,7 @@ namespace BizHawk.Common.BizInvoke return (o, dll, adapter) => { - var entryPtr = dll.SafeResolve(entryPointName); + var entryPtr = dll.GetProcAddrOrThrow(entryPointName); var interopDelegate = adapter.GetDelegateForFunctionPointer(entryPtr, delegateType.CreateType()); o.GetType().GetField(field.Name).SetValue(o, interopDelegate); }; @@ -357,7 +357,7 @@ namespace BizHawk.Common.BizInvoke return (o, dll, adapter) => { - var entryPtr = dll.SafeResolve(entryPointName); + var entryPtr = dll.GetProcAddrOrThrow(entryPointName); o.GetType().GetField(field.Name).SetValue( o, adapter.GetDepartureFunctionPointer(entryPtr, new ParameterInfo(returnType, paramTypes), o)); }; diff --git a/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs b/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs deleted file mode 100644 index 9f4f0ce27b..0000000000 --- a/BizHawk.Common/BizInvoke/DynamicLibraryImportResolver.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System; -using System.IO; -using System.Reflection; - -namespace BizHawk.Common.BizInvoke -{ - /// TODO move this and all in IImportResolver.cs to OSTailoredCode.cs and refactor - public class DynamicLibraryImportResolver : IImportResolver, IDisposable - { - private IntPtr _p; - private readonly OSTailoredCode.ILinkedLibManager libLoader = OSTailoredCode.LinkedLibManager; //TODO inline? - - public DynamicLibraryImportResolver(string dllName) - { - _p = libLoader.LoadOrThrow(dllName); - } - - private string[] RelativeSearchPaths = { - "/", - "/dll/" - }; - - private string[] AbsoluteSearchPaths = { - "/usr/lib/", - "/usr/lib/bizhawk/" - }; - - /// this is needed to actually find the DLL properly on Unix - private void ResolveFilePath(ref string dllName) - { - if (dllName.IndexOf('/') != -1) return; // relative paths shouldn't contain '/' - - var currDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase).Replace("file:", ""); - string dll; - foreach (var p in AbsoluteSearchPaths) - { - dll = p + dllName; - if (File.Exists(dll)) - { - dllName = dll; - return; - } - } - foreach (var p in RelativeSearchPaths) - { - dll = currDir + p + dllName; - if (File.Exists(dll)) - { - dllName = dll; - return; - } - } - } - - public IntPtr Resolve(string entryPoint) - { - return libLoader.GetProcAddr(_p, entryPoint); - } - - private void Free() - { - if (_p == IntPtr.Zero) return; // already freed - libLoader.FreeByPtr(_p); - _p = IntPtr.Zero; - } - - public void Dispose() - { - Free(); - GC.SuppressFinalize(this); - } - - ~DynamicLibraryImportResolver() - { - Free(); - } - } -} diff --git a/BizHawk.Common/IImportResolver.cs b/BizHawk.Common/IImportResolver.cs index 06b33b1085..86a2196d44 100644 --- a/BizHawk.Common/IImportResolver.cs +++ b/BizHawk.Common/IImportResolver.cs @@ -1,58 +1,122 @@ using System; using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Security.AccessControl; namespace BizHawk.Common { - /// - /// interface for a dynamic link library or similar - /// + /// Implementors are able to provide pointers to functions in dynamically-linked libraries, which are loaded through some undefined mechanism. + /// public interface IImportResolver { - IntPtr Resolve(string entryPoint); + IntPtr? GetProcAddrOrNull(string entryPoint); + IntPtr GetProcAddrOrThrow(string entryPoint); } - public static class ImportResolverExtensions + public class DynamicLibraryImportResolver : IDisposable, IImportResolver { - /// - /// Resolve an entry point and throw an exception if that resolution is NULL - /// - public static IntPtr SafeResolve(this IImportResolver dll, string entryPoint) + private static readonly Lazy> asdf = new Lazy>(() => { - var ret = dll.Resolve(entryPoint); - if (ret == IntPtr.Zero) - { - throw new NullReferenceException($"Couldn't resolve entry point \"{entryPoint}\""); - } + var currDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase).Replace("file:", ""); + return new[] { "/usr/lib/", "/usr/lib/bizhawk/", "./", "./dll/" }.Select(dir => dir[0] == '.' ? currDir + dir.Substring(1) : dir); + }); - return ret; + private IntPtr _p; + + public DynamicLibraryImportResolver(string dllName) + { + 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); + } + + public IntPtr? GetProcAddrOrNull(string entryPoint) => OSTailoredCode.LinkedLibManager.GetProcAddrOrNull(_p, entryPoint); + + public IntPtr GetProcAddrOrThrow(string entryPoint) => OSTailoredCode.LinkedLibManager.GetProcAddrOrThrow(_p, entryPoint); + + private void DisposeHelper() + { + if (_p == IntPtr.Zero) return; // already freed + OSTailoredCode.LinkedLibManager.FreeByPtr(_p); + _p = IntPtr.Zero; + } + + public void Dispose() + { + DisposeHelper(); + GC.SuppressFinalize(this); + } + + ~DynamicLibraryImportResolver() + { + DisposeHelper(); } } - /// - /// compose multiple ImportResolvers, where subsequent ones takes precedence over earlier ones - /// + public class InstanceDll : IDisposable, IImportResolver + { + public IntPtr HModule { get; private set; } + + public InstanceDll(string dllPath) + { + // copy the dll to a temp directory + var path = TempFileManager.GetTempFilename(Path.GetFileNameWithoutExtension(dllPath), ".dll", false); + using var stream = new FileStream(path, FileMode.Create, FileSystemRights.FullControl, FileShare.ReadWrite | FileShare.Delete, 4 * 1024, FileOptions.None); + using var sdll = File.OpenRead(dllPath); + sdll.CopyTo(stream); + // try to locate dlls in the current directory (for libretro cores) + // this isn't foolproof but it's a little better than nothing + // setting PWD temporarily doesn't work. that'd be ideal since it supposedly gets searched early on, + // but i guess not with SetDllDirectory in effect + var envpath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process); + try + { + var envpath_new = $"{Path.GetDirectoryName(path)};{envpath}"; + Environment.SetEnvironmentVariable("PATH", envpath_new, EnvironmentVariableTarget.Process); + HModule = OSTailoredCode.LinkedLibManager.LoadOrThrow(path); // consider using LoadLibraryEx instead of shenanigans? + var newfname = TempFileManager.RenameTempFilenameForDelete(path); + File.Move(path, newfname); + } + catch + { + // ignored + } + Environment.SetEnvironmentVariable("PATH", envpath, EnvironmentVariableTarget.Process); + } + + public IntPtr? GetProcAddrOrNull(string procName) => OSTailoredCode.LinkedLibManager.GetProcAddrOrNull(HModule, procName); + + public IntPtr GetProcAddrOrThrow(string procName) => OSTailoredCode.LinkedLibManager.GetProcAddrOrThrow(HModule, procName); + + public void Dispose() + { + if (HModule == IntPtr.Zero) return; // already freed + OSTailoredCode.LinkedLibManager.FreeByPtr(HModule); + HModule = IntPtr.Zero; + } + } + + /// Aggregates resolvers, resolving addresses by searching through them, starting with the last. public class PatchImportResolver : IImportResolver { - private readonly List _resolvers = new List(); + private readonly List _resolvers; - public PatchImportResolver(params IImportResolver[] rr) + public PatchImportResolver(params IImportResolver[] resolvers) { - Add(rr); - } - public void Add(params IImportResolver[] rr) - { - _resolvers.AddRange(rr); + _resolvers = resolvers.ToList(); } - public IntPtr Resolve(string entryPoint) + public IntPtr? GetProcAddrOrNull(string entryPoint) { - for (int i = _resolvers.Count - 1; i >= 0; i--) + for (var i = _resolvers.Count - 1; i != -1; i--) { - var ret = _resolvers[i].Resolve(entryPoint); - if (ret != IntPtr.Zero) - return ret; + var ret = _resolvers[i].GetProcAddrOrNull(entryPoint); + if (ret != null) return ret.Value; } - return IntPtr.Zero; + return null; } + + public IntPtr GetProcAddrOrThrow(string entryPoint) => GetProcAddrOrNull(entryPoint) ?? throw new IOException($"{entryPoint} was not found in any of the aggregated resolvers"); } } diff --git a/BizHawk.Common/InstanceDll.cs b/BizHawk.Common/InstanceDll.cs deleted file mode 100644 index f2492d09ca..0000000000 --- a/BizHawk.Common/InstanceDll.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.IO; -using System.Runtime.InteropServices; - -namespace BizHawk.Common -{ - public class InstanceDll : IDisposable, IImportResolver - { - [DllImport("kernel32.dll")] - public static extern UInt32 GetLastError(); - - public InstanceDll(string dllPath) - { - // copy the dll to a temp directory - var path = TempFileManager.GetTempFilename(Path.GetFileNameWithoutExtension(dllPath), ".dll", false); - using (var stream = new FileStream(path, FileMode.Create, System.Security.AccessControl.FileSystemRights.FullControl, FileShare.ReadWrite | FileShare.Delete, 4 * 1024, FileOptions.None)) - using (var sdll = File.OpenRead(dllPath)) - sdll.CopyTo(stream); - - // try to locate dlls in the current directory (for libretro cores) - // this isnt foolproof but its a little better than nothing - // setting PWD temporarily doesnt work. that'd be ideal since it supposedly gets searched early on, - // but i guess not with SetDllDirectory in effect - var envpath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process); - try - { - string envpath_new = $"{Path.GetDirectoryName(path)};{envpath}"; - Environment.SetEnvironmentVariable("PATH", envpath_new, EnvironmentVariableTarget.Process); - _hModule = LoadLibrary(path); //consider using LoadLibraryEx instead of shenanigans? - if (_hModule == IntPtr.Zero) - { - var lastError = GetLastError(); - throw new InvalidOperationException($"Failed to load plugin {path}, error code: 0x{lastError:X}"); - } - var newfname = TempFileManager.RenameTempFilenameForDelete(path); - File.Move(path, newfname); - } - finally - { - Environment.SetEnvironmentVariable("PATH", envpath, EnvironmentVariableTarget.Process); - } - } - - [Flags] - enum LoadLibraryFlags : uint - { - DONT_RESOLVE_DLL_REFERENCES = 0x00000001, - LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010, - LOAD_LIBRARY_AS_DATAFILE = 0x00000002, - LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040, - LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020, - LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008 - } - - [DllImport("kernel32.dll", SetLastError = true)] - static extern IntPtr LoadLibrary(string dllToLoad); - - [DllImport("kernel32.dll", SetLastError = true)] - static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags); - - [DllImport("kernel32.dll")] - static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); - - [DllImport("kernel32.dll")] - static extern bool FreeLibrary(IntPtr hModule); - - public IntPtr GetProcAddress(string procName) - { - return GetProcAddress(_hModule, procName); - } - - public IntPtr HModule => _hModule; - - IntPtr IImportResolver.Resolve(string entryPoint) - { - return GetProcAddress(entryPoint); - } - - public void Dispose() - { - if (_hModule != IntPtr.Zero) - { - FreeLibrary(_hModule); - _hModule = IntPtr.Zero; - } - } - - private IntPtr _hModule; - } -} \ No newline at end of file diff --git a/BizHawk.Common/OSTailoredCode.cs b/BizHawk.Common/OSTailoredCode.cs index d6c020bd52..b0ec481ca6 100644 --- a/BizHawk.Common/OSTailoredCode.cs +++ b/BizHawk.Common/OSTailoredCode.cs @@ -10,27 +10,19 @@ namespace BizHawk.Common { public static class OSTailoredCode { - /// - /// macOS doesn't use PlatformID.MacOSX - /// + /// macOS doesn't use PlatformID.MacOSX public static readonly DistinctOS CurrentOS = Environment.OSVersion.Platform == PlatformID.Unix ? SimpleSubshell("uname", "-s", "Can't determine OS") == "Darwin" ? DistinctOS.macOS : DistinctOS.Linux : DistinctOS.Windows; public static readonly bool IsUnixHost = CurrentOS != DistinctOS.Windows; - private static readonly Lazy _LinkedLibManager = new Lazy(() => + private static readonly Lazy _LinkedLibManager = new Lazy(() => CurrentOS switch { - switch (CurrentOS) - { - case DistinctOS.Linux: - case DistinctOS.macOS: - return new UnixMonoLLManager(); - case DistinctOS.Windows: - return new WindowsLLManager(); - default: - throw new ArgumentOutOfRangeException(); - } + DistinctOS.Linux => (ILinkedLibManager) new UnixMonoLLManager(), + DistinctOS.macOS => new UnixMonoLLManager(), + DistinctOS.Windows => new WindowsLLManager(), + _ => throw new ArgumentOutOfRangeException() }); public static ILinkedLibManager LinkedLibManager => _LinkedLibManager.Value; @@ -38,78 +30,87 @@ namespace BizHawk.Common /// this interface's inheritors hide OS-specific implementation details public interface ILinkedLibManager { + int FreeByPtr(IntPtr hModule); + IntPtr? GetProcAddrOrNull(IntPtr hModule, string procName); + IntPtr GetProcAddrOrThrow(IntPtr hModule, string procName); IntPtr? LoadOrNull(string dllToLoad); IntPtr LoadOrThrow(string dllToLoad); - IntPtr GetProcAddr(IntPtr hModule, string procName); //TODO also split into nullable and throwing? - int FreeByPtr(IntPtr hModule); } - /// This class is copied from a tutorial, so don't git blame and then email me expecting insight. private class UnixMonoLLManager : ILinkedLibManager { - private const int RTLD_NOW = 2; [DllImport("libdl.so.2")] private static extern int dlclose(IntPtr handle); + [DllImport("libdl.so.2")] private static extern IntPtr dlerror(); + [DllImport("libdl.so.2")] private static extern IntPtr dlopen(string fileName, int flags); + [DllImport("libdl.so.2")] private static extern IntPtr dlsym(IntPtr handle, string symbol); - public IntPtr GetProcAddr(IntPtr hModule, string procName) + public int FreeByPtr(IntPtr hModule) => dlclose(hModule); + + public IntPtr? GetProcAddrOrNull(IntPtr hModule, string procName) { - dlerror(); - var res = dlsym(hModule, procName); - var errPtr = dlerror(); - if (errPtr != IntPtr.Zero) throw new InvalidOperationException($"error in {nameof(dlsym)}: {Marshal.PtrToStringAnsi(errPtr)}"); - return res; + var p = dlsym(hModule, procName); + return p == IntPtr.Zero ? default : p; } - public int FreeByPtr(IntPtr hModule) => dlclose(hModule); + public IntPtr GetProcAddrOrThrow(IntPtr hModule, string procName) + { + _ = dlerror(); // the Internet said to do this + var p = GetProcAddrOrNull(hModule, procName); + if (p != null) return p.Value; + var errCharPtr = dlerror(); + throw new InvalidOperationException($"error in {nameof(dlsym)}{(errCharPtr == IntPtr.Zero ? string.Empty : $": {Marshal.PtrToStringAnsi(errCharPtr)}")}"); + } public IntPtr? LoadOrNull(string dllToLoad) { + const int RTLD_NOW = 2; var p = dlopen(dllToLoad, RTLD_NOW); - return p == IntPtr.Zero ? default(IntPtr?) : p; + return p == IntPtr.Zero ? default : p; } - public IntPtr LoadOrThrow(string dllToLoad) - { - var p = LoadOrNull(dllToLoad); - if (!p.HasValue) throw new InvalidOperationException($"got null pointer from {nameof(dlopen)}, error: {Marshal.PtrToStringAnsi(dlerror())}"); - return p.Value; - } + public IntPtr LoadOrThrow(string dllToLoad) => LoadOrNull(dllToLoad) ?? throw new InvalidOperationException($"got null pointer from {nameof(dlopen)}, error: {Marshal.PtrToStringAnsi(dlerror())}"); } private class WindowsLLManager : ILinkedLibManager { // comments reference extern functions removed from SevenZip.NativeMethods + [DllImport("kernel32.dll")] private static extern bool FreeLibrary(IntPtr hModule); // return type was annotated MarshalAs(UnmanagedType.Bool) + [DllImport("kernel32.dll")] private static extern uint GetLastError(); - [DllImport("kernel32.dll")] // had BestFitMapping = false, ThrowOnUnmappableChar = true + + [DllImport("kernel32.dll", SetLastError = true)] // had BestFitMapping = false, ThrowOnUnmappableChar = true private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); // param procName was annotated `[MarshalAs(UnmanagedType.LPStr)]` - [DllImport("kernel32.dll")] // had BestFitMapping = false, ThrowOnUnmappableChar = true + + [DllImport("kernel32.dll", SetLastError = true)] // had BestFitMapping = false, ThrowOnUnmappableChar = true private static extern IntPtr LoadLibrary(string dllToLoad); // param dllToLoad was annotated `[MarshalAs(UnmanagedType.LPStr)]` - public IntPtr GetProcAddr(IntPtr hModule, string procName) => GetProcAddress(hModule, procName); + public int FreeByPtr(IntPtr hModule) => FreeLibrary(hModule) ? 0 : 1; - public int FreeByPtr(IntPtr hModule) => FreeLibrary(hModule) ? 1 : 0; + public IntPtr? GetProcAddrOrNull(IntPtr hModule, string procName) + { + var p = GetProcAddress(hModule, procName); + return p == IntPtr.Zero ? default : p; + } + + public IntPtr GetProcAddrOrThrow(IntPtr hModule, string procName) => GetProcAddrOrNull(hModule, procName) ?? throw new InvalidOperationException($"got null pointer from {nameof(GetProcAddress)}, error code: {GetLastError()}"); public IntPtr? LoadOrNull(string dllToLoad) { var p = LoadLibrary(dllToLoad); - return p == IntPtr.Zero ? default(IntPtr?) : p; + return p == IntPtr.Zero ? default : p; } - public IntPtr LoadOrThrow(string dllToLoad) - { - var p = LoadOrNull(dllToLoad); - if (!p.HasValue) throw new InvalidOperationException($"got null pointer from {nameof(LoadLibrary)}, error code: {GetLastError()}"); - return p.Value; - } + public IntPtr LoadOrThrow(string dllToLoad) => LoadOrNull(dllToLoad) ?? throw new InvalidOperationException($"got null pointer from {nameof(LoadLibrary)}, error code: {GetLastError()}"); } public enum DistinctOS : byte diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusAudioApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusAudioApi.cs index a61fb49b0e..74d7833a76 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusAudioApi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusAudioApi.cs @@ -11,9 +11,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi /// private IntPtr AudDll; - [DllImport("kernel32.dll")] - public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); - /// /// Gets the size of the mupen64plus audio buffer /// @@ -44,13 +41,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi /// Core with loaded core api public mupen64plusAudioApi(mupen64plusApi core) { + T GetAudioDelegate(string proc) where T : Delegate => mupen64plusApi.GetTypedDelegate(AudDll, proc); + AudDll = core.AttachPlugin(mupen64plusApi.m64p_plugin_type.M64PLUGIN_AUDIO, "mupen64plus-audio-bkm.dll"); // Connect dll functions - dllGetBufferSize = (GetBufferSize)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "GetBufferSize"), typeof(GetBufferSize)); - dllReadAudioBuffer = (ReadAudioBuffer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "ReadAudioBuffer"), typeof(ReadAudioBuffer)); - dllGetAudioRate = (GetAudioRate)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "GetAudioRate"), typeof(GetAudioRate)); + dllGetBufferSize = GetAudioDelegate("GetBufferSize"); + dllReadAudioBuffer = GetAudioDelegate("ReadAudioBuffer"); + dllGetAudioRate = GetAudioDelegate("GetAudioRate"); } /// diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs index ab33b1f433..9739d80e1f 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs @@ -576,46 +576,50 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi cb.GetType(); } + internal static T GetTypedDelegate(IntPtr lib, string proc) where T : Delegate => (T) Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddrOrThrow(lib, proc), typeof(T)); + /// /// Look up function pointers in the dlls /// void connectFunctionPointers() { - m64pCoreStartup = (CoreStartup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreStartup"), typeof(CoreStartup)); - m64pCoreShutdown = (CoreShutdown)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreShutdown"), typeof(CoreShutdown)); - m64pCoreDoCommandByteArray = (CoreDoCommandByteArray)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandByteArray)); - m64pCoreDoCommandPtr = (CoreDoCommandPtr)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandPtr)); - m64pCoreDoCommandRefInt = (CoreDoCommandRefInt)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRefInt)); - m64pCoreDoCommandFrameCallback = (CoreDoCommandFrameCallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandFrameCallback)); - m64pCoreDoCommandVICallback = (CoreDoCommandVICallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandVICallback)); - m64pCoreDoCommandRenderCallback = (CoreDoCommandRenderCallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRenderCallback)); - m64pCoreAttachPlugin = (CoreAttachPlugin)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreAttachPlugin"), typeof(CoreAttachPlugin)); - m64pCoreDetachPlugin = (CoreDetachPlugin)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDetachPlugin"), typeof(CoreDetachPlugin)); - m64pConfigOpenSection = (ConfigOpenSection)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "ConfigOpenSection"), typeof(ConfigOpenSection)); - m64pConfigSetParameter = (ConfigSetParameter)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameter)); - m64pConfigSetParameterStr = (ConfigSetParameterStr)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameterStr)); - m64pCoreSaveState = (savestates_save_bkm)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "savestates_save_bkm"), typeof(savestates_save_bkm)); - m64pCoreLoadState = (savestates_load_bkm)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "savestates_load_bkm"), typeof(savestates_load_bkm)); - m64pDebugMemGetPointer = (DebugMemGetPointer)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugMemGetPointer"), typeof(DebugMemGetPointer)); - m64pDebugSetCallbacks = (DebugSetCallbacks)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugSetCallbacks"), typeof(DebugSetCallbacks)); - m64pDebugBreakpointLookup = (DebugBreakpointLookup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugBreakpointLookup"), typeof(DebugBreakpointLookup)); - m64pDebugBreakpointCommand = ( DebugBreakpointCommand )Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugBreakpointCommand"), typeof(DebugBreakpointCommand)); - m64pDebugGetState = (DebugGetState)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugGetState"), typeof(DebugGetState)); - m64pDebugSetRunState = (DebugSetRunState)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugSetRunState"), typeof(DebugSetRunState)); - m64pDebugStep = (DebugStep)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugStep"), typeof(DebugStep)); - m64pMemGetSize = (MemGetSize)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "MemGetSize"), typeof(MemGetSize)); - m64pinit_saveram = (init_saveram)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "init_saveram"), typeof(init_saveram)); - m64psave_saveram = (save_saveram)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "save_saveram"), typeof(save_saveram)); - m64pload_saveram = (load_saveram)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "load_saveram"), typeof(load_saveram)); + T GetCoreDelegate(string proc) where T : Delegate => GetTypedDelegate(CoreDll, proc); - m64pSetTraceCallback = (SetTraceCallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "SetTraceCallback"), typeof(SetTraceCallback)); + m64pCoreStartup = GetCoreDelegate("CoreStartup"); + m64pCoreShutdown = GetCoreDelegate("CoreShutdown"); + m64pCoreDoCommandByteArray = GetCoreDelegate("CoreDoCommand"); + m64pCoreDoCommandPtr = GetCoreDelegate("CoreDoCommand"); + m64pCoreDoCommandRefInt = GetCoreDelegate("CoreDoCommand"); + m64pCoreDoCommandFrameCallback = GetCoreDelegate("CoreDoCommand"); + m64pCoreDoCommandVICallback = GetCoreDelegate("CoreDoCommand"); + m64pCoreDoCommandRenderCallback = GetCoreDelegate("CoreDoCommand"); + m64pCoreAttachPlugin = GetCoreDelegate("CoreAttachPlugin"); + m64pCoreDetachPlugin = GetCoreDelegate("CoreDetachPlugin"); + m64pConfigOpenSection = GetCoreDelegate("ConfigOpenSection"); + m64pConfigSetParameter = GetCoreDelegate("ConfigSetParameter"); + m64pConfigSetParameterStr = GetCoreDelegate("ConfigSetParameter"); + m64pCoreSaveState = GetCoreDelegate("savestates_save_bkm"); + m64pCoreLoadState = GetCoreDelegate("savestates_load_bkm"); + m64pDebugMemGetPointer = GetCoreDelegate("DebugMemGetPointer"); + m64pDebugSetCallbacks = GetCoreDelegate("DebugSetCallbacks"); + m64pDebugBreakpointLookup = GetCoreDelegate("DebugBreakpointLookup"); + m64pDebugBreakpointCommand = GetCoreDelegate("DebugBreakpointCommand"); + m64pDebugGetState = GetCoreDelegate("DebugGetState"); + m64pDebugSetRunState = GetCoreDelegate("DebugSetRunState"); + m64pDebugStep = GetCoreDelegate("DebugStep"); + m64pMemGetSize = GetCoreDelegate("MemGetSize"); + m64pinit_saveram = GetCoreDelegate("init_saveram"); + m64psave_saveram = GetCoreDelegate("save_saveram"); + m64pload_saveram = GetCoreDelegate("load_saveram"); - m64pGetRegisters = (GetRegisters)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "GetRegisters"), typeof(GetRegisters)); + m64pSetTraceCallback = GetCoreDelegate("SetTraceCallback"); - m64p_read_memory_8 = (biz_read_memory)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "biz_read_memory"), typeof(biz_read_memory)); - m64p_write_memory_8 = (biz_write_memory)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "biz_write_memory"), typeof(biz_write_memory)); + m64pGetRegisters = GetCoreDelegate("GetRegisters"); - m64p_decode_op = (biz_r4300_decode_op)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "biz_r4300_decode_op"), typeof(biz_r4300_decode_op)); + m64p_read_memory_8 = GetCoreDelegate("biz_read_memory"); + m64p_write_memory_8 = GetCoreDelegate("biz_write_memory"); + + m64p_decode_op = GetCoreDelegate("biz_r4300_decode_op"); } /// @@ -986,8 +990,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi AttachedPlugin plugin; plugin.dllHandle = libLoader.LoadOrThrow(PluginName); - plugin.dllStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(plugin.dllHandle, "PluginStartup"), typeof(PluginStartup)); - plugin.dllShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(plugin.dllHandle, "PluginShutdown"), typeof(PluginShutdown)); + plugin.dllStartup = GetTypedDelegate(plugin.dllHandle, "PluginStartup"); + plugin.dllShutdown = GetTypedDelegate(plugin.dllHandle, "PluginShutdown"); plugin.dllStartup(CoreDll, null, null); m64p_error result = m64pCoreAttachPlugin(type, plugin.dllHandle); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusInputApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusInputApi.cs index f412ac0b35..6b5531f99d 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusInputApi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusInputApi.cs @@ -11,9 +11,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi { IntPtr InpDll; - [DllImport("kernel32.dll")] - public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);// Input plugin specific - /// /// Sets a callback to use when the mupen core wants controller buttons /// @@ -66,14 +63,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi public mupen64plusInputApi(mupen64plusApi core) { + T GetInputDelegate(string proc) where T : Delegate => mupen64plusApi.GetTypedDelegate(InpDll, proc); + InpDll = core.AttachPlugin(mupen64plusApi.m64p_plugin_type.M64PLUGIN_INPUT, "mupen64plus-input-bkm.dll"); mupen64plusApi.m64p_error result; - InpSetInputCallback = (SetInputCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetInputCallback"), typeof(SetInputCallback)); - InpSetRumbleCallback = (SetRumbleCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetRumbleCallback"), typeof(SetRumbleCallback)); - InpSetControllerPakType = (SetControllerPakType)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetControllerPakType"), typeof(SetControllerPakType)); - InpSetControllerConnected = (SetControllerConnected)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetControllerConnected"), typeof(SetControllerConnected)); + InpSetInputCallback = GetInputDelegate("SetInputCallback"); + InpSetRumbleCallback = GetInputDelegate("SetRumbleCallback"); + InpSetControllerPakType = GetInputDelegate("SetControllerPakType"); + InpSetControllerConnected = GetInputDelegate("SetControllerConnected"); m64pRumbleCallback = new RumbleCallback(FireOnRumbleChange); result = InpSetRumbleCallback(m64pRumbleCallback); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusVideoApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusVideoApi.cs index 16ec0a4516..ca8e64834e 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusVideoApi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusVideoApi.cs @@ -6,14 +6,13 @@ using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; +using BizHawk.Common; + namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi { class mupen64plusVideoApi { - IntPtr GfxDll;// Graphics plugin specific - - [DllImport("kernel32.dll")] - public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); + IntPtr GfxDll; /// /// Fills a provided buffer with the mupen64plus framebuffer @@ -64,10 +63,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi GfxDll = core.AttachPlugin(mupen64plusApi.m64p_plugin_type.M64PLUGIN_GFX, videoplugin); - GFXReadScreen2 = (ReadScreen2)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "ReadScreen2"), typeof(ReadScreen2)); - GFXReadScreen2Res = (ReadScreen2Res)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "ReadScreen2"), typeof(ReadScreen2Res)); - if(GetProcAddress(GfxDll, "GetScreenTextureID") != IntPtr.Zero) - GFXGetScreenTextureID = (GetScreenTextureID)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "GetScreenTextureID"), typeof(GetScreenTextureID)); + GFXReadScreen2 = mupen64plusApi.GetTypedDelegate(GfxDll, "ReadScreen2"); + GFXReadScreen2Res = mupen64plusApi.GetTypedDelegate(GfxDll, "ReadScreen2"); + var funcPtr = OSTailoredCode.LinkedLibManager.GetProcAddrOrNull(GfxDll, "GetScreenTextureID"); + if (funcPtr != null) GFXGetScreenTextureID = (GetScreenTextureID) Marshal.GetDelegateForFunctionPointer(funcPtr.Value, typeof(GetScreenTextureID)); } public void GetScreenDimensions(ref int width, ref int height) diff --git a/BizHawk.Emulation.Cores/Consoles/SNK/DualNeoGeoPort.cs b/BizHawk.Emulation.Cores/Consoles/SNK/DualNeoGeoPort.cs index ae20720922..87774a5428 100644 --- a/BizHawk.Emulation.Cores/Consoles/SNK/DualNeoGeoPort.cs +++ b/BizHawk.Emulation.Cores/Consoles/SNK/DualNeoGeoPort.cs @@ -210,9 +210,9 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK _push = push; _pull = pull; _exporter = BizExvoker.GetExvoker(this, CallingConventionAdapters.Waterbox); - _readcb = _exporter.SafeResolve("CommsReadCallback"); - _pollcb = _exporter.SafeResolve("CommsPollCallback"); - _writecb = _exporter.SafeResolve("CommsWriteCallback"); + _readcb = _exporter.GetProcAddrOrThrow("CommsReadCallback"); + _pollcb = _exporter.GetProcAddrOrThrow("CommsPollCallback"); + _writecb = _exporter.GetProcAddrOrThrow("CommsWriteCallback"); ConnectPointers(); } diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GenDbgHlp.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GenDbgHlp.cs index 115a5fdc7a..7ad5c01bd6 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GenDbgHlp.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GenDbgHlp.cs @@ -5,6 +5,8 @@ using System.Text; using System.Runtime.InteropServices; using System.IO; +using BizHawk.Common; + namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx { /* @@ -25,35 +27,22 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx public class GenDbgHlp : IDisposable { - private static class Win32 - { - [DllImport("kernel32.dll")] - public static extern IntPtr LoadLibrary(string dllToLoad); - [DllImport("kernel32.dll")] - public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); - [DllImport("kernel32.dll")] - public static extern bool FreeLibrary(IntPtr hModule); - } - // config const string modulename = "libgenplusgx.dll"; const string symbolname = @"D:\encodes\bizhawksrc\genplus-gx\libretro\msvc\Debug\vars.txt"; const int start = 0x0c7d8000 - 0x0c540000; const int length = 0x01082000; - bool disposed = false; + private bool disposed => DllBase == IntPtr.Zero; public void Dispose() { - if (!disposed) - { - Win32.FreeLibrary(DllBase); - DllBase = IntPtr.Zero; - disposed = true; - } + if (DllBase == IntPtr.Zero) return; // already freed + OSTailoredCode.LinkedLibManager.FreeByPtr(DllBase); + DllBase = IntPtr.Zero; } - IntPtr DllBase; + private IntPtr DllBase; List SymbolsByAddr = new List(); Dictionary SymbolsByName = new Dictionary(); @@ -145,10 +134,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx } SymbolsByAddr.Sort(); } - - DllBase = Win32.LoadLibrary(modulename); - if (DllBase == IntPtr.Zero) - throw new Exception(); + DllBase = OSTailoredCode.LinkedLibManager.LoadOrThrow(modulename); } public List Find(IntPtr addr, int length) diff --git a/BizHawk.Emulation.Cores/Libretro/LibretroApi.cs b/BizHawk.Emulation.Cores/Libretro/LibretroApi.cs index ecd25b3354..7619cdaafd 100644 --- a/BizHawk.Emulation.Cores/Libretro/LibretroApi.cs +++ b/BizHawk.Emulation.Cores/Libretro/LibretroApi.cs @@ -49,6 +49,8 @@ namespace BizHawk.Emulation.Cores.Libretro public LibretroApi(string dllPath, string corePath) { + T GetTypedDelegate(string proc) where T : Delegate => (T) Marshal.GetDelegateForFunctionPointer(instanceDll.GetProcAddrOrThrow(proc), typeof(T)); + InstanceName = "libretro_" + Guid.NewGuid().ToString(); var pipeName = InstanceName; @@ -56,11 +58,11 @@ namespace BizHawk.Emulation.Cores.Libretro instanceDll = new InstanceDll(dllPath); instanceDllCore = new InstanceDll(corePath); - var dllinit = (DllInit)Marshal.GetDelegateForFunctionPointer(instanceDll.GetProcAddress("DllInit"), typeof(DllInit)); - Message = (MessageApi)Marshal.GetDelegateForFunctionPointer(instanceDll.GetProcAddress("Message"), typeof(MessageApi)); - _copyBuffer = (BufferApi)Marshal.GetDelegateForFunctionPointer(instanceDll.GetProcAddress("CopyBuffer"), typeof(BufferApi)); - _setBuffer = (BufferApi)Marshal.GetDelegateForFunctionPointer(instanceDll.GetProcAddress("SetBuffer"), typeof(BufferApi)); - SetVariable = (SetVariableApi)Marshal.GetDelegateForFunctionPointer(instanceDll.GetProcAddress("SetVariable"), typeof(SetVariableApi)); + var dllinit = GetTypedDelegate("DllInit"); + Message = GetTypedDelegate("Message"); + _copyBuffer = GetTypedDelegate("CopyBuffer"); + _setBuffer = GetTypedDelegate("SetBuffer"); + SetVariable = GetTypedDelegate("SetVariable"); comm = (CommStruct*)dllinit(instanceDllCore.HModule).ToPointer(); diff --git a/BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs b/BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs index 96d5ac0756..5a1ef6bd2b 100644 --- a/BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs +++ b/BizHawk.Emulation.Cores/Waterbox/ElfRunner.cs @@ -390,18 +390,9 @@ namespace BizHawk.Emulation.Cores.Waterbox #endregion - public IntPtr Resolve(string entryPoint) - { - SymbolEntry sym; - if (_symdict.TryGetValue(entryPoint, out sym)) - { - return Z.SS(sym.Value + _loadoffset); - } - else - { - return IntPtr.Zero; - } - } + public IntPtr? GetProcAddrOrNull(string entryPoint) => _symdict.TryGetValue(entryPoint, out var sym) ? Z.SS(sym.Value + _loadoffset) : default; + + public IntPtr GetProcAddrOrThrow(string entryPoint) => GetProcAddrOrNull(entryPoint) ?? throw new InvalidOperationException($"could not find {entryPoint} in exports"); #region state diff --git a/BizHawk.Emulation.Cores/Waterbox/PeRunner.cs b/BizHawk.Emulation.Cores/Waterbox/PeRunner.cs index a39a2b47ab..e7eb4f5eda 100644 --- a/BizHawk.Emulation.Cores/Waterbox/PeRunner.cs +++ b/BizHawk.Emulation.Cores/Waterbox/PeRunner.cs @@ -97,19 +97,16 @@ namespace BizHawk.Emulation.Cores.Waterbox var imports = _parent._exports[moduleName]; var pointers = entries.Select(e => { - var ptr = imports.Resolve(e); - if (ptr == IntPtr.Zero) + var ptr = imports.GetProcAddrOrNull(e); + if (ptr != null) return ptr.Value; + var s = $"Trapped on unimplemented function {moduleName}:{e}"; + Action del = () => { - var s = $"Trapped on unimplemented function {moduleName}:{e}"; - Action del = () => - { - Console.WriteLine(s); - throw new InvalidOperationException(s); - }; - _traps.Add(del); - ptr = CallingConventionAdapters.Waterbox.GetFunctionPointerForDelegate(del); - } - return ptr; + Console.WriteLine(s); + throw new InvalidOperationException(s); + }; + _traps.Add(del); + return CallingConventionAdapters.Waterbox.GetFunctionPointerForDelegate(del); }).ToArray(); Marshal.Copy(pointers, 0, table, pointers.Length); } @@ -1071,8 +1068,8 @@ namespace BizHawk.Emulation.Cores.Waterbox } // run unmanaged init code - var libcEnter = _exports["libc.so"].SafeResolve("__libc_entry_routine"); - var psxInit = _exports["libpsxscl.so"].SafeResolve("__psx_init"); + var libcEnter = _exports["libc.so"].GetProcAddrOrThrow("__libc_entry_routine"); + var psxInit = _exports["libpsxscl.so"].GetProcAddrOrThrow("__psx_init"); var del = (LibcEntryRoutineD)CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer(libcEnter, typeof(LibcEntryRoutineD)); // the current mmglue code doesn't use the main pointer at all, and this just returns @@ -1101,11 +1098,9 @@ namespace BizHawk.Emulation.Cores.Waterbox } } - public IntPtr Resolve(string entryPoint) - { - // modules[0] is always the main module - return _modules[0].Resolve(entryPoint); - } + public IntPtr? GetProcAddrOrNull(string entryPoint) => _modules[0].GetProcAddrOrNull(entryPoint); // _modules[0] is always the main module + + public IntPtr GetProcAddrOrThrow(string entryPoint) => _modules[0].GetProcAddrOrThrow(entryPoint); public void Seal() { @@ -1121,7 +1116,7 @@ namespace BizHawk.Emulation.Cores.Waterbox if (_exports.TryGetValue("libco.so", out libco)) { Console.WriteLine("Calling co_clean()..."); - CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer(libco.SafeResolve("co_clean"))(); + CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer(libco.GetProcAddrOrThrow("co_clean"))(); } _sealedheap.Seal(); diff --git a/BizHawk.Emulation.Cores/Waterbox/PeWrapper.cs b/BizHawk.Emulation.Cores/Waterbox/PeWrapper.cs index e94afb4ecd..031d047c16 100644 --- a/BizHawk.Emulation.Cores/Waterbox/PeWrapper.cs +++ b/BizHawk.Emulation.Cores/Waterbox/PeWrapper.cs @@ -301,12 +301,9 @@ namespace BizHawk.Emulation.Cores.Waterbox } } - public IntPtr Resolve(string entryPoint) - { - IntPtr ret; - ExportsByName.TryGetValue(entryPoint, out ret); - return ret; - } + public IntPtr? GetProcAddrOrNull(string entryPoint) => ExportsByName.TryGetValue(entryPoint, out var ret) ? ret : default; + + public IntPtr GetProcAddrOrThrow(string entryPoint) => GetProcAddrOrNull(entryPoint) ?? throw new InvalidOperationException($"could not find {entryPoint} in exports"); public void ConnectImports(string moduleName, IImportResolver module) { @@ -321,7 +318,7 @@ namespace BizHawk.Emulation.Cores.Waterbox { foreach (var kvp in imports) { - var valueArray = new IntPtr[] { module.SafeResolve(kvp.Key) }; + var valueArray = new IntPtr[] { module.GetProcAddrOrThrow(kvp.Key) }; Marshal.Copy(valueArray, 0, kvp.Value, 1); } } diff --git a/BizHawk.Emulation.DiscSystem/API_MednaDisc.cs b/BizHawk.Emulation.DiscSystem/API_MednaDisc.cs index 5288b214fb..93732b8a97 100644 --- a/BizHawk.Emulation.DiscSystem/API_MednaDisc.cs +++ b/BizHawk.Emulation.DiscSystem/API_MednaDisc.cs @@ -5,6 +5,8 @@ using System.Globalization; using System.Collections.Generic; using System.Runtime.InteropServices; +using BizHawk.Common; + namespace BizHawk.Emulation.DiscSystem { /// @@ -92,19 +94,10 @@ namespace BizHawk.Emulation.DiscSystem static void CheckLibrary() { - IntPtr lib = LoadLibrary("mednadisc.dll"); - if (lib == IntPtr.Zero) - { - _IsLibraryAvailable = false; - return; - } - IntPtr addr = GetProcAddress(lib, "mednadisc_LoadCD"); - FreeLibrary(lib); - if (addr == IntPtr.Zero) - { - _IsLibraryAvailable = false; - } - _IsLibraryAvailable = true; + var lib = OSTailoredCode.LinkedLibManager.LoadOrNull("mednadisc.dll"); + _IsLibraryAvailable = lib != null + && OSTailoredCode.LinkedLibManager.GetProcAddrOrNull(lib.Value, "mednadisc_LoadCD") != null; + if (lib != null) OSTailoredCode.LinkedLibManager.FreeByPtr(lib.Value); } static MednaDisc() @@ -142,13 +135,6 @@ namespace BizHawk.Emulation.DiscSystem public bool Valid { get { return _validByte != 0; } } }; - [DllImport("kernel32.dll")] - static extern IntPtr LoadLibrary(string dllToLoad); - [DllImport("kernel32.dll")] - static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName); - [DllImport("kernel32.dll")] - static extern bool FreeLibrary(IntPtr hModule); - [DllImport("mednadisc.dll", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr mednadisc_LoadCD(string path);