Refactoring and cleanup of dynamic lib loading
Also fixed error reporting in WindowsLLManager, and fixed bug in MednaDisc.CheckLibrary
This commit is contained in:
parent
7ea8fb185a
commit
580aa2eaf9
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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));
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue