Refactoring and cleanup of dynamic lib loading

Also fixed error reporting in WindowsLLManager, and fixed bug in
MednaDisc.CheckLibrary
This commit is contained in:
YoshiRulz 2019-12-19 14:16:42 +10:00
parent 7ea8fb185a
commit 580aa2eaf9
No known key found for this signature in database
GPG Key ID: C4DE31C245353FB7
20 changed files with 270 additions and 419 deletions

View File

@ -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
{

View File

@ -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()

View File

@ -65,7 +65,6 @@
<Compile Include="BizInvoke\BizInvokeUtilities.cs" />
<Compile Include="BizInvoke\CallingConventionAdapter.cs" />
<Compile Include="BizInvoke\POSIXLibC.cs" />
<Compile Include="BizInvoke\DynamicLibraryImportResolver.cs" />
<Compile Include="BizInvoke\MemoryBlock.cs" />
<Compile Include="BizInvoke\MemoryBlockBase.cs" />
<Compile Include="BizInvoke\MemoryBlockUnix.cs" />
@ -84,7 +83,6 @@
<Compile Include="HawkFile.cs" />
<Compile Include="IImportResolver.cs" />
<Compile Include="IMonitor.cs" />
<Compile Include="InstanceDll.cs" />
<Compile Include="Log.cs" />
<Compile Include="MutableIntRange.cs" />
<Compile Include="OSTailoredCode.cs" />

View File

@ -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<Type, DelegateStorage> Impls = new Dictionary<Type, DelegateStorage>();

View File

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

View File

@ -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/"
};
/// <remarks>this is needed to actually find the DLL properly on Unix</remarks>
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();
}
}
}

View File

@ -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
{
/// <summary>
/// interface for a dynamic link library or similar
/// </summary>
/// <summary>Implementors are able to provide pointers to functions in dynamically-linked libraries, which are loaded through some undefined mechanism.</summary>
/// <seealso cref="PatchImportResolver"/>
public interface IImportResolver
{
IntPtr Resolve(string entryPoint);
IntPtr? GetProcAddrOrNull(string entryPoint);
IntPtr GetProcAddrOrThrow(string entryPoint);
}
public static class ImportResolverExtensions
public class DynamicLibraryImportResolver : IDisposable, IImportResolver
{
/// <summary>
/// Resolve an entry point and throw an exception if that resolution is NULL
/// </summary>
public static IntPtr SafeResolve(this IImportResolver dll, string entryPoint)
private static readonly Lazy<IEnumerable<string>> asdf = new Lazy<IEnumerable<string>>(() =>
{
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();
}
}
/// <summary>
/// compose multiple ImportResolvers, where subsequent ones takes precedence over earlier ones
/// </summary>
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;
}
}
/// <summary>Aggregates <see cref="IImportResolver">resolvers</see>, resolving addresses by searching through them, starting with the last.</summary>
public class PatchImportResolver : IImportResolver
{
private readonly List<IImportResolver> _resolvers = new List<IImportResolver>();
private readonly List<IImportResolver> _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");
}
}

View File

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

View File

@ -10,27 +10,19 @@ namespace BizHawk.Common
{
public static class OSTailoredCode
{
/// <remarks>
/// macOS doesn't use <see cref="PlatformID.MacOSX">PlatformID.MacOSX</see>
/// </remarks>
/// <remarks>macOS doesn't use <see cref="PlatformID.MacOSX">PlatformID.MacOSX</see></remarks>
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<ILinkedLibManager> _LinkedLibManager = new Lazy<ILinkedLibManager>(() =>
private static readonly Lazy<ILinkedLibManager> _LinkedLibManager = new Lazy<ILinkedLibManager>(() => 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
/// <remarks>this interface's inheritors hide OS-specific implementation details</remarks>
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);
}
/// <remarks>This class is copied from a tutorial, so don't git blame and then email me expecting insight.</remarks>
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

View File

@ -11,9 +11,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
/// </summary>
private IntPtr AudDll;
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
/// <summary>
/// Gets the size of the mupen64plus audio buffer
/// </summary>
@ -44,13 +41,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
/// <param name="core">Core with loaded core api</param>
public mupen64plusAudioApi(mupen64plusApi core)
{
T GetAudioDelegate<T>(string proc) where T : Delegate => mupen64plusApi.GetTypedDelegate<T>(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>("GetBufferSize");
dllReadAudioBuffer = GetAudioDelegate<ReadAudioBuffer>("ReadAudioBuffer");
dllGetAudioRate = GetAudioDelegate<GetAudioRate>("GetAudioRate");
}
/// <summary>

View File

@ -576,46 +576,50 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
cb.GetType();
}
internal static T GetTypedDelegate<T>(IntPtr lib, string proc) where T : Delegate => (T) Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddrOrThrow(lib, proc), typeof(T));
/// <summary>
/// Look up function pointers in the dlls
/// </summary>
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<T>(string proc) where T : Delegate => GetTypedDelegate<T>(CoreDll, proc);
m64pSetTraceCallback = (SetTraceCallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "SetTraceCallback"), typeof(SetTraceCallback));
m64pCoreStartup = GetCoreDelegate<CoreStartup>("CoreStartup");
m64pCoreShutdown = GetCoreDelegate<CoreShutdown>("CoreShutdown");
m64pCoreDoCommandByteArray = GetCoreDelegate<CoreDoCommandByteArray>("CoreDoCommand");
m64pCoreDoCommandPtr = GetCoreDelegate<CoreDoCommandPtr>("CoreDoCommand");
m64pCoreDoCommandRefInt = GetCoreDelegate<CoreDoCommandRefInt>("CoreDoCommand");
m64pCoreDoCommandFrameCallback = GetCoreDelegate<CoreDoCommandFrameCallback>("CoreDoCommand");
m64pCoreDoCommandVICallback = GetCoreDelegate<CoreDoCommandVICallback>("CoreDoCommand");
m64pCoreDoCommandRenderCallback = GetCoreDelegate<CoreDoCommandRenderCallback>("CoreDoCommand");
m64pCoreAttachPlugin = GetCoreDelegate<CoreAttachPlugin>("CoreAttachPlugin");
m64pCoreDetachPlugin = GetCoreDelegate<CoreDetachPlugin>("CoreDetachPlugin");
m64pConfigOpenSection = GetCoreDelegate<ConfigOpenSection>("ConfigOpenSection");
m64pConfigSetParameter = GetCoreDelegate<ConfigSetParameter>("ConfigSetParameter");
m64pConfigSetParameterStr = GetCoreDelegate<ConfigSetParameterStr>("ConfigSetParameter");
m64pCoreSaveState = GetCoreDelegate<savestates_save_bkm>("savestates_save_bkm");
m64pCoreLoadState = GetCoreDelegate<savestates_load_bkm>("savestates_load_bkm");
m64pDebugMemGetPointer = GetCoreDelegate<DebugMemGetPointer>("DebugMemGetPointer");
m64pDebugSetCallbacks = GetCoreDelegate<DebugSetCallbacks>("DebugSetCallbacks");
m64pDebugBreakpointLookup = GetCoreDelegate<DebugBreakpointLookup>("DebugBreakpointLookup");
m64pDebugBreakpointCommand = GetCoreDelegate<DebugBreakpointCommand>("DebugBreakpointCommand");
m64pDebugGetState = GetCoreDelegate<DebugGetState>("DebugGetState");
m64pDebugSetRunState = GetCoreDelegate<DebugSetRunState>("DebugSetRunState");
m64pDebugStep = GetCoreDelegate<DebugStep>("DebugStep");
m64pMemGetSize = GetCoreDelegate<MemGetSize>("MemGetSize");
m64pinit_saveram = GetCoreDelegate<init_saveram>("init_saveram");
m64psave_saveram = GetCoreDelegate<save_saveram>("save_saveram");
m64pload_saveram = GetCoreDelegate<load_saveram>("load_saveram");
m64pGetRegisters = (GetRegisters)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "GetRegisters"), typeof(GetRegisters));
m64pSetTraceCallback = GetCoreDelegate<SetTraceCallback>("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>("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>("biz_read_memory");
m64p_write_memory_8 = GetCoreDelegate<biz_write_memory>("biz_write_memory");
m64p_decode_op = GetCoreDelegate<biz_r4300_decode_op>("biz_r4300_decode_op");
}
/// <summary>
@ -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<PluginStartup>(plugin.dllHandle, "PluginStartup");
plugin.dllShutdown = GetTypedDelegate<PluginShutdown>(plugin.dllHandle, "PluginShutdown");
plugin.dllStartup(CoreDll, null, null);
m64p_error result = m64pCoreAttachPlugin(type, plugin.dllHandle);

View File

@ -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
/// <summary>
/// Sets a callback to use when the mupen core wants controller buttons
/// </summary>
@ -66,14 +63,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
public mupen64plusInputApi(mupen64plusApi core)
{
T GetInputDelegate<T>(string proc) where T : Delegate => mupen64plusApi.GetTypedDelegate<T>(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>("SetInputCallback");
InpSetRumbleCallback = GetInputDelegate<SetRumbleCallback>("SetRumbleCallback");
InpSetControllerPakType = GetInputDelegate<SetControllerPakType>("SetControllerPakType");
InpSetControllerConnected = GetInputDelegate<SetControllerConnected>("SetControllerConnected");
m64pRumbleCallback = new RumbleCallback(FireOnRumbleChange);
result = InpSetRumbleCallback(m64pRumbleCallback);

View File

@ -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;
/// <summary>
/// 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<ReadScreen2>(GfxDll, "ReadScreen2");
GFXReadScreen2Res = mupen64plusApi.GetTypedDelegate<ReadScreen2Res>(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)

View File

@ -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();
}

View File

@ -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<Symbol> SymbolsByAddr = new List<Symbol>();
Dictionary<string, Symbol> SymbolsByName = new Dictionary<string, Symbol>();
@ -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<Symbol> Find(IntPtr addr, int length)

View File

@ -49,6 +49,8 @@ namespace BizHawk.Emulation.Cores.Libretro
public LibretroApi(string dllPath, string corePath)
{
T GetTypedDelegate<T>(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>("DllInit");
Message = GetTypedDelegate<MessageApi>("Message");
_copyBuffer = GetTypedDelegate<BufferApi>("CopyBuffer");
_setBuffer = GetTypedDelegate<BufferApi>("SetBuffer");
SetVariable = GetTypedDelegate<SetVariableApi>("SetVariable");
comm = (CommStruct*)dllinit(instanceDllCore.HModule).ToPointer();

View File

@ -390,18 +390,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
#endregion
public IntPtr Resolve(string entryPoint)
{
SymbolEntry<long> 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

View File

@ -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<Action>(libco.SafeResolve("co_clean"))();
CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer<Action>(libco.GetProcAddrOrThrow("co_clean"))();
}
_sealedheap.Seal();

View File

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

View File

@ -5,6 +5,8 @@ using System.Globalization;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using BizHawk.Common;
namespace BizHawk.Emulation.DiscSystem
{
/// <summary>
@ -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);