From 7ea8fb185a3d3457e11631b1b4510b7c65b5ab5b Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Sat, 21 Dec 2019 18:17:43 +1000 Subject: [PATCH] Congregate, organise, and cleanup some Win32 imports and their usages --- .../Classes/ExternalToolManager.cs | 2 +- BizHawk.Client.Common/lua/LuaSandbox.cs | 27 +- BizHawk.Client.EmuHawk/AVOut/AviWriter.cs | 21 +- .../CustomControls/InputWidget.cs | 7 +- BizHawk.Client.EmuHawk/EmuHawkUtil.cs | 19 + BizHawk.Client.EmuHawk/Input/GamePad360.cs | 5 +- .../Input/KeyboardMapping.cs | 6 +- BizHawk.Client.EmuHawk/MainForm.FileLoader.cs | 2 +- BizHawk.Client.EmuHawk/MainForm.cs | 2 +- BizHawk.Client.EmuHawk/ScreenSaver.cs | 22 +- BizHawk.Client.EmuHawk/Throttle.cs | 31 +- .../MultiDiskBundler/MultiDiskFileSelector.cs | 2 +- BizHawk.Common/BizHawk.Common.csproj | 6 +- BizHawk.Common/HawkFile.cs | 10 - BizHawk.Common/TempFileManager.cs | 5 +- BizHawk.Common/Win32/MotWHack.cs | 8 + .../Win32/ProcessorFeatureImports.cs | 24 + BizHawk.Common/Win32/ShellLinkImports.cs | 104 ++++ BizHawk.Common/Win32/ThreadHacks.cs | 47 ++ BizHawk.Common/Win32/Win32Imports.cs | 47 ++ BizHawk.Common/Win32Hacks.cs | 470 ------------------ .../N64/NativeApi/mupen64plusCoreApi.cs | 85 +++- .../Libretro/LibretroApi.cs | 8 +- BizHawk.Emulation.Cores/Waterbox/PeRunner.cs | 2 +- 24 files changed, 366 insertions(+), 596 deletions(-) create mode 100644 BizHawk.Common/Win32/MotWHack.cs create mode 100644 BizHawk.Common/Win32/ProcessorFeatureImports.cs create mode 100644 BizHawk.Common/Win32/ShellLinkImports.cs create mode 100644 BizHawk.Common/Win32/ThreadHacks.cs create mode 100644 BizHawk.Common/Win32/Win32Imports.cs delete mode 100644 BizHawk.Common/Win32Hacks.cs diff --git a/BizHawk.Client.ApiHawk/Classes/ExternalToolManager.cs b/BizHawk.Client.ApiHawk/Classes/ExternalToolManager.cs index 8565448739..01c1c104be 100644 --- a/BizHawk.Client.ApiHawk/Classes/ExternalToolManager.cs +++ b/BizHawk.Client.ApiHawk/Classes/ExternalToolManager.cs @@ -85,7 +85,7 @@ namespace BizHawk.Client.ApiHawk try { - BizHawk.Common.Win32Hacks.RemoveMOTW(fileName); + BizHawk.Common.MotWHack.RemoveMOTW(fileName); var externalToolFile = Assembly.LoadFrom(fileName); object[] attributes = externalToolFile.GetCustomAttributes(typeof(BizHawkExternalToolAttribute), false); if (attributes != null && attributes.Count() == 1) diff --git a/BizHawk.Client.Common/lua/LuaSandbox.cs b/BizHawk.Client.Common/lua/LuaSandbox.cs index 9559949d10..ccf28bc50e 100644 --- a/BizHawk.Client.Common/lua/LuaSandbox.cs +++ b/BizHawk.Client.Common/lua/LuaSandbox.cs @@ -21,13 +21,18 @@ namespace BizHawk.Client.Common private string _currentDirectory; - [DllImport("kernel32.dll", SetLastError = true)] - static extern bool SetCurrentDirectoryW(byte* lpPathName); - [DllImport("kernel32.dll", SetLastError=true)] - static extern uint GetCurrentDirectoryW(uint nBufferLength, byte* pBuffer); - private bool CoolSetCurrentDirectory(string path, string currDirSpeedHack = null) { + static string CoolGetCurrentDirectory() + { + if (OSTailoredCode.IsUnixHost) return Environment.CurrentDirectory; + + //HACK to bypass Windows security checks triggered by *getting* the current directory (why), which only slow us down + var buf = new byte[32768]; + fixed (byte* pBuf = &buf[0]) + return System.Text.Encoding.Unicode.GetString(buf, 0, 2 * (int) Win32Imports.GetCurrentDirectoryW(32767, pBuf)); + } + string target = $"{_currentDirectory}\\"; // first we'll bypass it with a general hack: don't do any setting if the value's already there (even at the OS level, setting the directory can be slow) @@ -56,17 +61,7 @@ namespace BizHawk.Client.Common //HACK to bypass Windows security checks triggered by setting the current directory, which only slow us down fixed (byte* pstr = &System.Text.Encoding.Unicode.GetBytes($"{target}\0")[0]) - return SetCurrentDirectoryW(pstr); - } - - private string CoolGetCurrentDirectory() - { - if (OSTailoredCode.IsUnixHost) return Environment.CurrentDirectory; - - //HACK to bypass Windows security checks triggered by *getting* the current directory (why), which only slow us down - var buf = new byte[32768]; - fixed (byte* pBuf = &buf[0]) - return System.Text.Encoding.Unicode.GetString(buf, 0, 2 * (int) GetCurrentDirectoryW(32767, pBuf)); + return Win32Imports.SetCurrentDirectoryW(pstr); } private void Sandbox(Action callback, Action exceptionCallback) diff --git a/BizHawk.Client.EmuHawk/AVOut/AviWriter.cs b/BizHawk.Client.EmuHawk/AVOut/AviWriter.cs index 706382c3ec..4501278523 100644 --- a/BizHawk.Client.EmuHawk/AVOut/AviWriter.cs +++ b/BizHawk.Client.EmuHawk/AVOut/AviWriter.cs @@ -5,6 +5,7 @@ using System.Runtime.InteropServices; using System.Windows.Forms; using BizHawk.Client.Common; +using BizHawk.Common; using BizHawk.Emulation.Common; // some helpful p/invoke from http://www.codeproject.com/KB/audio-video/Motion_Detection.aspx?msg=1142967 @@ -434,20 +435,12 @@ namespace BizHawk.Client.EmuHawk return ret; } - [DllImport("kernel32.dll", SetLastError = true)] - public static extern bool HeapFree(IntPtr hHeap, uint dwFlags, IntPtr lpMem); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern IntPtr GetProcessHeap(); - - [DllImport("kernel32.dll", SetLastError = false)] - public static extern IntPtr HeapAlloc(IntPtr hHeap, uint dwFlags, int dwBytes); - public static void DeallocateAVICOMPRESSOPTIONS(ref Win32.AVICOMPRESSOPTIONS opts) { - // test: increase stability by never freeing anything, ever - // if (opts.lpParms != IntPtr.Zero) CodecToken.HeapFree(CodecToken.GetProcessHeap(), 0, opts.lpParms); - // if (opts.lpFormat != IntPtr.Zero) CodecToken.HeapFree(CodecToken.GetProcessHeap(), 0, opts.lpFormat); +#if false // test: increase stability by never freeing anything, ever + if (opts.lpParms != IntPtr.Zero) Win32Imports.HeapFree(Win32Imports.GetProcessHeap(), 0, opts.lpParms); + if (opts.lpFormat != IntPtr.Zero) Win32Imports.HeapFree(Win32Imports.GetProcessHeap(), 0, opts.lpFormat); +#endif opts.lpParms = IntPtr.Zero; opts.lpFormat = IntPtr.Zero; } @@ -457,12 +450,12 @@ namespace BizHawk.Client.EmuHawk opts = comprOptions; if (opts.cbParms != 0) { - opts.lpParms = HeapAlloc(GetProcessHeap(), 0, opts.cbParms); + opts.lpParms = Win32Imports.HeapAlloc(Win32Imports.GetProcessHeap(), 0, opts.cbParms); Marshal.Copy(Parms, 0, opts.lpParms, opts.cbParms); } if (opts.cbFormat != 0) { - opts.lpFormat = HeapAlloc(GetProcessHeap(), 0, opts.cbFormat); + opts.lpFormat = Win32Imports.HeapAlloc(Win32Imports.GetProcessHeap(), 0, opts.cbFormat); Marshal.Copy(Format, 0, opts.lpFormat, opts.cbFormat); } } diff --git a/BizHawk.Client.EmuHawk/CustomControls/InputWidget.cs b/BizHawk.Client.EmuHawk/CustomControls/InputWidget.cs index 9599e544e2..0b02272bf7 100644 --- a/BizHawk.Client.EmuHawk/CustomControls/InputWidget.cs +++ b/BizHawk.Client.EmuHawk/CustomControls/InputWidget.cs @@ -62,12 +62,9 @@ namespace BizHawk.Client.EmuHawk } } - [DllImport("user32")] - private static extern bool HideCaret(IntPtr hWnd); - protected override void OnMouseClick(MouseEventArgs e) { - if (!OSTailoredCode.IsUnixHost) HideCaret(Handle); + if (!OSTailoredCode.IsUnixHost) Win32Imports.HideCaret(Handle); base.OnMouseClick(e); } @@ -259,7 +256,7 @@ namespace BizHawk.Client.EmuHawk protected override void OnGotFocus(EventArgs e) { - if (!OSTailoredCode.IsUnixHost) HideCaret(Handle); + if (!OSTailoredCode.IsUnixHost) Win32Imports.HideCaret(Handle); } protected override bool ProcessCmdKey(ref Message msg, Keys keyData) diff --git a/BizHawk.Client.EmuHawk/EmuHawkUtil.cs b/BizHawk.Client.EmuHawk/EmuHawkUtil.cs index ca0879fd32..9d1ae1ad32 100644 --- a/BizHawk.Client.EmuHawk/EmuHawkUtil.cs +++ b/BizHawk.Client.EmuHawk/EmuHawkUtil.cs @@ -1,8 +1,11 @@ using System; using System.Drawing; +using System.IO; +using System.Text; using System.Windows.Forms; using BizHawk.Client.Common; using BizHawk.Client.EmuHawk.CustomControls; +using BizHawk.Common; using BizHawk.Emulation.Common; using Cores = BizHawk.Emulation.Cores; @@ -49,5 +52,21 @@ namespace BizHawk.Client.EmuHawk return true; } + + /// http://stackoverflow.com/questions/139010/how-to-resolve-a-lnk-in-c-sharp + public static string ResolveShortcut(string filename) + { + if (filename.Contains("|") || OSTailoredCode.IsUnixHost || !".lnk".Equals(Path.GetExtension(filename), StringComparison.InvariantCultureIgnoreCase)) return filename; // archive internal files are never shortcuts (and choke when analyzing any further) + var link = new ShellLinkImports.ShellLink(); + const uint STGM_READ = 0; + ((ShellLinkImports.IPersistFile) link).Load(filename, STGM_READ); +#if false + // TODO: if I can get hold of the hwnd call resolve first. This handles moved and renamed files. + ((ShellLinkImports.IShellLinkW) link).Resolve(hwnd, 0); +#endif + var sb = new StringBuilder(Win32Imports.MAX_PATH); + ((ShellLinkImports.IShellLinkW) link).GetPath(sb, sb.Capacity, out _, 0); + return sb.Length == 0 ? filename : sb.ToString(); // maybe? what if it's invalid? + } } } diff --git a/BizHawk.Client.EmuHawk/Input/GamePad360.cs b/BizHawk.Client.EmuHawk/Input/GamePad360.cs index 2d77a44485..e28a5d6833 100644 --- a/BizHawk.Client.EmuHawk/Input/GamePad360.cs +++ b/BizHawk.Client.EmuHawk/Input/GamePad360.cs @@ -16,9 +16,6 @@ namespace BizHawk.Client.EmuHawk private static readonly List _devices = new List(); private static readonly bool _isAvailable; - [DllImport("kernel32", SetLastError = true, EntryPoint = "GetProcAddress")] - static extern IntPtr GetProcAddressOrdinal(IntPtr hModule, IntPtr procName); - delegate uint XInputGetStateExProcDelegate(uint dwUserIndex, out XINPUT_STATE state); static bool HasGetInputStateEx; @@ -61,7 +58,7 @@ namespace BizHawk.Client.EmuHawk { if (HasGetInputStateEx) { - IntPtr proc = GetProcAddressOrdinal(LibraryHandle, new IntPtr(100)); + var proc = BizHawk.Common.Win32Imports.GetProcAddressOrdinal(LibraryHandle, new IntPtr(100)); XInputGetStateExProc = (XInputGetStateExProcDelegate)Marshal.GetDelegateForFunctionPointer(proc, typeof(XInputGetStateExProcDelegate)); } diff --git a/BizHawk.Client.EmuHawk/Input/KeyboardMapping.cs b/BizHawk.Client.EmuHawk/Input/KeyboardMapping.cs index 4e73b5450f..69990fb286 100644 --- a/BizHawk.Client.EmuHawk/Input/KeyboardMapping.cs +++ b/BizHawk.Client.EmuHawk/Input/KeyboardMapping.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Linq; -using System.Runtime.InteropServices; using System.Windows.Forms; using BizHawk.Client.Common; using SlimDX.DirectInput; @@ -9,16 +8,13 @@ namespace BizHawk.Client.EmuHawk { internal static class KeyboardMapping { - [DllImport("user32.dll", CharSet = CharSet.Auto)] - private static extern uint MapVirtualKey(uint uCode, uint uMapType); - private const uint MAPVK_VSC_TO_VK_EX = 0x03; public static Key Handle(Key key) { if (!Global.Config.HandleAlternateKeyboardLayouts) return key; ScanCode inputScanCode = SlimDXScanCodeMap[(int)key]; - Keys virtualKey = (Keys)MapVirtualKey((uint)inputScanCode, MAPVK_VSC_TO_VK_EX); + Keys virtualKey = (Keys)BizHawk.Common.Win32Imports.MapVirtualKey((uint)inputScanCode, MAPVK_VSC_TO_VK_EX); ScanCode standardScanCode = GetStandardScanCode(virtualKey); if (standardScanCode == 0) standardScanCode = inputScanCode; diff --git a/BizHawk.Client.EmuHawk/MainForm.FileLoader.cs b/BizHawk.Client.EmuHawk/MainForm.FileLoader.cs index fa1d499314..52f1a4be75 100644 --- a/BizHawk.Client.EmuHawk/MainForm.FileLoader.cs +++ b/BizHawk.Client.EmuHawk/MainForm.FileLoader.cs @@ -266,7 +266,7 @@ namespace BizHawk.Client.EmuHawk sortedFiles.Add(value, new List()); } - ProcessFileList(HawkFile.Util_ResolveLinks(filePaths), ref sortedFiles); + ProcessFileList(filePaths.Select(EmuHawkUtil.ResolveShortcut), ref sortedFiles); // For each of the different types of item, if there are no items of that type, skip them. // If there is exactly one of that type of item, load it. diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 5b51f947c0..cc9dda8021 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -3644,7 +3644,7 @@ namespace BizHawk.Client.EmuHawk if (args == null) throw new ArgumentNullException(nameof(args)); - path = HawkFile.Util_ResolveLink(path); + path = EmuHawkUtil.ResolveShortcut(path); // if this is the first call to LoadRom (they will come in recursively) then stash the args bool firstCall = false; diff --git a/BizHawk.Client.EmuHawk/ScreenSaver.cs b/BizHawk.Client.EmuHawk/ScreenSaver.cs index 70147bfa75..f9018e2921 100644 --- a/BizHawk.Client.EmuHawk/ScreenSaver.cs +++ b/BizHawk.Client.EmuHawk/ScreenSaver.cs @@ -1,6 +1,4 @@ -using System.Runtime.InteropServices; - -using BizHawk.Common; +using BizHawk.Common; namespace BizHawk.Client.EmuHawk { @@ -17,25 +15,21 @@ namespace BizHawk.Client.EmuHawk private class Win32ScreenBlankTimer : IScreenBlankTimer { - [DllImport("user32.dll", CharSet = CharSet.Auto)] - private static extern bool SystemParametersInfo(int uAction, int uParam, ref int lpvParam, int flags); - - private const int SPI_GETSCREENSAVERTIMEOUT = 14; - private const int SPI_SETSCREENSAVERTIMEOUT = 15; - private const int SPIF_SENDWININICHANGE = 2; - public int Duration { get { - var value = 0; - SystemParametersInfo(SPI_GETSCREENSAVERTIMEOUT, 0, ref value, 0); + const int SPI_GETSCREENSAVERTIMEOUT = 14; + int value = default; + Win32Imports.SystemParametersInfo(SPI_GETSCREENSAVERTIMEOUT, 0, ref value, 0); return value; } set { - var nullVar = 0; - SystemParametersInfo(SPI_SETSCREENSAVERTIMEOUT, value, ref nullVar, SPIF_SENDWININICHANGE); + const int SPI_SETSCREENSAVERTIMEOUT = 15; + const int SPIF_SENDWININICHANGE = 2; + int nullVar = default; + Win32Imports.SystemParametersInfo(SPI_SETSCREENSAVERTIMEOUT, value, ref nullVar, SPIF_SENDWININICHANGE); } } } diff --git a/BizHawk.Client.EmuHawk/Throttle.cs b/BizHawk.Client.EmuHawk/Throttle.cs index 251a2ad408..ce473927b1 100644 --- a/BizHawk.Client.EmuHawk/Throttle.cs +++ b/BizHawk.Client.EmuHawk/Throttle.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics; -using System.Runtime.InteropServices; using System.Threading; using BizHawk.Client.Common; @@ -138,33 +137,9 @@ namespace BizHawk.Client.EmuHawk return (ulong)Environment.TickCount; } - private interface PlatformSpecificSysTimer - { - uint TimeBeginPeriod(uint ms); - } - private class WinSysTimer : PlatformSpecificSysTimer - { - [DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")] - private static extern uint timeBeginPeriod(uint uMilliseconds); - public uint TimeBeginPeriod(uint ms) - { - return timeBeginPeriod(ms); - } - } - private class UnixMonoSysTimer : PlatformSpecificSysTimer - { - public uint TimeBeginPeriod(uint ms) - { - // we are not going to bother trying to set a minimum resolution for periodic timers - // (on linux I don't think you can set this in user code) - return ms; - } - } - static readonly PlatformSpecificSysTimer sysTimer = OSTailoredCode.IsUnixHost ? (PlatformSpecificSysTimer) new UnixMonoSysTimer() : new WinSysTimer(); - static uint TimeBeginPeriod(uint ms) - { - return sysTimer.TimeBeginPeriod(ms); - } + static readonly Func TimeBeginPeriod = OSTailoredCode.IsUnixHost + ? u => u + : (Func) Win32Imports.timeBeginPeriod; static readonly int tmethod; static readonly ulong afsfreq; diff --git a/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskFileSelector.cs b/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskFileSelector.cs index b15ad65787..4028309ca6 100644 --- a/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskFileSelector.cs +++ b/BizHawk.Client.EmuHawk/tools/MultiDiskBundler/MultiDiskFileSelector.cs @@ -91,7 +91,7 @@ namespace BizHawk.Client.EmuHawk try { var file = new FileInfo(ofd.FileName); - var path = BizHawk.Common.HawkFile.Util_ResolveLink(file.FullName); + var path = EmuHawkUtil.ResolveShortcut(file.FullName); using (var hf = new BizHawk.Common.HawkFile(path)) { diff --git a/BizHawk.Common/BizHawk.Common.csproj b/BizHawk.Common/BizHawk.Common.csproj index e791e6fda4..17c37d26de 100644 --- a/BizHawk.Common/BizHawk.Common.csproj +++ b/BizHawk.Common/BizHawk.Common.csproj @@ -97,7 +97,11 @@ - + + + + + diff --git a/BizHawk.Common/HawkFile.cs b/BizHawk.Common/HawkFile.cs index adc5f559eb..0e2c78c3e6 100644 --- a/BizHawk.Common/HawkFile.cs +++ b/BizHawk.Common/HawkFile.cs @@ -519,16 +519,6 @@ namespace BizHawk.Common return $"{root}|{member}"; } - - public static IEnumerable Util_ResolveLinks(IEnumerable paths) - { - return paths.Select(f => Win32PInvokes.ResolveShortcut(f)); - } - - public static string Util_ResolveLink(string path) - { - return Win32PInvokes.ResolveShortcut(path); - } } /// diff --git a/BizHawk.Common/TempFileManager.cs b/BizHawk.Common/TempFileManager.cs index fc2be63a97..5c899fbb21 100644 --- a/BizHawk.Common/TempFileManager.cs +++ b/BizHawk.Common/TempFileManager.cs @@ -59,9 +59,6 @@ namespace BizHawk.Common } } - [DllImport("kernel32.dll", EntryPoint = "DeleteFileW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] - static extern bool DeleteFileW([MarshalAs(UnmanagedType.LPWStr)]string lpFileName); - static void ThreadProc() { //squirrely logic, trying not to create garbage @@ -99,7 +96,7 @@ namespace BizHawk.Common } else { - DeleteFileW(fi.FullName); // SHUT. UP. THE. EXCEPTIONS. + Win32Imports.DeleteFileW(fi.FullName); // SHUT. UP. THE. EXCEPTIONS. } } catch diff --git a/BizHawk.Common/Win32/MotWHack.cs b/BizHawk.Common/Win32/MotWHack.cs new file mode 100644 index 0000000000..0a122cc438 --- /dev/null +++ b/BizHawk.Common/Win32/MotWHack.cs @@ -0,0 +1,8 @@ +namespace BizHawk.Common +{ + /// This code (and an import for ) is duplicated in each executable project because it needs to be used before loading assemblies. + public static class MotWHack + { + public static void RemoveMOTW(string path) => Win32Imports.DeleteFileW($"{path}:Zone.Identifier"); + } +} diff --git a/BizHawk.Common/Win32/ProcessorFeatureImports.cs b/BizHawk.Common/Win32/ProcessorFeatureImports.cs new file mode 100644 index 0000000000..e6082d006d --- /dev/null +++ b/BizHawk.Common/Win32/ProcessorFeatureImports.cs @@ -0,0 +1,24 @@ +using System.Runtime.InteropServices; + +namespace BizHawk.Common +{ + /// used by commented-out code in LibretroApi ctor, don't delete + public static class ProcessorFeatureImports + { + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsProcessorFeaturePresent(ProcessorFeature processorFeature); + + public enum ProcessorFeature : uint + { + /// The MMX instruction set is available + InstructionsMMXAvailable = 3, + /// The SSE instruction set is available + InstructionsXMMIAvailable = 6, + /// The SSE2 instruction set is available + InstructionsXMMI64Available = 10, + /// The SSE3 instruction set is available. (This feature is not supported until Windows Vista) + InstructionsSSE3Available = 13 + } + } +} diff --git a/BizHawk.Common/Win32/ShellLinkImports.cs b/BizHawk.Common/Win32/ShellLinkImports.cs new file mode 100644 index 0000000000..24c88af156 --- /dev/null +++ b/BizHawk.Common/Win32/ShellLinkImports.cs @@ -0,0 +1,104 @@ +using System; +using System.Runtime.InteropServices; +using System.Text; + +namespace BizHawk.Common +{ + public static class ShellLinkImports + { + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public struct WIN32_FIND_DATAW + { + public uint dwFileAttributes; + public long ftCreationTime; + public long ftLastAccessTime; + public long ftLastWriteTime; + public uint nFileSizeHigh; + public uint nFileSizeLow; + public uint dwReserved0; + public uint dwReserved1; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string cFileName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName; + } + + [Flags] + public enum SLGP_FLAGS {} + + [Flags] + public enum SLR_FLAGS {} + + /// The IShellLink interface allows Shell links to be created, modified, and resolved + [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")] + public interface IShellLinkW + { + /// Retrieves the path and file name of a Shell link object + void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out WIN32_FIND_DATAW pfd, SLGP_FLAGS fFlags); + /// Retrieves the list of item identifiers for a Shell link object + void GetIDList(out IntPtr ppidl); + /// Sets the pointer to an item identifier list (PIDL) for a Shell link object. + void SetIDList(IntPtr pidl); + /// Retrieves the description string for a Shell link object + void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName); + /// Sets the description for a Shell link object. The description can be any application-defined string + void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); + /// Retrieves the name of the working directory for a Shell link object + void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); + /// Sets the name of the working directory for a Shell link object + void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); + /// Retrieves the command-line arguments associated with a Shell link object + void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); + /// Sets the command-line arguments for a Shell link object + void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); + /// Retrieves the hot key for a Shell link object + void GetHotkey(out short pwHotkey); + /// Sets a hot key for a Shell link object + void SetHotkey(short wHotkey); + /// Retrieves the show command for a Shell link object + void GetShowCmd(out int piShowCmd); + /// Sets the show command for a Shell link object. The show command sets the initial show state of the window. + void SetShowCmd(int iShowCmd); + /// Retrieves the location (path and index) of the icon for a Shell link object + void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon); + /// Sets the location (path and index) of the icon for a Shell link object + void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); + /// Sets the relative path to the Shell link object + void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved); + /// Attempts to find the target of a Shell link, even if it has been moved or renamed + void Resolve(IntPtr hwnd, SLR_FLAGS fFlags); + /// Sets the path and file name of a Shell link object + void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); + } + + [ComImport, Guid("0000010c-0000-0000-c000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IPersist + { + [PreserveSig] + void GetClassID(out Guid pClassID); + } + + [ComImport, Guid("0000010b-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface IPersistFile : IPersist + { + new void GetClassID(out Guid pClassID); + + [PreserveSig] + int IsDirty(); + + [PreserveSig] + void Load([In, MarshalAs(UnmanagedType.LPWStr)]string pszFileName, uint dwMode); + + [PreserveSig] + void Save([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName, [In, MarshalAs(UnmanagedType.Bool)] bool fRemember); + + [PreserveSig] + void SaveCompleted([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName); + + [PreserveSig] + void GetCurFile([In, MarshalAs(UnmanagedType.LPWStr)] string ppszFileName); + } + + /// CLSID_ShellLink from ShlGuid.h + [ComImport, Guid("00021401-0000-0000-C000-000000000046")] + public class ShellLink /* : IPersistFile, IShellLinkW */ {} + } +} diff --git a/BizHawk.Common/Win32/ThreadHacks.cs b/BizHawk.Common/Win32/ThreadHacks.cs new file mode 100644 index 0000000000..6dca599ec2 --- /dev/null +++ b/BizHawk.Common/Win32/ThreadHacks.cs @@ -0,0 +1,47 @@ +using System; +using System.Runtime.InteropServices; + +using Microsoft.Win32.SafeHandles; + +namespace BizHawk.Common +{ + /// + /// largely from https://raw.githubusercontent.com/noserati/tpl/master/ThreadAffinityTaskScheduler.cs (MIT license)
+ /// most of this is used in #if false code in mupen64plusApi.frame_advance(), don't delete it + ///
+ public static class ThreadHacks + { + public const uint QS_ALLINPUT = 0x4FFU; + public const uint MWMO_INPUTAVAILABLE = 0x0004U; + public const uint PM_REMOVE = 0x0001U; + + [StructLayout(LayoutKind.Sequential)] + public struct MSG + { + public IntPtr hwnd; + public uint message; + public IntPtr wParam; + public IntPtr lParam; + public uint time; + public int x; + public int y; + } + + [DllImport("user32.dll")] + public static extern IntPtr DispatchMessage([In] ref MSG lpMsg); + + [DllImport("user32.dll", SetLastError = true)] + public static extern uint MsgWaitForMultipleObjectsEx(uint nCount, IntPtr[] pHandles, uint dwMilliseconds, uint dwWakeMask, uint dwFlags); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool TranslateMessage([In] ref MSG lpMsg); + + [DllImport("kernel32", SetLastError = true, ExactSpelling = true)] + public static extern int WaitForSingleObject(SafeWaitHandle handle, uint milliseconds); + } +} diff --git a/BizHawk.Common/Win32/Win32Imports.cs b/BizHawk.Common/Win32/Win32Imports.cs new file mode 100644 index 0000000000..192dce9459 --- /dev/null +++ b/BizHawk.Common/Win32/Win32Imports.cs @@ -0,0 +1,47 @@ +using System; +using System.Runtime.InteropServices; + +namespace BizHawk.Common +{ + public static class Win32Imports + { + public const int MAX_PATH = 260; + + [DllImport("kernel32.dll", EntryPoint = "DeleteFileW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] + public static extern bool DeleteFileW([MarshalAs(UnmanagedType.LPWStr)] string lpFileName); + + [DllImport("kernel32.dll", SetLastError=true)] + public static extern unsafe uint GetCurrentDirectoryW(uint nBufferLength, byte* pBuffer); + + [DllImport("kernel32", SetLastError = true, EntryPoint = "GetProcAddress")] + public static extern IntPtr GetProcAddressOrdinal(IntPtr hModule, IntPtr procName); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern IntPtr GetProcessHeap(); + + [DllImport("kernel32.dll", SetLastError = false)] + public static extern IntPtr HeapAlloc(IntPtr hHeap, uint dwFlags, int dwBytes); + + /// used in #if false code in AviWriter.CodecToken.DeallocateAVICOMPRESSOPTIONS, don't delete it + [DllImport("kernel32.dll", SetLastError = true)] + public static extern bool HeapFree(IntPtr hHeap, uint dwFlags, IntPtr lpMem); + + [DllImport("user32")] + public static extern bool HideCaret(IntPtr hWnd); + + [DllImport("kernel32.dll")] + public static extern bool IsDebuggerPresent(); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern uint MapVirtualKey(uint uCode, uint uMapType); + + [DllImport("kernel32.dll", SetLastError = true)] + public static extern unsafe bool SetCurrentDirectoryW(byte* lpPathName); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + public static extern bool SystemParametersInfo(int uAction, int uParam, ref int lpvParam, int flags); + + [DllImport("winmm.dll", EntryPoint = "timeBeginPeriod")] + public static extern uint timeBeginPeriod(uint uMilliseconds); + } +} diff --git a/BizHawk.Common/Win32Hacks.cs b/BizHawk.Common/Win32Hacks.cs deleted file mode 100644 index 7a20f6a95d..0000000000 --- a/BizHawk.Common/Win32Hacks.cs +++ /dev/null @@ -1,470 +0,0 @@ -using System; -using System.IO; -using System.Text; -using System.Threading; -using System.Runtime.InteropServices; - -namespace BizHawk.Common -{ - static class PInvokes - { - [DllImport("shfolder.dll", CharSet = CharSet.Auto)] - internal static extern int SHGetFolderPath(IntPtr hwndOwner, int nFolder, IntPtr hToken, int dwFlags, StringBuilder lpszPath); - - [Flags()] - public enum SLGP_FLAGS - { - /// Retrieves the standard short (8.3 format) file name - SLGP_SHORTPATH = 0x1, - /// Retrieves the Universal Naming Convention (UNC) path name of the file - SLGP_UNCPRIORITY = 0x2, - /// Retrieves the raw path name. A raw path is something that might not exist and may include environment variables that need to be expanded - SLGP_RAWPATH = 0x4 - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - public struct WIN32_FIND_DATAW - { - public uint dwFileAttributes; - public long ftCreationTime; - public long ftLastAccessTime; - public long ftLastWriteTime; - public uint nFileSizeHigh; - public uint nFileSizeLow; - public uint dwReserved0; - public uint dwReserved1; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string cFileName; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] - public string cAlternateFileName; - } - - [Flags()] - public enum SLR_FLAGS - { - /// - /// Do not display a dialog box if the link cannot be resolved. When SLR_NO_UI is set, - /// the high-order word of fFlags can be set to a time-out value that specifies the - /// maximum amount of time to be spent resolving the link. The function returns if the - /// link cannot be resolved within the time-out duration. If the high-order word is set - /// to zero, the time-out duration will be set to the default value of 3,000 milliseconds - /// (3 seconds). To specify a value, set the high word of fFlags to the desired time-out - /// duration, in milliseconds. - /// - SLR_NO_UI = 0x1, - /// Obsolete and no longer used - SLR_ANY_MATCH = 0x2, - /// If the link object has changed, update its path and list of identifiers. - /// If SLR_UPDATE is set, you do not need to call IPersistFile::IsDirty to determine - /// whether or not the link object has changed. - SLR_UPDATE = 0x4, - /// Do not update the link information - SLR_NOUPDATE = 0x8, - /// Do not execute the search heuristics - SLR_NOSEARCH = 0x10, - /// Do not use distributed link tracking - SLR_NOTRACK = 0x20, - /// Disable distributed link tracking. By default, distributed link tracking tracks - /// removable media across multiple devices based on the volume name. It also uses the - /// Universal Naming Convention (UNC) path to track remote file systems whose drive letter - /// has changed. Setting SLR_NOLINKINFO disables both types of tracking. - SLR_NOLINKINFO = 0x40, - /// Call the Microsoft Windows Installer - SLR_INVOKE_MSI = 0x80 - } - - - /// The IShellLink interface allows Shell links to be created, modified, and resolved - [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")] - public interface IShellLinkW - { - /// Retrieves the path and file name of a Shell link object - void GetPath([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out WIN32_FIND_DATAW pfd, SLGP_FLAGS fFlags); - /// Retrieves the list of item identifiers for a Shell link object - void GetIDList(out IntPtr ppidl); - /// Sets the pointer to an item identifier list (PIDL) for a Shell link object. - void SetIDList(IntPtr pidl); - /// Retrieves the description string for a Shell link object - void GetDescription([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName); - /// Sets the description for a Shell link object. The description can be any application-defined string - void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); - /// Retrieves the name of the working directory for a Shell link object - void GetWorkingDirectory([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); - /// Sets the name of the working directory for a Shell link object - void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); - /// Retrieves the command-line arguments associated with a Shell link object - void GetArguments([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); - /// Sets the command-line arguments for a Shell link object - void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); - /// Retrieves the hot key for a Shell link object - void GetHotkey(out short pwHotkey); - /// Sets a hot key for a Shell link object - void SetHotkey(short wHotkey); - /// Retrieves the show command for a Shell link object - void GetShowCmd(out int piShowCmd); - /// Sets the show command for a Shell link object. The show command sets the initial show state of the window. - void SetShowCmd(int iShowCmd); - /// Retrieves the location (path and index) of the icon for a Shell link object - void GetIconLocation([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, - int cchIconPath, out int piIcon); - /// Sets the location (path and index) of the icon for a Shell link object - void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); - /// Sets the relative path to the Shell link object - void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved); - /// Attempts to find the target of a Shell link, even if it has been moved or renamed - void Resolve(IntPtr hwnd, SLR_FLAGS fFlags); - /// Sets the path and file name of a Shell link object - void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); - - } - - [ComImport, Guid("0000010c-0000-0000-c000-000000000046"), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IPersist - { - [PreserveSig] - void GetClassID(out Guid pClassID); - } - - - [ComImport, Guid("0000010b-0000-0000-C000-000000000046"), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] - public interface IPersistFile : IPersist - { - new void GetClassID(out Guid pClassID); - [PreserveSig] - int IsDirty(); - - [PreserveSig] - void Load([In, MarshalAs(UnmanagedType.LPWStr)]string pszFileName, uint dwMode); - - [PreserveSig] - void Save([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName, - [In, MarshalAs(UnmanagedType.Bool)] bool fRemember); - - [PreserveSig] - void SaveCompleted([In, MarshalAs(UnmanagedType.LPWStr)] string pszFileName); - - [PreserveSig] - void GetCurFile([In, MarshalAs(UnmanagedType.LPWStr)] string ppszFileName); - } - - public const uint STGM_READ = 0; - public const int MAX_PATH = 260; - - // CLSID_ShellLink from ShlGuid.h - [ - ComImport(), - Guid("00021401-0000-0000-C000-000000000046") - ] - public class ShellLink - { - } - } - - public static class Win32PInvokes - { - //http://stackoverflow.com/questions/139010/how-to-resolve-a-lnk-in-c-sharp - public static string ResolveShortcut(string filename) - { - // archive internal files are never shortcuts (and choke when analyzing any further) - if (filename.Contains("|")) - { - return filename; - } - - if (Path.GetExtension(filename).ToLowerInvariant() != ".lnk") - { - return filename; - } - - PInvokes.ShellLink link = new PInvokes.ShellLink(); - ((PInvokes.IPersistFile)link).Load(filename, PInvokes.STGM_READ); - // TODO: if I can get hold of the hwnd call resolve first. This handles moved and renamed files. - // ((IShellLinkW)link).Resolve(hwnd, 0) - StringBuilder sb = new StringBuilder(PInvokes.MAX_PATH); - PInvokes.WIN32_FIND_DATAW data = new PInvokes.WIN32_FIND_DATAW(); - ((PInvokes.IShellLinkW)link).GetPath(sb, sb.Capacity, out data, 0); - - //maybe? what if it's invalid? - if (sb.Length == 0) - return filename; - return sb.ToString(); - } - - [DllImport("kernel32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsProcessorFeaturePresent(ProcessorFeature processorFeature); - - public enum ProcessorFeature : uint - { - /// - /// On a Pentium, a floating-point precision error can occur in rare circumstances - /// - FloatingPointPrecisionErrata = 0, - /// - /// Floating-point operations are emulated using a software emulator. - /// This function returns a nonzero value if floating-point operations are emulated; otherwise, it returns zero. - /// - FloatingPointEmulated = 1, - /// - /// The atomic compare and exchange operation (cmpxchg) is available - /// - CompareExchangeDouble = 2, - /// - /// The MMX instruction set is available - /// - InstructionsMMXAvailable = 3, - /// - /// The SSE instruction set is available - /// - InstructionsXMMIAvailable = 6, - /// - /// The 3D-Now instruction set is available. - /// - Instruction3DNowAvailable = 7, - /// - /// The RDTSC instruction is available - /// - InstructionRDTSCAvailable = 8, - /// - /// The processor is PAE-enabled - /// - PAEEnabled = 9, - /// - /// The SSE2 instruction set is available - /// - InstructionsXMMI64Available = 10, - /// - /// Data execution prevention is enabled. (This feature is not supported until Windows XP SP2 and Windows Server 2003 SP1) - /// - NXEnabled = 12, - /// - /// The SSE3 instruction set is available. (This feature is not supported until Windows Vista) - /// - InstructionsSSE3Available = 13, - /// - /// The atomic compare and exchange 128-bit operation (cmpxchg16b) is available. (This feature is not supported until Windows Vista) - /// - CompareExchange128 = 14, - /// - /// The atomic compare 64 and exchange 128-bit operation (cmp8xchg16) is available (This feature is not supported until Windows Vista.) - /// - Compare64Exchange128 = 15, - /// - /// TBD - /// - ChannelsEnabled = 16, - } - - - - } - - //largely from https://raw.githubusercontent.com/noserati/tpl/master/ThreadAffinityTaskScheduler.cs (MIT license) - public static class Win32ThreadHacks - { - internal static class NativeMethods - { - [DllImport("kernel32", SetLastError = true, ExactSpelling = true)] - public static extern Int32 WaitForSingleObject(Microsoft.Win32.SafeHandles.SafeWaitHandle handle, uint milliseconds); - - public const uint QS_KEY = 0x0001; - public const uint QS_MOUSEMOVE = 0x0002; - public const uint QS_MOUSEBUTTON = 0x0004; - public const uint QS_POSTMESSAGE = 0x0008; - public const uint QS_TIMER = 0x0010; - public const uint QS_PAINT = 0x0020; - public const uint QS_SENDMESSAGE = 0x0040; - public const uint QS_HOTKEY = 0x0080; - public const uint QS_ALLPOSTMESSAGE = 0x0100; - public const uint QS_RAWINPUT = 0x0400; - - public const uint QS_MOUSE = (QS_MOUSEMOVE | QS_MOUSEBUTTON); - public const uint QS_INPUT = (QS_MOUSE | QS_KEY | QS_RAWINPUT); - public const uint QS_ALLEVENTS = (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY); - public const uint QS_ALLINPUT = (QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE); - - public const uint MWMO_INPUTAVAILABLE = 0x0004; - public const uint MWMO_WAITALL = 0x0001; - - public const uint PM_REMOVE = 0x0001; - public const uint PM_NOREMOVE = 0; - - public const uint WAIT_TIMEOUT = 0x00000102; - public const uint WAIT_FAILED = 0xFFFFFFFF; - public const uint INFINITE = 0xFFFFFFFF; - public const uint WAIT_OBJECT_0 = 0; - public const uint WAIT_ABANDONED_0 = 0x00000080; - public const uint WAIT_IO_COMPLETION = 0x000000C0; - - [StructLayout(LayoutKind.Sequential)] - public struct MSG - { - public IntPtr hwnd; - public uint message; - public IntPtr wParam; - public IntPtr lParam; - public uint time; - public int x; - public int y; - } - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool PeekMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg); - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); - - [DllImport("user32.dll")] - public static extern IntPtr DispatchMessage([In] ref MSG lpMsg); - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool TranslateMessage([In] ref MSG lpMsg); - - [DllImport("ole32.dll", PreserveSig = false)] - public static extern void OleInitialize(IntPtr pvReserved); - - [DllImport("ole32.dll", PreserveSig = true)] - public static extern void OleUninitialize(); - - [DllImport("kernel32.dll")] - public static extern uint GetTickCount(); - - [DllImport("user32.dll")] - public static extern uint GetQueueStatus(uint flags); - - [DllImport("user32.dll", SetLastError = true)] - public static extern uint MsgWaitForMultipleObjectsEx( - uint nCount, IntPtr[] pHandles, uint dwMilliseconds, uint dwWakeMask, uint dwFlags); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern uint WaitForMultipleObjects( - uint nCount, IntPtr[] lpHandles, bool bWaitAll, uint dwMilliseconds); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); - - [DllImport("kernel32.dll", SetLastError = true)] - public static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName); - - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool SetEvent(IntPtr hEvent); - - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool CloseHandle(IntPtr hObject); - } - - /// - /// Analyze the result of the native wait API - /// - static bool IsNativeWaitSuccessful(uint count, uint nativeResult, out int managedResult) - { - if (nativeResult == (NativeMethods.WAIT_OBJECT_0 + count)) - { - // a is message pending, only valid for MsgWaitForMultipleObjectsEx - managedResult = unchecked((int)nativeResult); - return false; - } - - if (nativeResult >= NativeMethods.WAIT_OBJECT_0 && nativeResult < (NativeMethods.WAIT_OBJECT_0 + count)) - { - managedResult = unchecked((int)(nativeResult - NativeMethods.WAIT_OBJECT_0)); - return true; - } - - if (nativeResult >= NativeMethods.WAIT_ABANDONED_0 && nativeResult < (NativeMethods.WAIT_ABANDONED_0 + count)) - { - managedResult = unchecked((int)(nativeResult - NativeMethods.WAIT_ABANDONED_0)); - throw new AbandonedMutexException(); - } - - if (nativeResult == NativeMethods.WAIT_TIMEOUT) - { - managedResult = WaitHandle.WaitTimeout; - return false; - } - - throw new InvalidOperationException(); - } - - /// - /// functionally the same as WaitOne, but does not message pump - /// - public static void HackyPinvokeWaitOne(WaitHandle handle, uint timeout = 0xFFFFFFFF) - { - NativeMethods.WaitForSingleObject(handle.SafeWaitHandle, timeout); - } - - /// - /// Functionally the same as WaitOne(), but pumps com messa - /// - public static void HackyComWaitOne(WaitHandle handle) - { - uint nativeResult; // result of the native wait API (WaitForMultipleObjects or MsgWaitForMultipleObjectsEx) - int managedResult; // result to return from WaitHelper - - IntPtr[] waitHandles = new IntPtr[]{ - handle.SafeWaitHandle.DangerousGetHandle() }; - uint count = 1; - - uint QS_MASK = NativeMethods.QS_ALLINPUT; // message queue status - QS_MASK = 0; //bizhawk edit?? did we need any messages here?? apparently not??? - - // the core loop - var msg = new NativeMethods.MSG(); - while (true) - { - // MsgWaitForMultipleObjectsEx with MWMO_INPUTAVAILABLE returns, - // even if there's a message already seen but not removed in the message queue - nativeResult = NativeMethods.MsgWaitForMultipleObjectsEx( - count, waitHandles, - (uint)0xFFFFFFFF, - QS_MASK, - NativeMethods.MWMO_INPUTAVAILABLE); - - if (IsNativeWaitSuccessful(count, nativeResult, out managedResult) || WaitHandle.WaitTimeout == managedResult) - break; - // there is a message, pump and dispatch it - if (NativeMethods.PeekMessage(out msg, IntPtr.Zero, 0, 0, NativeMethods.PM_REMOVE)) - { - NativeMethods.TranslateMessage(ref msg); - NativeMethods.DispatchMessage(ref msg); - } - } - //m64pFrameComplete.WaitOne(); - } - - } - - public static class Win32Hacks - { - [DllImport("kernel32.dll", EntryPoint = "DeleteFileW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)] - static extern bool DeleteFileW([MarshalAs(UnmanagedType.LPWStr)]string lpFileName); - - //warning: youll have to copy this into the main assembly for your exes in order to run it when booting. - //I only put this for use here by external cores - public static void RemoveMOTW(string path) - { - DeleteFileW($"{path}:Zone.Identifier"); - } - - [DllImport("kernel32.dll")] - static extern bool IsDebuggerPresent(); - - public static bool IsDebuggerReallyPresent() - { - return IsDebuggerPresent(); - } - } - -} \ No newline at end of file diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs index 3601c271f3..ab33b1f433 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/NativeApi/mupen64plusCoreApi.cs @@ -711,28 +711,81 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi public void frame_advance() { - if (!emulator_running) - return; +#if false // for alt. method #2 below + static bool IsNativeWaitSuccessful(uint count, uint nativeResult, out int managedResult) + { + const uint WAIT_OBJECT_0 = 0x00000000U; + const uint WAIT_ABANDONED_0 = 0x00000080U; + const uint WAIT_TIMEOUT = 0x00000102U; + if (/* WAIT_OBJECT_0 <= nativeResult && */ nativeResult < WAIT_OBJECT_0 + count) + { + managedResult = unchecked((int) (nativeResult - WAIT_OBJECT_0)); + return true; + } + else if (nativeResult == WAIT_OBJECT_0 + count) + { + // a is message pending, only valid for MsgWaitForMultipleObjectsEx + managedResult = unchecked((int) nativeResult); + return false; + } + else if (WAIT_ABANDONED_0 <= nativeResult && nativeResult < WAIT_ABANDONED_0 + count) + { + managedResult = unchecked((int) (nativeResult - WAIT_ABANDONED_0)); + throw new AbandonedMutexException(); + } + else if (nativeResult == WAIT_TIMEOUT) + { + managedResult = WaitHandle.WaitTimeout; + return false; + } + else + { + throw new InvalidOperationException(); + } + } + + static void HackyComWaitOne(WaitHandle handle) + { + IntPtr[] waitHandles = { handle.SafeWaitHandle.DangerousGetHandle() }; + const uint count = 1; + var QS_MASK = ThreadHacks.QS_ALLINPUT; // message queue status + QS_MASK = 0; //bizhawk edit?? did we need any messages here?? apparently not??? + uint nativeResult; + ThreadHacks.MSG msg; + while (true) + { + // MsgWaitForMultipleObjectsEx with MWMO_INPUTAVAILABLE returns, + // even if there's a message already seen but not removed in the message queue + nativeResult = ThreadHacks.MsgWaitForMultipleObjectsEx(count, waitHandles, 0xFFFFFFFF, QS_MASK, ThreadHacks.MWMO_INPUTAVAILABLE); + if (IsNativeWaitSuccessful(count, nativeResult, out int managedResult) || WaitHandle.WaitTimeout == managedResult) break; + // there is a message, pump and dispatch it + if (ThreadHacks.PeekMessage(out msg, IntPtr.Zero, 0, 0, ThreadHacks.PM_REMOVE)) + { + ThreadHacks.TranslateMessage(ref msg); + ThreadHacks.DispatchMessage(ref msg); + } + } +// handle.WaitOne(); + } +#endif + + if (!emulator_running) return; event_frameend = false; m64pCoreDoCommandPtr(m64p_command.M64CMD_ADVANCE_FRAME, 0, IntPtr.Zero); - //the way we should be able to do it: - //m64pFrameComplete.WaitOne(); - - //however. since this is probably an STAThread, this call results in message pumps running. - //those message pumps are only supposed to respond to critical COM stuff, but in fact they interfere with other things. - //so here are two workaround methods. - - //method 1. - //BizHawk.Common.Win32ThreadHacks.HackyPinvokeWaitOne(m64pFrameComplete); - - //method 2. - //BizHawk.Common.Win32ThreadHacks.HackyComWaitOne(m64pFrameComplete); - for(;;) { - BizHawk.Common.Win32ThreadHacks.HackyPinvokeWaitOne(m64pEvent, 200); +#if false // the way we should be able to do it + m64pEvent.WaitOne(); + // however. since this is probably an STAThread, this call results in message pumps running. + // those message pumps are only supposed to respond to critical COM stuff, but in fact they interfere with other things. + // so here are two workaround methods: +#elif true // alt. method #1 - functionally the same as WaitOne, but does not message pump + ThreadHacks.WaitForSingleObject(m64pEvent.SafeWaitHandle, 200); +#else // alt. method #2 - functionally the same as WaitOne(), but pumps com messages + HackyComWaitOne(m64pEvent); +#endif if (event_frameend) break; if (event_breakpoint) diff --git a/BizHawk.Emulation.Cores/Libretro/LibretroApi.cs b/BizHawk.Emulation.Cores/Libretro/LibretroApi.cs index db2286cd84..ecd25b3354 100644 --- a/BizHawk.Emulation.Cores/Libretro/LibretroApi.cs +++ b/BizHawk.Emulation.Cores/Libretro/LibretroApi.cs @@ -68,10 +68,10 @@ namespace BizHawk.Emulation.Cores.Libretro //ALSO: this should be done by the core, I think, not the API. No smarts should be in here comm->env.retro_perf_callback.get_cpu_features = IntPtr.Zero; //retro_perf_callback.get_cpu_features = new LibRetro.retro_get_cpu_features_t(() => (ulong)( - // (Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsXMMIAvailable) ? LibRetro.RETRO_SIMD.SSE : 0) | - // (Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsXMMI64Available) ? LibRetro.RETRO_SIMD.SSE2 : 0) | - // (Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsSSE3Available) ? LibRetro.RETRO_SIMD.SSE3 : 0) | - // (Win32PInvokes.IsProcessorFeaturePresent(Win32PInvokes.ProcessorFeature.InstructionsMMXAvailable) ? LibRetro.RETRO_SIMD.MMX : 0) + // (ProcessorFeatureImports.IsProcessorFeaturePresent(ProcessorFeatureImports.ProcessorFeature.InstructionsXMMIAvailable) ? LibRetro.RETRO_SIMD.SSE : 0) | + // (ProcessorFeatureImports.IsProcessorFeaturePresent(ProcessorFeatureImports.ProcessorFeature.InstructionsXMMI64Available) ? LibRetro.RETRO_SIMD.SSE2 : 0) | + // (ProcessorFeatureImports.IsProcessorFeaturePresent(ProcessorFeatureImports.ProcessorFeature.InstructionsSSE3Available) ? LibRetro.RETRO_SIMD.SSE3 : 0) | + // (ProcessorFeatureImports.IsProcessorFeaturePresent(ProcessorFeatureImports.ProcessorFeature.InstructionsMMXAvailable) ? LibRetro.RETRO_SIMD.MMX : 0) // )); //retro_perf_callback.get_perf_counter = new LibRetro.retro_perf_get_counter_t(() => System.Diagnostics.Stopwatch.GetTimestamp()); //retro_perf_callback.get_time_usec = new LibRetro.retro_perf_get_time_usec_t(() => DateTime.Now.Ticks / 10); diff --git a/BizHawk.Emulation.Cores/Waterbox/PeRunner.cs b/BizHawk.Emulation.Cores/Waterbox/PeRunner.cs index 68f25da2f4..a39a2b47ab 100644 --- a/BizHawk.Emulation.Cores/Waterbox/PeRunner.cs +++ b/BizHawk.Emulation.Cores/Waterbox/PeRunner.cs @@ -1063,7 +1063,7 @@ namespace BizHawk.Emulation.Cores.Waterbox _syscalls.Init(); Console.WriteLine("About to enter unmanaged code"); - if (Win32Hacks.IsDebuggerReallyPresent() && !System.Diagnostics.Debugger.IsAttached) + if (!OSTailoredCode.IsUnixHost && !System.Diagnostics.Debugger.IsAttached && Win32Imports.IsDebuggerPresent()) { // this means that GDB or another unconventional debugger is attached. // if that's the case, and it's observing this core, it probably wants a break