Congregate, organise, and cleanup some Win32 imports and their usages
This commit is contained in:
parent
7149b0ef65
commit
7ea8fb185a
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/// <remarks>http://stackoverflow.com/questions/139010/how-to-resolve-a-lnk-in-c-sharp</remarks>
|
||||
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?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,6 @@ namespace BizHawk.Client.EmuHawk
|
|||
private static readonly List<GamePad360> _devices = new List<GamePad360>();
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -266,7 +266,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
sortedFiles.Add(value, new List<FileInformation>());
|
||||
}
|
||||
|
||||
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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<uint, uint> TimeBeginPeriod = OSTailoredCode.IsUnixHost
|
||||
? u => u
|
||||
: (Func<uint, uint>) Win32Imports.timeBeginPeriod;
|
||||
|
||||
static readonly int tmethod;
|
||||
static readonly ulong afsfreq;
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -97,7 +97,11 @@
|
|||
<Compile Include="TempFileManager.cs" />
|
||||
<Compile Include="UndoHistory.cs" />
|
||||
<Compile Include="Util.cs" />
|
||||
<Compile Include="Win32Hacks.cs" />
|
||||
<Compile Include="Win32/MotWHack.cs" />
|
||||
<Compile Include="Win32/ProcessorFeatureImports.cs" />
|
||||
<Compile Include="Win32/ShellLinkImports.cs" />
|
||||
<Compile Include="Win32/ThreadHacks.cs" />
|
||||
<Compile Include="Win32/Win32Imports.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
|
|
|
@ -519,16 +519,6 @@ namespace BizHawk.Common
|
|||
|
||||
return $"{root}|{member}";
|
||||
}
|
||||
|
||||
public static IEnumerable<string> Util_ResolveLinks(IEnumerable<string> paths)
|
||||
{
|
||||
return paths.Select(f => Win32PInvokes.ResolveShortcut(f));
|
||||
}
|
||||
|
||||
public static string Util_ResolveLink(string path)
|
||||
{
|
||||
return Win32PInvokes.ResolveShortcut(path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
namespace BizHawk.Common
|
||||
{
|
||||
/// <remarks>This code (and an import for <see cref="Win32Imports.DeleteFileW"/>) is duplicated in each executable project because it needs to be used before loading assemblies.</remarks>
|
||||
public static class MotWHack
|
||||
{
|
||||
public static void RemoveMOTW(string path) => Win32Imports.DeleteFileW($"{path}:Zone.Identifier");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace BizHawk.Common
|
||||
{
|
||||
/// <remarks>used by commented-out code in LibretroApi ctor, don't delete</remarks>
|
||||
public static class ProcessorFeatureImports
|
||||
{
|
||||
[DllImport("kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool IsProcessorFeaturePresent(ProcessorFeature processorFeature);
|
||||
|
||||
public enum ProcessorFeature : uint
|
||||
{
|
||||
/// <summary>The MMX instruction set is available</summary>
|
||||
InstructionsMMXAvailable = 3,
|
||||
/// <summary>The SSE instruction set is available</summary>
|
||||
InstructionsXMMIAvailable = 6,
|
||||
/// <summary>The SSE2 instruction set is available</summary>
|
||||
InstructionsXMMI64Available = 10,
|
||||
/// <summary>The SSE3 instruction set is available. (This feature is not supported until Windows Vista)</summary>
|
||||
InstructionsSSE3Available = 13
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 {}
|
||||
|
||||
/// <summary>The IShellLink interface allows Shell links to be created, modified, and resolved</summary>
|
||||
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")]
|
||||
public interface IShellLinkW
|
||||
{
|
||||
/// <summary>Retrieves the path and file name of a Shell link object</summary>
|
||||
void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out WIN32_FIND_DATAW pfd, SLGP_FLAGS fFlags);
|
||||
/// <summary>Retrieves the list of item identifiers for a Shell link object</summary>
|
||||
void GetIDList(out IntPtr ppidl);
|
||||
/// <summary>Sets the pointer to an item identifier list (PIDL) for a Shell link object.</summary>
|
||||
void SetIDList(IntPtr pidl);
|
||||
/// <summary>Retrieves the description string for a Shell link object</summary>
|
||||
void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
|
||||
/// <summary>Sets the description for a Shell link object. The description can be any application-defined string</summary>
|
||||
void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
|
||||
/// <summary>Retrieves the name of the working directory for a Shell link object</summary>
|
||||
void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
|
||||
/// <summary>Sets the name of the working directory for a Shell link object</summary>
|
||||
void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
|
||||
/// <summary>Retrieves the command-line arguments associated with a Shell link object</summary>
|
||||
void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
|
||||
/// <summary>Sets the command-line arguments for a Shell link object</summary>
|
||||
void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
|
||||
/// <summary>Retrieves the hot key for a Shell link object</summary>
|
||||
void GetHotkey(out short pwHotkey);
|
||||
/// <summary>Sets a hot key for a Shell link object</summary>
|
||||
void SetHotkey(short wHotkey);
|
||||
/// <summary>Retrieves the show command for a Shell link object</summary>
|
||||
void GetShowCmd(out int piShowCmd);
|
||||
/// <summary>Sets the show command for a Shell link object. The show command sets the initial show state of the window.</summary>
|
||||
void SetShowCmd(int iShowCmd);
|
||||
/// <summary>Retrieves the location (path and index) of the icon for a Shell link object</summary>
|
||||
void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon);
|
||||
/// <summary>Sets the location (path and index) of the icon for a Shell link object</summary>
|
||||
void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
|
||||
/// <summary>Sets the relative path to the Shell link object</summary>
|
||||
void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
|
||||
/// <summary>Attempts to find the target of a Shell link, even if it has been moved or renamed</summary>
|
||||
void Resolve(IntPtr hwnd, SLR_FLAGS fFlags);
|
||||
/// <summary>Sets the path and file name of a Shell link object</summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <remarks>CLSID_ShellLink from ShlGuid.h</remarks>
|
||||
[ComImport, Guid("00021401-0000-0000-C000-000000000046")]
|
||||
public class ShellLink /* : IPersistFile, IShellLinkW */ {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace BizHawk.Common
|
||||
{
|
||||
/// <remarks>
|
||||
/// largely from https://raw.githubusercontent.com/noserati/tpl/master/ThreadAffinityTaskScheduler.cs (MIT license)<br/>
|
||||
/// most of this is used in <c>#if false</c> code in <c>mupen64plusApi.frame_advance()</c>, don't delete it
|
||||
/// </remarks>
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
/// <remarks>used in <c>#if false</c> code in <c>AviWriter.CodecToken.DeallocateAVICOMPRESSOPTIONS</c>, don't delete it</remarks>
|
||||
[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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
/// <summary>Retrieves the standard short (8.3 format) file name</summary>
|
||||
SLGP_SHORTPATH = 0x1,
|
||||
/// <summary>Retrieves the Universal Naming Convention (UNC) path name of the file</summary>
|
||||
SLGP_UNCPRIORITY = 0x2,
|
||||
/// <summary>Retrieves the raw path name. A raw path is something that might not exist and may include environment variables that need to be expanded</summary>
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
SLR_NO_UI = 0x1,
|
||||
/// <summary>Obsolete and no longer used</summary>
|
||||
SLR_ANY_MATCH = 0x2,
|
||||
/// <summary>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.</summary>
|
||||
SLR_UPDATE = 0x4,
|
||||
/// <summary>Do not update the link information</summary>
|
||||
SLR_NOUPDATE = 0x8,
|
||||
/// <summary>Do not execute the search heuristics</summary>
|
||||
SLR_NOSEARCH = 0x10,
|
||||
/// <summary>Do not use distributed link tracking</summary>
|
||||
SLR_NOTRACK = 0x20,
|
||||
/// <summary>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.</summary>
|
||||
SLR_NOLINKINFO = 0x40,
|
||||
/// <summary>Call the Microsoft Windows Installer</summary>
|
||||
SLR_INVOKE_MSI = 0x80
|
||||
}
|
||||
|
||||
|
||||
/// <summary>The IShellLink interface allows Shell links to be created, modified, and resolved</summary>
|
||||
[ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")]
|
||||
public interface IShellLinkW
|
||||
{
|
||||
/// <summary>Retrieves the path and file name of a Shell link object</summary>
|
||||
void GetPath([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out WIN32_FIND_DATAW pfd, SLGP_FLAGS fFlags);
|
||||
/// <summary>Retrieves the list of item identifiers for a Shell link object</summary>
|
||||
void GetIDList(out IntPtr ppidl);
|
||||
/// <summary>Sets the pointer to an item identifier list (PIDL) for a Shell link object.</summary>
|
||||
void SetIDList(IntPtr pidl);
|
||||
/// <summary>Retrieves the description string for a Shell link object</summary>
|
||||
void GetDescription([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
|
||||
/// <summary>Sets the description for a Shell link object. The description can be any application-defined string</summary>
|
||||
void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
|
||||
/// <summary>Retrieves the name of the working directory for a Shell link object</summary>
|
||||
void GetWorkingDirectory([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
|
||||
/// <summary>Sets the name of the working directory for a Shell link object</summary>
|
||||
void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
|
||||
/// <summary>Retrieves the command-line arguments associated with a Shell link object</summary>
|
||||
void GetArguments([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
|
||||
/// <summary>Sets the command-line arguments for a Shell link object</summary>
|
||||
void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
|
||||
/// <summary>Retrieves the hot key for a Shell link object</summary>
|
||||
void GetHotkey(out short pwHotkey);
|
||||
/// <summary>Sets a hot key for a Shell link object</summary>
|
||||
void SetHotkey(short wHotkey);
|
||||
/// <summary>Retrieves the show command for a Shell link object</summary>
|
||||
void GetShowCmd(out int piShowCmd);
|
||||
/// <summary>Sets the show command for a Shell link object. The show command sets the initial show state of the window.</summary>
|
||||
void SetShowCmd(int iShowCmd);
|
||||
/// <summary>Retrieves the location (path and index) of the icon for a Shell link object</summary>
|
||||
void GetIconLocation([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
|
||||
int cchIconPath, out int piIcon);
|
||||
/// <summary>Sets the location (path and index) of the icon for a Shell link object</summary>
|
||||
void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
|
||||
/// <summary>Sets the relative path to the Shell link object</summary>
|
||||
void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
|
||||
/// <summary>Attempts to find the target of a Shell link, even if it has been moved or renamed</summary>
|
||||
void Resolve(IntPtr hwnd, SLR_FLAGS fFlags);
|
||||
/// <summary>Sets the path and file name of a Shell link object</summary>
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// On a Pentium, a floating-point precision error can occur in rare circumstances
|
||||
/// </summary>
|
||||
FloatingPointPrecisionErrata = 0,
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
FloatingPointEmulated = 1,
|
||||
/// <summary>
|
||||
/// The atomic compare and exchange operation (cmpxchg) is available
|
||||
/// </summary>
|
||||
CompareExchangeDouble = 2,
|
||||
/// <summary>
|
||||
/// The MMX instruction set is available
|
||||
/// </summary>
|
||||
InstructionsMMXAvailable = 3,
|
||||
/// <summary>
|
||||
/// The SSE instruction set is available
|
||||
/// </summary>
|
||||
InstructionsXMMIAvailable = 6,
|
||||
/// <summary>
|
||||
/// The 3D-Now instruction set is available.
|
||||
/// </summary>
|
||||
Instruction3DNowAvailable = 7,
|
||||
/// <summary>
|
||||
/// The RDTSC instruction is available
|
||||
/// </summary>
|
||||
InstructionRDTSCAvailable = 8,
|
||||
/// <summary>
|
||||
/// The processor is PAE-enabled
|
||||
/// </summary>
|
||||
PAEEnabled = 9,
|
||||
/// <summary>
|
||||
/// The SSE2 instruction set is available
|
||||
/// </summary>
|
||||
InstructionsXMMI64Available = 10,
|
||||
/// <summary>
|
||||
/// Data execution prevention is enabled. (This feature is not supported until Windows XP SP2 and Windows Server 2003 SP1)
|
||||
/// </summary>
|
||||
NXEnabled = 12,
|
||||
/// <summary>
|
||||
/// The SSE3 instruction set is available. (This feature is not supported until Windows Vista)
|
||||
/// </summary>
|
||||
InstructionsSSE3Available = 13,
|
||||
/// <summary>
|
||||
/// The atomic compare and exchange 128-bit operation (cmpxchg16b) is available. (This feature is not supported until Windows Vista)
|
||||
/// </summary>
|
||||
CompareExchange128 = 14,
|
||||
/// <summary>
|
||||
/// The atomic compare 64 and exchange 128-bit operation (cmp8xchg16) is available (This feature is not supported until Windows Vista.)
|
||||
/// </summary>
|
||||
Compare64Exchange128 = 15,
|
||||
/// <summary>
|
||||
/// TBD
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Analyze the result of the native wait API
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// functionally the same as WaitOne, but does not message pump
|
||||
/// </summary>
|
||||
public static void HackyPinvokeWaitOne(WaitHandle handle, uint timeout = 0xFFFFFFFF)
|
||||
{
|
||||
NativeMethods.WaitForSingleObject(handle.SafeWaitHandle, timeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Functionally the same as WaitOne(), but pumps com messa
|
||||
/// </summary>
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue