diff --git a/src/BizHawk.Bizware.Input/DirectX/XGamepad.cs b/src/BizHawk.Bizware.Input/DirectX/XGamepad.cs index c6910ed044..2e982eac3b 100644 --- a/src/BizHawk.Bizware.Input/DirectX/XGamepad.cs +++ b/src/BizHawk.Bizware.Input/DirectX/XGamepad.cs @@ -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(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 _); } diff --git a/src/BizHawk.Bizware.Input/KeyInput/RawKeyInput.cs b/src/BizHawk.Bizware.Input/KeyInput/RawKeyInput.cs index 411d70960e..1c1c29cacd 100644 --- a/src/BizHawk.Bizware.Input/KeyInput/RawKeyInput.cs +++ b/src/BizHawk.Bizware.Input/KeyInput/RawKeyInput.cs @@ -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) diff --git a/src/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj b/src/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj index 60ba414b0a..041d5dde2b 100755 --- a/src/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj +++ b/src/BizHawk.Client.DiscoHawk/BizHawk.Client.DiscoHawk.csproj @@ -6,6 +6,7 @@ discohawk.ico disable + true diff --git a/src/BizHawk.Common/OSTailoredCode.cs b/src/BizHawk.Common/OSTailoredCode.cs index 638d96df74..5083d82ff2 100644 --- a/src/BizHawk.Common/OSTailoredCode.cs +++ b/src/BizHawk.Common/OSTailoredCode.cs @@ -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)}"; } } diff --git a/src/BizHawk.Common/Win32/LoaderApiImports.cs b/src/BizHawk.Common/Win32/LoaderApiImports.cs new file mode 100644 index 0000000000..8788b8788f --- /dev/null +++ b/src/BizHawk.Common/Win32/LoaderApiImports.cs @@ -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); + } +} diff --git a/src/BizHawk.Common/Win32/Win32Imports.cs b/src/BizHawk.Common/Win32/Win32Imports.cs index 99c80251be..df119cc66e 100644 --- a/src/BizHawk.Common/Win32/Win32Imports.cs +++ b/src/BizHawk.Common/Win32/Win32Imports.cs @@ -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);