fix ordinal loading (im pretty sure what was being done before only actually worked for dllimport and not getprocaddress)

cleanup some more win32 imports (new LoaderApiImports, although it isn't used for OSTailoredCode to avoid hard dep on BizHawk.Common, probably want to use same hack on LoaderApiImports)
This commit is contained in:
CasualPokePlayer 2023-11-02 22:48:12 -07:00
parent 195846f2f3
commit b1f16cf437
6 changed files with 56 additions and 49 deletions

View File

@ -32,29 +32,24 @@ namespace BizHawk.Bizware.Input
IsAvailable = XInput.Version != XInputVersion.Invalid;
if (IsAvailable)
{
var llManager = OSTailoredCode.LinkedLibManager;
var libHandle = XInput.Version switch
{
XInputVersion.Version14 => llManager.LoadOrThrow("xinput1_4.dll"),
XInputVersion.Version13 => llManager.LoadOrThrow("xinput1_3.dll"),
XInputVersion.Version14 => LoaderApiImports.GetModuleHandleW("xinput1_4.dll"),
XInputVersion.Version13 => LoaderApiImports.GetModuleHandleW("xinput1_3.dll"),
_ => IntPtr.Zero // unofficial API isn't available for 9.1.0
};
if (libHandle != IntPtr.Zero)
{
var fptr = llManager.GetProcAddrOrZero(libHandle, "#100");
var fptr = LoaderApiImports.GetProcAddress(libHandle, new IntPtr(100));
if (fptr != IntPtr.Zero)
{
XInputGetStateExProc =
Marshal.GetDelegateForFunctionPointer<XInputGetStateExProcDelegate>(fptr);
}
// nb: this doesn't actually free the library here, rather it will just decrement the reference count
llManager.FreeByPtr(libHandle);
}
// don't remove this code. it's important to catch errors on systems with broken xinput installs.
_ = XInputGetStateExProc?.Invoke(0, out _);
_ = XInput.GetState(0, out _);
}

View File

@ -6,7 +6,6 @@ using System.Runtime.InteropServices;
using BizHawk.Client.Common;
using BizHawk.Common;
using BizHawk.Common.CollectionExtensions;
using static BizHawk.Common.RawInputImports;
using static BizHawk.Common.WmImports;
@ -35,7 +34,7 @@ namespace BizHawk.Bizware.Input
{
var wc = default(WNDCLASS);
wc.lpfnWndProc = _wndProc;
wc.hInstance = Win32Imports.GetModuleHandle(null);
wc.hInstance = LoaderApiImports.GetModuleHandleW(null);
wc.lpszClassName = "RawKeyInputClass";
var atom = RegisterClass(ref wc);
@ -128,7 +127,7 @@ namespace BizHawk.Bizware.Input
nHeight: 1,
hWndParent: HWND_MESSAGE,
hMenu: IntPtr.Zero,
hInstance: Win32Imports.GetModuleHandle(null),
hInstance: LoaderApiImports.GetModuleHandleW(null),
lpParam: IntPtr.Zero);
if (window == IntPtr.Zero)

View File

@ -6,6 +6,7 @@
<PropertyGroup>
<ApplicationIcon>discohawk.ico</ApplicationIcon>
<Nullable>disable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="System.Windows.Forms" />

View File

@ -119,6 +119,8 @@ namespace BizHawk.Common
private class UnixMonoLLManager : ILinkedLibManager
{
private const int RTLD_NOW = 2;
[DllImport("libdl.so.2")]
private static extern int dlclose(IntPtr handle);
@ -155,40 +157,24 @@ namespace BizHawk.Common
public string GetErrorMessage()
{
var errCharPtr = dlerror();
return errCharPtr == IntPtr.Zero ? "No error present" : Marshal.PtrToStringAnsi(errCharPtr);
return errCharPtr == IntPtr.Zero ? "No error present" : Marshal.PtrToStringAnsi(errCharPtr)!;
}
private const int RTLD_NOW = 2;
}
private class WindowsLLManager : ILinkedLibManager
{
// comments reference extern functions removed from SevenZip.NativeMethods
// functions taken from LoaderApiImports
// TODO: Should we apply the same EXE_PROJECT hack to that file?
[DllImport("kernel32.dll")]
private static extern bool FreeLibrary(IntPtr hModule); // return type was annotated MarshalAs(UnmanagedType.Bool)
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
private static extern IntPtr LoadLibraryW(string lpLibFileName);
[DllImport("kernel32.dll")]
private static extern uint GetLastError();
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool FreeLibrary(IntPtr hLibModule);
private enum FORMAT_MESSAGE : uint
{
ALLOCATE_BUFFER = 0x00000100,
IGNORE_INSERTS = 0x00000200,
FROM_SYSTEM = 0x00001000,
}
[DllImport("kernel32.dll")]
private static extern int FormatMessageA(FORMAT_MESSAGE flags, IntPtr source, uint messageId, uint languageId, out IntPtr outMsg, int size, IntPtr args);
[DllImport("kernel32.dll")]
private static extern IntPtr LocalFree(IntPtr hMem); // use this to free a message from FORMAT_MESSAGE.ALLOCATE_BUFFER
[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", SetLastError = true)] // had BestFitMapping = false, ThrowOnUnmappableChar = true
private static extern IntPtr LoadLibrary(string dllToLoad); // param dllToLoad was annotated `[MarshalAs(UnmanagedType.LPStr)]`
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
public int FreeByPtr(IntPtr hModule) => FreeLibrary(hModule) ? 0 : 1;
@ -197,25 +183,30 @@ namespace BizHawk.Common
public IntPtr GetProcAddrOrThrow(IntPtr hModule, string procName)
{
var ret = GetProcAddrOrZero(hModule, procName);
return ret != IntPtr.Zero ? ret : throw new InvalidOperationException($"got null pointer from {nameof(GetProcAddress)}, error code: {GetLastError()}");
return ret != IntPtr.Zero ? ret : throw new InvalidOperationException($"got null pointer from {nameof(GetProcAddress)}, {GetErrorMessage()}");
}
public IntPtr LoadOrZero(string dllToLoad) => LoadLibrary(dllToLoad);
public IntPtr LoadOrZero(string dllToLoad) => LoadLibraryW(dllToLoad);
public IntPtr LoadOrThrow(string dllToLoad)
{
var ret = LoadOrZero(dllToLoad);
return ret != IntPtr.Zero ? ret : throw new InvalidOperationException($"got null pointer from {nameof(LoadLibrary)}, error code: {GetLastError()}");
return ret != IntPtr.Zero ? ret : throw new InvalidOperationException($"got null pointer from {nameof(LoadLibraryW)}, {GetErrorMessage()}");
}
public string GetErrorMessage()
[DllImport("kernel32.dll", ExactSpelling = true)]
private static extern uint GetLastError();
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
private static extern unsafe int FormatMessageW(int flags, IntPtr source, uint messageId, uint languageId, char* outMsg, int size, IntPtr args);
public unsafe string GetErrorMessage()
{
var errCode = GetLastError();
var sz = FormatMessageA(FORMAT_MESSAGE.ALLOCATE_BUFFER | FORMAT_MESSAGE.FROM_SYSTEM | FORMAT_MESSAGE.IGNORE_INSERTS,
IntPtr.Zero, errCode, 0, out var buffer, 1024, IntPtr.Zero);
var ret = Marshal.PtrToStringAnsi(buffer, sz);
_ = LocalFree(buffer);
return ret;
var buffer = stackalloc char[1024];
const int FORMAT_MESSAGE_FROM_SYSTEM = 0x1000;
var sz = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, IntPtr.Zero, errCode, 0, buffer, 1024, IntPtr.Zero);
return $"error code: 0x{errCode:X8}, error message: {new string(buffer, 0, sz)}";
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Runtime.InteropServices;
namespace BizHawk.Common
{
public static class LoaderApiImports
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
public static extern IntPtr GetModuleHandleW(string? lpModuleName);
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
public static extern IntPtr LoadLibraryW(string lpLibFileName);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FreeLibrary(IntPtr hLibModule);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, IntPtr lpProcName);
}
}

View File

@ -17,9 +17,6 @@ namespace BizHawk.Common
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
public static extern bool DeleteFileW([MarshalAs(UnmanagedType.LPWStr)] string lpFileName);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern uint MapVirtualKey(uint uCode, uint uMapType);