Merge pull request #1765 from TASVideos/winhacksbgone

Cleaning up and hopefully removing some Win32 hacks
This commit is contained in:
James Groom 2019-12-22 17:09:38 +00:00 committed by GitHub
commit d8eaafd47f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 1154 additions and 1952 deletions

View File

@ -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)

View File

@ -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)

View File

@ -19,7 +19,9 @@ namespace BizHawk.Client.Common
if (DefaultToAWE)
{
return new StreamStringLog(false);
return OSTailoredCode.IsUnixHost
? throw new InvalidOperationException("logging to AWE is only available on Windows for now")
: new StreamStringLog(false);
}
return new ListStringLog();

View File

@ -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
@ -287,7 +288,7 @@ namespace BizHawk.Client.EmuHawk
public int width, height;
public int pitch; //in bytes
public int pitch_add;
public void PopulateBITMAPINFOHEADER24(ref Win32.BITMAPINFOHEADER bmih)
public void PopulateBITMAPINFOHEADER24(ref AVIWriterImports.BITMAPINFOHEADER bmih)
{
bmih.Init();
bmih.biPlanes = 1;
@ -302,7 +303,7 @@ namespace BizHawk.Client.EmuHawk
bmih.biSizeImage = (uint)(pitch * height);
}
public void PopulateBITMAPINFOHEADER32(ref Win32.BITMAPINFOHEADER bmih)
public void PopulateBITMAPINFOHEADER32(ref AVIWriterImports.BITMAPINFOHEADER bmih)
{
bmih.Init();
bmih.biPlanes = 1;
@ -315,8 +316,9 @@ namespace BizHawk.Client.EmuHawk
public bool has_audio;
public int a_samplerate, a_channels, a_bits;
public void PopulateWAVEFORMATEX(ref Win32.WAVEFORMATEX wfex)
public void PopulateWAVEFORMATEX(ref AVIWriterImports.WAVEFORMATEX wfex)
{
const int WAVE_FORMAT_PCM = 1;
int bytes = 0;
if (a_bits == 16) bytes = 2;
else if (a_bits == 8) bytes = 1;
@ -328,7 +330,7 @@ namespace BizHawk.Client.EmuHawk
wfex.nBlockAlign = (ushort)(bytes * a_channels);
wfex.nChannels = (ushort)a_channels;
wfex.wBitsPerSample = (ushort)a_bits;
wfex.wFormatTag = Win32.WAVE_FORMAT_PCM;
wfex.wFormatTag = WAVE_FORMAT_PCM;
wfex.nSamplesPerSec = (uint)a_samplerate;
wfex.nAvgBytesPerSec = (uint)(wfex.nBlockAlign * a_samplerate);
}
@ -406,17 +408,30 @@ namespace BizHawk.Client.EmuHawk
{
public void Dispose() { }
private CodecToken() { }
private Win32.AVICOMPRESSOPTIONS comprOptions;
private AVIWriterImports.AVICOMPRESSOPTIONS comprOptions;
public string codec;
public byte[] Format = new byte[0];
public byte[] Parms = new byte[0];
public static CodecToken CreateFromAVICOMPRESSOPTIONS(ref Win32.AVICOMPRESSOPTIONS opts)
private static string decode_mmioFOURCC(int code)
{
char[] chs = new char[4];
for (int i = 0; i < 4; i++)
{
chs[i] = (char)(byte)((code >> (i << 3)) & 0xFF);
if (!char.IsLetterOrDigit(chs[i]))
chs[i] = ' ';
}
return new string(chs);
}
public static CodecToken CreateFromAVICOMPRESSOPTIONS(ref AVIWriterImports.AVICOMPRESSOPTIONS opts)
{
var ret = new CodecToken
{
comprOptions = opts,
codec = Win32.decode_mmioFOURCC(opts.fccHandler),
codec = decode_mmioFOURCC(opts.fccHandler),
Format = new byte[opts.cbFormat],
Parms = new byte[opts.cbParms]
};
@ -434,35 +449,27 @@ 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)
public static void DeallocateAVICOMPRESSOPTIONS(ref AVIWriterImports.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;
}
public void AllocateToAVICOMPRESSOPTIONS(ref Win32.AVICOMPRESSOPTIONS opts)
public void AllocateToAVICOMPRESSOPTIONS(ref AVIWriterImports.AVICOMPRESSOPTIONS opts)
{
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);
}
}
@ -494,7 +501,7 @@ namespace BizHawk.Client.EmuHawk
var m = new MemoryStream(data, false);
var b = new BinaryReader(m);
Win32.AVICOMPRESSOPTIONS comprOptions = new Win32.AVICOMPRESSOPTIONS();
AVIWriterImports.AVICOMPRESSOPTIONS comprOptions = new AVIWriterImports.AVICOMPRESSOPTIONS();
byte[] Format;
byte[] Parms;
@ -532,7 +539,7 @@ namespace BizHawk.Client.EmuHawk
comprOptions = comprOptions,
Format = Format,
Parms = Parms,
codec = Win32.decode_mmioFOURCC(comprOptions.fccHandler)
codec = decode_mmioFOURCC(comprOptions.fccHandler)
};
return ret;
}
@ -560,7 +567,7 @@ namespace BizHawk.Client.EmuHawk
{
static AviWriterSegment()
{
Win32.AVIFileInit();
AVIWriterImports.AVIFileInit();
}
public AviWriterSegment()
@ -619,20 +626,29 @@ namespace BizHawk.Client.EmuHawk
return outStatus.video_bytes + outStatus.audio_bytes;
}
static unsafe int AVISaveOptions(IntPtr stream, ref Win32.AVICOMPRESSOPTIONS opts, IntPtr owner)
private static bool FAILED(int hr) => hr < 0;
static unsafe int AVISaveOptions(IntPtr stream, ref AVIWriterImports.AVICOMPRESSOPTIONS opts, IntPtr owner)
{
fixed (Win32.AVICOMPRESSOPTIONS* _popts = &opts)
fixed (AVIWriterImports.AVICOMPRESSOPTIONS* _popts = &opts)
{
IntPtr* pStream = &stream;
Win32.AVICOMPRESSOPTIONS* popts = _popts;
Win32.AVICOMPRESSOPTIONS** ppopts = &popts;
return Win32.AVISaveOptions(owner, 0, 1, (void*)pStream, (void*)ppopts);
AVIWriterImports.AVICOMPRESSOPTIONS* popts = _popts;
AVIWriterImports.AVICOMPRESSOPTIONS** ppopts = &popts;
return AVIWriterImports.AVISaveOptions(owner, 0, 1, (void*)pStream, (void*)ppopts);
}
}
Parameters parameters;
public void OpenFile(string destPath, Parameters parameters, CodecToken videoCodecToken)
{
static int mmioFOURCC(string str) => (
((int)(byte)(str[0]))
| ((int)(byte)(str[1]) << 8)
| ((int)(byte)(str[2]) << 16)
| ((int)(byte)(str[3]) << 24)
);
this.parameters = parameters;
this.currVideoCodecToken = videoCodecToken;
@ -644,36 +660,36 @@ namespace BizHawk.Client.EmuHawk
File.Delete(destPath);
}
if (Win32.FAILED(Win32.AVIFileOpenW(ref pAviFile, destPath, Win32.OpenFileStyle.OF_CREATE | Win32.OpenFileStyle.OF_WRITE, 0)))
if (FAILED(AVIWriterImports.AVIFileOpenW(ref pAviFile, destPath, AVIWriterImports.OpenFileStyle.OF_CREATE | AVIWriterImports.OpenFileStyle.OF_WRITE, 0)))
{
throw new InvalidOperationException($"Couldnt open dest path for avi file: {destPath}");
}
// initialize the video stream
Win32.AVISTREAMINFOW vidstream_header = new Win32.AVISTREAMINFOW();
Win32.BITMAPINFOHEADER bmih = new Win32.BITMAPINFOHEADER();
AVIWriterImports.AVISTREAMINFOW vidstream_header = new AVIWriterImports.AVISTREAMINFOW();
AVIWriterImports.BITMAPINFOHEADER bmih = new AVIWriterImports.BITMAPINFOHEADER();
parameters.PopulateBITMAPINFOHEADER24(ref bmih);
vidstream_header.fccType = Win32.mmioFOURCC("vids");
vidstream_header.fccType = mmioFOURCC("vids");
vidstream_header.dwRate = parameters.fps;
vidstream_header.dwScale = parameters.fps_scale;
vidstream_header.dwSuggestedBufferSize = (int)bmih.biSizeImage;
if (Win32.FAILED(Win32.AVIFileCreateStreamW(pAviFile, out pAviRawVideoStream, ref vidstream_header)))
if (FAILED(AVIWriterImports.AVIFileCreateStreamW(pAviFile, out pAviRawVideoStream, ref vidstream_header)))
{
CloseFile();
throw new InvalidOperationException("Failed opening raw video stream. Not sure how this could happen");
}
// initialize audio stream
Win32.AVISTREAMINFOW audstream_header = new Win32.AVISTREAMINFOW();
Win32.WAVEFORMATEX wfex = new Win32.WAVEFORMATEX();
AVIWriterImports.AVISTREAMINFOW audstream_header = new AVIWriterImports.AVISTREAMINFOW();
AVIWriterImports.WAVEFORMATEX wfex = new AVIWriterImports.WAVEFORMATEX();
parameters.PopulateWAVEFORMATEX(ref wfex);
audstream_header.fccType = Win32.mmioFOURCC("auds");
audstream_header.fccType = mmioFOURCC("auds");
audstream_header.dwQuality = -1;
audstream_header.dwScale = wfex.nBlockAlign;
audstream_header.dwRate = (int)wfex.nAvgBytesPerSec;
audstream_header.dwSampleSize = wfex.nBlockAlign;
audstream_header.dwInitialFrames = 1; // ??? optimal value?
if (Win32.FAILED(Win32.AVIFileCreateStreamW(pAviFile, out pAviRawAudioStream, ref audstream_header)))
if (FAILED(AVIWriterImports.AVIFileCreateStreamW(pAviFile, out pAviRawAudioStream, ref audstream_header)))
{
CloseFile();
throw new InvalidOperationException("Failed opening raw audio stream. Not sure how this could happen");
@ -700,7 +716,7 @@ namespace BizHawk.Client.EmuHawk
}
// encoder params
Win32.AVICOMPRESSOPTIONS comprOptions = new Win32.AVICOMPRESSOPTIONS();
AVIWriterImports.AVICOMPRESSOPTIONS comprOptions = new AVIWriterImports.AVICOMPRESSOPTIONS();
currVideoCodecToken?.AllocateToAVICOMPRESSOPTIONS(ref comprOptions);
bool result = AVISaveOptions(pAviRawVideoStream, ref comprOptions, hwnd) != 0;
@ -736,9 +752,9 @@ namespace BizHawk.Client.EmuHawk
}
// open compressed video stream
Win32.AVICOMPRESSOPTIONS opts = new Win32.AVICOMPRESSOPTIONS();
AVIWriterImports.AVICOMPRESSOPTIONS opts = new AVIWriterImports.AVICOMPRESSOPTIONS();
currVideoCodecToken.AllocateToAVICOMPRESSOPTIONS(ref opts);
bool failed = Win32.FAILED(Win32.AVIMakeCompressedStream(out pAviCompressedVideoStream, pAviRawVideoStream, ref opts, IntPtr.Zero));
bool failed = FAILED(AVIWriterImports.AVIMakeCompressedStream(out pAviCompressedVideoStream, pAviRawVideoStream, ref opts, IntPtr.Zero));
CodecToken.DeallocateAVICOMPRESSOPTIONS(ref opts);
if (failed)
@ -748,7 +764,7 @@ namespace BizHawk.Client.EmuHawk
}
// set the compressed video stream input format
Win32.BITMAPINFOHEADER bmih = new Win32.BITMAPINFOHEADER();
AVIWriterImports.BITMAPINFOHEADER bmih = new AVIWriterImports.BITMAPINFOHEADER();
if (bit32)
{
parameters.PopulateBITMAPINFOHEADER32(ref bmih);
@ -758,7 +774,7 @@ namespace BizHawk.Client.EmuHawk
parameters.PopulateBITMAPINFOHEADER24(ref bmih);
}
if (Win32.FAILED(Win32.AVIStreamSetFormat(pAviCompressedVideoStream, 0, ref bmih, Marshal.SizeOf(bmih))))
if (FAILED(AVIWriterImports.AVIStreamSetFormat(pAviCompressedVideoStream, 0, ref bmih, Marshal.SizeOf(bmih))))
{
bit32 = true; // we'll try again
CloseStreams();
@ -766,9 +782,9 @@ namespace BizHawk.Client.EmuHawk
}
// set audio stream input format
Win32.WAVEFORMATEX wfex = new Win32.WAVEFORMATEX();
AVIWriterImports.WAVEFORMATEX wfex = new AVIWriterImports.WAVEFORMATEX();
parameters.PopulateWAVEFORMATEX(ref wfex);
if (Win32.FAILED(Win32.AVIStreamSetFormat(pAviRawAudioStream, 0, ref wfex, Marshal.SizeOf(wfex))))
if (FAILED(AVIWriterImports.AVIStreamSetFormat(pAviRawAudioStream, 0, ref wfex, Marshal.SizeOf(wfex))))
{
CloseStreams();
throw new InvalidOperationException("Failed setting raw audio stream input format");
@ -783,19 +799,19 @@ namespace BizHawk.Client.EmuHawk
CloseStreams();
if (pAviRawAudioStream != IntPtr.Zero)
{
Win32.AVIStreamRelease(pAviRawAudioStream);
AVIWriterImports.AVIStreamRelease(pAviRawAudioStream);
pAviRawAudioStream = IntPtr.Zero;
}
if (pAviRawVideoStream != IntPtr.Zero)
{
Win32.AVIStreamRelease(pAviRawVideoStream);
AVIWriterImports.AVIStreamRelease(pAviRawVideoStream);
pAviRawVideoStream = IntPtr.Zero;
}
if (pAviFile != IntPtr.Zero)
{
Win32.AVIFileRelease(pAviFile);
AVIWriterImports.AVIFileRelease(pAviFile);
pAviFile = IntPtr.Zero;
}
@ -819,7 +835,7 @@ namespace BizHawk.Client.EmuHawk
if (pAviCompressedVideoStream != IntPtr.Zero)
{
Win32.AVIStreamRelease(pAviCompressedVideoStream);
AVIWriterImports.AVIStreamRelease(pAviCompressedVideoStream);
pAviCompressedVideoStream = IntPtr.Zero;
}
}
@ -860,7 +876,7 @@ namespace BizHawk.Client.EmuHawk
// (TODO - inefficient- build directly in a buffer)
int bytes_written;
Win32.AVIStreamWrite(pAviRawAudioStream, outStatus.audio_samples, todo_realsamples, buf, todo_realsamples * 4, 0, IntPtr.Zero, out bytes_written);
AVIWriterImports.AVIStreamWrite(pAviRawAudioStream, outStatus.audio_samples, todo_realsamples, buf, todo_realsamples * 4, 0, IntPtr.Zero, out bytes_written);
outStatus.audio_samples += todo_realsamples;
outStatus.audio_bytes += bytes_written;
outStatus.audio_buffered_shorts = 0;
@ -868,6 +884,8 @@ namespace BizHawk.Client.EmuHawk
public unsafe void AddFrame(IVideoProvider source)
{
const int AVIIF_KEYFRAME = 0x00000010;
if (parameters.width != source.BufferWidth
|| parameters.height != source.BufferHeight)
throw new InvalidOperationException("video buffer changed between start and now");
@ -906,7 +924,7 @@ namespace BizHawk.Client.EmuHawk
}
int bytes_written;
int ret = Win32.AVIStreamWrite(pAviCompressedVideoStream, outStatus.video_frames, 1, new IntPtr(bytes_ptr), todo, Win32.AVIIF_KEYFRAME, IntPtr.Zero, out bytes_written);
int ret = AVIWriterImports.AVIStreamWrite(pAviCompressedVideoStream, outStatus.video_frames, 1, new IntPtr(bytes_ptr), todo, AVIIF_KEYFRAME, IntPtr.Zero, out bytes_written);
outStatus.video_bytes += bytes_written;
outStatus.video_frames++;
}
@ -938,7 +956,7 @@ namespace BizHawk.Client.EmuHawk
}
int bytes_written;
int ret = Win32.AVIStreamWrite(pAviCompressedVideoStream, outStatus.video_frames, 1, new IntPtr(bytes_ptr), todo * 3, Win32.AVIIF_KEYFRAME, IntPtr.Zero, out bytes_written);
int ret = AVIWriterImports.AVIStreamWrite(pAviCompressedVideoStream, outStatus.video_frames, 1, new IntPtr(bytes_ptr), todo * 3, AVIIF_KEYFRAME, IntPtr.Zero, out bytes_written);
outStatus.video_bytes += bytes_written;
outStatus.video_frames++;
}

View File

@ -620,7 +620,6 @@
<Compile Include="CustomControls\ViewportPanel.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="CustomControls\Win32.cs" />
<Compile Include="DisplayManager\DisplayManager.cs" />
<Compile Include="DisplayManager\DisplaySurface.cs" />
<Compile Include="DisplayManager\FilterManager.cs" />

View File

@ -1,248 +1,85 @@
using System.Runtime.InteropServices;
using System.Text;
using System;
using System.Windows.Forms;
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
//I believe this code is from http://support.microsoft.com/kb/306285
//The license is assumed to be effectively public domain.
//I saw a version of it with at least one bug fixed at https://github.com/slavat/MailSystem.NET/blob/master/Queuing%20System/ActiveQLibrary/CustomControl/FolderBrowser.cs
using BizHawk.Common;
namespace BizHawk.Client.EmuHawk
{
/// <summary>
/// Component wrapping access to the Browse For Folder common dialog box.
/// Call the ShowDialog() method to bring the dialog box up.
/// </summary>
/// <remarks>
/// I believe this code is from http://support.microsoft.com/kb/306285<br/>
/// The license is assumed to be effectively public domain.<br/>
/// I saw a version of it with at least one bug fixed at https://github.com/slavat/MailSystem.NET/blob/master/Queuing%20System/ActiveQLibrary/CustomControl/FolderBrowser.cs<br/>
/// --zeromus
/// </remarks>
public sealed class FolderBrowserEx : Component
{
private const int MAX_PATH = 260;
/// <remarks>is this supposed to be public? we're obviously not using it at callsites at the moment --yoshi</remarks>
private Win32Imports.BROWSEINFO.FLAGS publicOptions = Win32Imports.BROWSEINFO.FLAGS.RestrictToFilesystem | Win32Imports.BROWSEINFO.FLAGS.RestrictToDomain;
// Root node of the tree view.
private FolderID startLocation = FolderID.Desktop;
// Browse info options.
private int publicOptions = (int) Win32API.Shell32.BffStyles.RestrictToFilesystem |
(int) Win32API.Shell32.BffStyles.RestrictToDomain;
private const int privateOptions = (int) (Win32API.Shell32.BffStyles.NewDialogStyle | Win32API.Shell32.BffStyles.ShowTextBox);
// Description text to show.
public string Description = "Please select a folder below:";
/// <summary>
/// Enum of CSIDLs identifying standard shell folders.
/// </summary>
public enum FolderID
{
Desktop = 0x0000,
Printers = 0x0004,
MyDocuments = 0x0005,
Favorites = 0x0006,
Recent = 0x0008,
SendTo = 0x0009,
StartMenu = 0x000b,
MyComputer = 0x0011,
NetworkNeighborhood = 0x0012,
Templates = 0x0015,
MyPictures = 0x0027,
NetAndDialUpConnections = 0x0031,
}
public string SelectedPath;
/// <summary>
/// Helper function that returns the IMalloc interface used by the shell.
/// </summary>
private static Win32API.IMalloc GetShMalloc()
/// <summary>Shows the folder browser dialog box with the specified owner window.</summary>
public DialogResult ShowDialog(IWin32Window owner = null)
{
Win32API.Shell32.SHGetMalloc(out var malloc);
return malloc;
}
/// <summary>
/// Shows the folder browser dialog box.
/// </summary>
public DialogResult ShowDialog()
{
return ShowDialog(null);
}
private int Callback(IntPtr hwnd, uint uMsg, IntPtr lParam, IntPtr lpData)
{
switch (uMsg)
const Win32Imports.BROWSEINFO.FLAGS privateOptions = Win32Imports.BROWSEINFO.FLAGS.NewDialogStyle | Win32Imports.BROWSEINFO.FLAGS.ShowTextBox;
const int startLocation = 0; // = Desktop CSIDL
int Callback(IntPtr hwnd, uint uMsg, IntPtr lParam, IntPtr lpData)
{
case 1:
IntPtr str = Marshal.StringToHGlobalUni(SelectedPath);
Win32.SendMessage(hwnd, 0x400 + 103, (IntPtr)1, str);
Marshal.FreeHGlobal(str);
break;
}
return 0;
}
/// <summary>
/// Shows the folder browser dialog box with the specified owner window.
/// </summary>
public DialogResult ShowDialog(IWin32Window owner)
{
IntPtr pidlRoot = IntPtr.Zero;
// Get/find an owner HWND for this dialog.
var hWndOwner = owner?.Handle ?? Win32API.GetActiveWindow();
// Get the IDL for the specific startLocation.
Win32API.Shell32.SHGetSpecialFolderLocation(hWndOwner, (int) startLocation, out pidlRoot);
if (pidlRoot == IntPtr.Zero)
{
return DialogResult.Cancel;
}
int mergedOptions = publicOptions | privateOptions;
if ((mergedOptions & (int) Win32API.Shell32.BffStyles.NewDialogStyle) != 0)
{
if (System.Threading.ApartmentState.MTA == Application.OleRequired())
if (uMsg == 1)
{
mergedOptions = mergedOptions & (~(int) Win32API.Shell32.BffStyles.NewDialogStyle);
var str = Marshal.StringToHGlobalUni(SelectedPath);
Win32Imports.SendMessage(hwnd, 0x400 + 103, (IntPtr) 1, str);
Marshal.FreeHGlobal(str);
}
return 0;
}
IntPtr pidlRet = IntPtr.Zero;
var hWndOwner = owner?.Handle ?? Win32Imports.GetActiveWindow();
Win32Imports.SHGetSpecialFolderLocation(hWndOwner, startLocation, out var pidlRoot);
if (pidlRoot == IntPtr.Zero) return DialogResult.Cancel;
var mergedOptions = publicOptions | privateOptions;
if ((mergedOptions & Win32Imports.BROWSEINFO.FLAGS.NewDialogStyle) != 0 && ApartmentState.MTA == Application.OleRequired())
{
mergedOptions &= ~Win32Imports.BROWSEINFO.FLAGS.NewDialogStyle;
}
IntPtr pidlRet = default;
try
{
// Construct a BROWSEINFO.
Win32API.Shell32.BROWSEINFO bi = new Win32API.Shell32.BROWSEINFO();
IntPtr buffer = Marshal.AllocHGlobal(MAX_PATH);
bi.pidlRoot = pidlRoot;
bi.hwndOwner = hWndOwner;
bi.pszDisplayName = buffer;
bi.lpszTitle = Description;
bi.ulFlags = mergedOptions;
bi.lpfn = Callback;
// The rest of the fields are initialized to zero by the constructor.
// bi.lParam = IntPtr.Zero; bi.iImage = 0;
// Show the dialog.
pidlRet = Win32API.Shell32.SHBrowseForFolder(ref bi);
// Free the buffer you've allocated on the global heap.
var buffer = Marshal.AllocHGlobal(Win32Imports.MAX_PATH);
var bi = new Win32Imports.BROWSEINFO
{
hwndOwner = hWndOwner,
pidlRoot = pidlRoot,
pszDisplayName = buffer,
lpszTitle = Description,
ulFlags = mergedOptions,
lpfn = Callback
};
pidlRet = Win32Imports.SHBrowseForFolder(ref bi);
Marshal.FreeHGlobal(buffer);
if (pidlRet == IntPtr.Zero)
{
// User clicked Cancel.
return DialogResult.Cancel;
}
// Then retrieve the path from the IDList.
var sb = new StringBuilder(MAX_PATH);
if (0 == Win32API.Shell32.SHGetPathFromIDList(pidlRet, sb))
{
return DialogResult.Cancel;
}
// Convert to a string.
if (pidlRet == IntPtr.Zero) return DialogResult.Cancel; // user clicked Cancel
var sb = new StringBuilder(Win32Imports.MAX_PATH);
if (Win32Imports.SHGetPathFromIDList(pidlRet, sb) == 0) return DialogResult.Cancel;
SelectedPath = sb.ToString();
}
finally
{
Win32API.IMalloc malloc = GetShMalloc();
Win32Imports.SHGetMalloc(out var malloc);
malloc.Free(pidlRoot);
if (pidlRet != IntPtr.Zero)
{
malloc.Free(pidlRet);
}
if (pidlRet != IntPtr.Zero) malloc.Free(pidlRet);
}
return DialogResult.OK;
}
public string SelectedPath;
}
internal class Win32API
{
// C# representation of the IMalloc interface.
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
Guid("00000002-0000-0000-C000-000000000046")]
public interface IMalloc
{
[PreserveSig]
IntPtr Alloc([In] int cb);
[PreserveSig]
IntPtr Realloc([In] IntPtr pv, [In] int cb);
[PreserveSig]
void Free([In] IntPtr pv);
[PreserveSig]
int GetSize([In] IntPtr pv);
[PreserveSig]
int DidAlloc(IntPtr pv);
[PreserveSig]
void HeapMinimize();
}
[DllImport("User32.DLL")]
public static extern IntPtr GetActiveWindow();
public class Shell32
{
// Styles used in the BROWSEINFO.ulFlags field.
[Flags]
public enum BffStyles
{
RestrictToFilesystem = 0x0001, // BIF_RETURNONLYFSDIRS
RestrictToDomain = 0x0002, // BIF_DONTGOBELOWDOMAIN
RestrictToSubfolders = 0x0008, // BIF_RETURNFSANCESTORS
ShowTextBox = 0x0010, // BIF_EDITBOX
ValidateSelection = 0x0020, // BIF_VALIDATE
NewDialogStyle = 0x0040, // BIF_NEWDIALOGSTYLE
BrowseForComputer = 0x1000, // BIF_BROWSEFORCOMPUTER
BrowseForPrinter = 0x2000, // BIF_BROWSEFORPRINTER
BrowseForEverything = 0x4000, // BIF_BROWSEINCLUDEFILES
}
// Delegate type used in BROWSEINFO.lpfn field.
public delegate int BFFCALLBACK(IntPtr hwnd, uint uMsg, IntPtr lParam, IntPtr lpData);
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct BROWSEINFO
{
public IntPtr hwndOwner;
public IntPtr pidlRoot;
public IntPtr pszDisplayName;
[MarshalAs(UnmanagedType.LPTStr)] public string lpszTitle;
public int ulFlags;
[MarshalAs(UnmanagedType.FunctionPtr)] public BFFCALLBACK lpfn;
public IntPtr lParam;
public int iImage;
}
[DllImport("Shell32.DLL")]
public static extern int SHGetMalloc(out IMalloc ppMalloc);
[DllImport("Shell32.DLL")]
public static extern int SHGetSpecialFolderLocation(
IntPtr hwndOwner, int nFolder, out IntPtr ppidl);
[DllImport("Shell32.DLL")]
public static extern int SHGetPathFromIDList(
IntPtr pidl, StringBuilder Path);
[DllImport("Shell32.DLL", CharSet = CharSet.Auto)]
public static extern IntPtr SHBrowseForFolder(ref BROWSEINFO bi);
}
}
}
}

View File

@ -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)

View File

@ -1,535 +0,0 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace BizHawk.Client.EmuHawk
{
public static unsafe class Win32
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RECT
{
private int _Left;
private int _Top;
private int _Right;
private int _Bottom;
public RECT(RECT Rectangle)
: this(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom)
{
}
public RECT(int Left, int Top, int Right, int Bottom)
{
_Left = Left;
_Top = Top;
_Right = Right;
_Bottom = Bottom;
}
public int X
{
get { return _Left; }
set { _Left = value; }
}
public int Y
{
get { return _Top; }
set { _Top = value; }
}
public int Left
{
get { return _Left; }
set { _Left = value; }
}
public int Top
{
get { return _Top; }
set { _Top = value; }
}
public int Right
{
get { return _Right; }
set { _Right = value; }
}
public int Bottom
{
get { return _Bottom; }
set { _Bottom = value; }
}
public int Height
{
get { return _Bottom - _Top; }
set { _Bottom = value - _Top; }
}
public int Width
{
get { return _Right - _Left; }
set { _Right = value + _Left; }
}
public Point Location
{
get { return new Point(Left, Top); }
set
{
_Left = value.X;
_Top = value.Y;
}
}
public Size Size
{
get { return new Size(Width, Height); }
set
{
_Right = value.Width + _Left;
_Bottom = value.Height + _Top;
}
}
public static implicit operator Rectangle(RECT Rectangle)
{
return new Rectangle(Rectangle.Left, Rectangle.Top, Rectangle.Width, Rectangle.Height);
}
public static implicit operator RECT(Rectangle Rectangle)
{
return new RECT(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom);
}
public static bool operator ==(RECT Rectangle1, RECT Rectangle2)
{
return Rectangle1.Equals(Rectangle2);
}
public static bool operator !=(RECT Rectangle1, RECT Rectangle2)
{
return !Rectangle1.Equals(Rectangle2);
}
public override string ToString()
{
return $"{{Left: {_Left}; Top: {_Top}; Right: {_Right}; Bottom: {_Bottom}}}";
}
public override int GetHashCode()
{
return ToString().GetHashCode();
}
public bool Equals(RECT Rectangle)
{
return Rectangle.Left == _Left && Rectangle.Top == _Top && Rectangle.Right == _Right && Rectangle.Bottom == _Bottom;
}
public override bool Equals(object Object)
{
if (Object is RECT)
{
return Equals((RECT)Object);
}
else if (Object is Rectangle)
{
return Equals(new RECT((Rectangle)Object));
}
return false;
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct AVISTREAMINFOW
{
public Int32 fccType;
public Int32 fccHandler;
public Int32 dwFlags;
public Int32 dwCaps;
public Int16 wPriority;
public Int16 wLanguage;
public Int32 dwScale;
public Int32 dwRate;
public Int32 dwStart;
public Int32 dwLength;
public Int32 dwInitialFrames;
public Int32 dwSuggestedBufferSize;
public Int32 dwQuality;
public Int32 dwSampleSize;
public RECT rcFrame;
public Int32 dwEditCount;
public Int32 dwFormatChangeCount;
[MarshalAs(UnmanagedType.LPWStr, SizeConst=64)]
public string szName;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BITMAPINFOHEADER
{
public uint biSize;
public int biWidth;
public int biHeight;
public ushort biPlanes;
public ushort biBitCount;
public uint biCompression;
public uint biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public uint biClrUsed;
public uint biClrImportant;
public void Init()
{
biSize = (uint)Marshal.SizeOf(this);
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct WAVEFORMATEX
{
public ushort wFormatTag;
public ushort nChannels;
public uint nSamplesPerSec;
public uint nAvgBytesPerSec;
public ushort nBlockAlign;
public ushort wBitsPerSample;
public ushort cbSize;
public void Init()
{
cbSize = (ushort)Marshal.SizeOf(this);
}
}
public const int WAVE_FORMAT_PCM = 1;
public const int AVIIF_KEYFRAME = 0x00000010;
[Flags]
public enum OpenFileStyle : uint
{
OF_CANCEL = 0x00000800, // Ignored. For a dialog box with a Cancel button, use OF_PROMPT.
OF_CREATE = 0x00001000, // Creates a new file. If file exists, it is truncated to zero (0) length.
OF_DELETE = 0x00000200, // Deletes a file.
OF_EXIST = 0x00004000, // Opens a file and then closes it. Used to test that a file exists
OF_PARSE = 0x00000100, // Fills the OFSTRUCT structure, but does not do anything else.
OF_PROMPT = 0x00002000, // Displays a dialog box if a requested file does not exist
OF_READ = 0x00000000, // Opens a file for reading only.
OF_READWRITE = 0x00000002, // Opens a file with read/write permissions.
OF_REOPEN = 0x00008000, // Opens a file by using information in the reopen buffer.
// For MS-DOSbased file systems, opens a file with compatibility mode, allows any process on a
// specified computer to open the file any number of times.
// Other efforts to open a file with other sharing modes fail. This flag is mapped to the
// FILE_SHARE_READ|FILE_SHARE_WRITE flags of the CreateFile function.
OF_SHARE_COMPAT = 0x00000000,
// Opens a file without denying read or write access to other processes.
// On MS-DOS-based file systems, if the file has been opened in compatibility mode
// by any other process, the function fails.
// This flag is mapped to the FILE_SHARE_READ|FILE_SHARE_WRITE flags of the CreateFile function.
OF_SHARE_DENY_NONE = 0x00000040,
// Opens a file and denies read access to other processes.
// On MS-DOS-based file systems, if the file has been opened in compatibility mode,
// or for read access by any other process, the function fails.
// This flag is mapped to the FILE_SHARE_WRITE flag of the CreateFile function.
OF_SHARE_DENY_READ = 0x00000030,
// Opens a file and denies write access to other processes.
// On MS-DOS-based file systems, if a file has been opened in compatibility mode,
// or for write access by any other process, the function fails.
// This flag is mapped to the FILE_SHARE_READ flag of the CreateFile function.
OF_SHARE_DENY_WRITE = 0x00000020,
// Opens a file with exclusive mode, and denies both read/write access to other processes.
// If a file has been opened in any other mode for read/write access, even by the current process,
// the function fails.
OF_SHARE_EXCLUSIVE = 0x00000010,
// Verifies that the date and time of a file are the same as when it was opened previously.
// This is useful as an extra check for read-only files.
OF_VERIFY = 0x00000400,
// Opens a file for write access only.
OF_WRITE = 0x00000001
}
[DllImport("avifil32.dll", SetLastError = true)]
public static extern int AVIFileOpenW(ref IntPtr pAviFile, [MarshalAs(UnmanagedType.LPWStr)] string szFile, OpenFileStyle uMode, int lpHandler);
[DllImport("avifil32.dll", SetLastError = true)]
public static extern void AVIFileInit();
// Create a new stream in an existing file and creates an interface to the new stream
[DllImport("avifil32.dll")]
public static extern int AVIFileCreateStreamW(
IntPtr pfile,
out IntPtr ppavi,
ref AVISTREAMINFOW psi);
[StructLayout(LayoutKind.Sequential)]
public struct AVICOMPRESSOPTIONS
{
public int fccType;
public int fccHandler;
public int dwKeyFrameEvery;
public int dwQuality;
public int dwBytesPerSecond;
public int dwFlags;
public IntPtr lpFormat;
public int cbFormat;
public IntPtr lpParms;
public int cbParms;
public int dwInterleaveEvery;
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern SafeFileHandle CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[DllImport("kernel32.dll")]
public static extern FileType GetFileType(IntPtr hFile);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetCommandLine();
public enum FileType : uint
{
FileTypeChar = 0x0002,
FileTypeDisk = 0x0001,
FileTypePipe = 0x0003,
FileTypeRemote = 0x8000,
FileTypeUnknown = 0x0000,
}
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetActiveWindow(IntPtr hWnd);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool AttachConsole(int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = false)]
public static extern bool FreeConsole();
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetStdHandle(int nStdHandle, IntPtr hConsoleOutput);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CreateFile(
string fileName,
int desiredAccess,
int shareMode,
IntPtr securityAttributes,
int creationDisposition,
int flagsAndAttributes,
IntPtr templateFile);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
public static extern bool CloseHandle(IntPtr handle);
[DllImport("user32.dll", SetLastError = false)]
public static extern IntPtr GetDesktopWindow();
// Retrieve the save options for a file and returns them in a buffer
[DllImport("avifil32.dll")]
public static extern int AVISaveOptions(IntPtr hwnd, int flags, int streams, void* ppAvi, void* plpOptions);
// Free the resources allocated by the AVISaveOptions function
[DllImport("avifil32.dll")]
public static extern int AVISaveOptionsFree(
int streams,
[In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] IntPtr[] plpOptions);
// Create a compressed stream from an uncompressed stream and a
// compression filter, and returns the address of a pointer to
// the compressed stream
[DllImport("avifil32.dll")]
public static extern int AVIMakeCompressedStream(
out IntPtr ppsCompressed,
IntPtr psSource,
ref AVICOMPRESSOPTIONS lpOptions,
IntPtr pclsidHandler);
// Set the format of a stream at the specified position
[DllImport("avifil32.dll")]
public static extern int AVIStreamSetFormat(
IntPtr pavi,
int lPos,
ref BITMAPINFOHEADER lpFormat,
int cbFormat);
// Set the format of a stream at the specified position
[DllImport("avifil32.dll")]
public static extern int AVIStreamSetFormat(
IntPtr pavi,
int lPos,
ref WAVEFORMATEX lpFormat,
int cbFormat);
// Write data to a stream
[DllImport("avifil32.dll")]
public static extern int AVIStreamWrite(
IntPtr pavi,
int lStart,
int lSamples,
IntPtr lpBuffer,
int cbBuffer,
int dwFlags,
IntPtr plSampWritten,
out int plBytesWritten);
// Release an open AVI stream
[DllImport("avifil32.dll")]
public static extern int AVIStreamRelease(IntPtr pavi);
// Release an open AVI stream
[DllImport("avifil32.dll")]
public static extern int AVIFileRelease(IntPtr pfile);
// Replacement of mmioFOURCC macros
public static int mmioFOURCC(string str)
{
return (
((int)(byte)(str[0])) |
((int)(byte)(str[1]) << 8) |
((int)(byte)(str[2]) << 16) |
((int)(byte)(str[3]) << 24));
}
public static bool FAILED(int hr) { return hr < 0; }
// Inverse of mmioFOURCC
public static string decode_mmioFOURCC(int code)
{
char[] chs = new char[4];
for (int i = 0; i < 4; i++)
{
chs[i] = (char)(byte)((code >> (i << 3)) & 0xFF);
if (!char.IsLetterOrDigit(chs[i]))
chs[i] = ' ';
}
return new string(chs);
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[DllImport("Kernel32.dll", EntryPoint = "RtlZeroMemory", SetLastError = false)]
public static extern void ZeroMemory(IntPtr dest, uint size);
[DllImport("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern IntPtr MemSet(IntPtr dest, int c, uint count);
[DllImport("shlwapi.dll", CharSet = CharSet.Auto)]
public static extern bool PathRelativePathTo(
[Out] System.Text.StringBuilder pszPath,
[In] string pszFrom,
[In] FileAttributes dwAttrFrom,
[In] string pszTo,
[In] FileAttributes dwAttrTo
);
/// <summary>
/// File attributes are metadata values stored by the file system on disk and are used by the system and are available to developers via various file I/O APIs.
/// </summary>
[Flags]
//[CLSCompliant(false)]
public enum FileAttributes : uint
{
/// <summary>
/// A file that is read-only. Applications can read the file, but cannot write to it or delete it. This attribute is not honored on directories. For more information, see "You cannot view or change the Read-only or the System attributes of folders in Windows Server 2003, in Windows XP, or in Windows Vista".
/// </summary>
Readonly = 0x00000001,
/// <summary>
/// The file or directory is hidden. It is not included in an ordinary directory listing.
/// </summary>
Hidden = 0x00000002,
/// <summary>
/// A file or directory that the operating system uses a part of, or uses exclusively.
/// </summary>
System = 0x00000004,
/// <summary>
/// The handle that identifies a directory.
/// </summary>
Directory = 0x00000010,
/// <summary>
/// A file or directory that is an archive file or directory. Applications typically use this attribute to mark files for backup or removal.
/// </summary>
Archive = 0x00000020,
/// <summary>
/// This value is reserved for system use.
/// </summary>
Device = 0x00000040,
/// <summary>
/// A file that does not have other attributes set. This attribute is valid only when used alone.
/// </summary>
Normal = 0x00000080,
/// <summary>
/// A file that is being used for temporary storage. File systems avoid writing data back to mass storage if sufficient cache memory is available, because typically, an application deletes a temporary file after the handle is closed. In that scenario, the system can entirely avoid writing the data. Otherwise, the data is written after the handle is closed.
/// </summary>
Temporary = 0x00000100,
/// <summary>
/// A file that is a sparse file.
/// </summary>
SparseFile = 0x00000200,
/// <summary>
/// A file or directory that has an associated reparse point, or a file that is a symbolic link.
/// </summary>
ReparsePoint = 0x00000400,
/// <summary>
/// A file or directory that is compressed. For a file, all of the data in the file is compressed. For a directory, compression is the default for newly created files and subdirectories.
/// </summary>
Compressed = 0x00000800,
/// <summary>
/// The data of a file is not available immediately. This attribute indicates that the file data is physically moved to offline storage. This attribute is used by Remote Storage, which is the hierarchical storage management software. Applications should not arbitrarily change this attribute.
/// </summary>
Offline = 0x00001000,
/// <summary>
/// The file or directory is not to be indexed by the content indexing service.
/// </summary>
NotContentIndexed = 0x00002000,
/// <summary>
/// A file or directory that is encrypted. For a file, all data streams in the file are encrypted. For a directory, encryption is the default for newly created files and subdirectories.
/// </summary>
Encrypted = 0x00004000,
/// <summary>
/// This value is reserved for system use.
/// </summary>
Virtual = 0x00010000
}
}
}

View File

@ -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?
}
}
}

View File

@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using BizHawk.Common;
using BizHawk.Common.ReflectionExtensions;
namespace BizHawk.Client.EmuHawk.WinFormExtensions
@ -140,53 +140,6 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions
public static class ListViewExtensions
{
[StructLayout(LayoutKind.Sequential)]
public struct HDITEM
{
public Mask mask;
public int cxy;
[MarshalAs(UnmanagedType.LPTStr)]
public string pszText;
public IntPtr hbm;
public int cchTextMax;
public Format fmt;
public IntPtr lParam;
// _WIN32_IE >= 0x0300
public int iImage;
public int iOrder;
// _WIN32_IE >= 0x0500
public uint type;
public IntPtr pvFilter;
// _WIN32_WINNT >= 0x0600
public uint state;
[Flags]
public enum Mask
{
Format = 0x4, // HDI_FORMAT
};
[Flags]
public enum Format
{
SortDown = 0x200, // HDF_SORTDOWN
SortUp = 0x400, // HDF_SORTUP
};
};
public const int LVM_FIRST = 0x1000;
public const int LVM_GETHEADER = LVM_FIRST + 31;
public const int HDM_FIRST = 0x1200;
public const int HDM_GETITEM = HDM_FIRST + 11;
public const int HDM_SETITEM = HDM_FIRST + 12;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, ref HDITEM lParam);
/// <summary>
/// Dumps the contents of the ListView into a tab separated list of lines
/// </summary>
@ -226,43 +179,30 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions
public static void SetSortIcon(this ListView listViewControl, int columnIndex, SortOrder order)
{
IntPtr columnHeader = SendMessage(listViewControl.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
for (int columnNumber = 0; columnNumber <= listViewControl.Columns.Count - 1; columnNumber++)
const int LVM_GETHEADER = 4127;
const int HDM_GETITEM = 4619;
const int HDM_SETITEM = 4620;
var columnHeader = Win32Imports.SendMessage(listViewControl.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
for (int columnNumber = 0, l = listViewControl.Columns.Count; columnNumber < l; columnNumber++)
{
var columnPtr = new IntPtr(columnNumber);
var item = new HDITEM
var item = new Win32Imports.HDITEM { mask = Win32Imports.HDITEM.Mask.Format };
if (Win32Imports.SendMessage(columnHeader, HDM_GETITEM, columnPtr, ref item) == IntPtr.Zero) throw new Win32Exception();
if (columnNumber != columnIndex || order == SortOrder.None)
{
mask = HDITEM.Mask.Format
};
if (SendMessage(columnHeader, HDM_GETITEM, columnPtr, ref item) == IntPtr.Zero)
{
throw new Win32Exception();
item.fmt &= ~Win32Imports.HDITEM.Format.SortDown & ~Win32Imports.HDITEM.Format.SortUp;
}
if (order != SortOrder.None && columnNumber == columnIndex)
else if (order == SortOrder.Ascending)
{
switch (order)
{
case SortOrder.Ascending:
item.fmt &= ~HDITEM.Format.SortDown;
item.fmt |= HDITEM.Format.SortUp;
break;
case SortOrder.Descending:
item.fmt &= ~HDITEM.Format.SortUp;
item.fmt |= HDITEM.Format.SortDown;
break;
}
item.fmt &= ~Win32Imports.HDITEM.Format.SortDown;
item.fmt |= Win32Imports.HDITEM.Format.SortUp;
}
else
else if (order == SortOrder.Descending)
{
item.fmt &= ~HDITEM.Format.SortDown & ~HDITEM.Format.SortUp;
}
if (SendMessage(columnHeader, HDM_SETITEM, columnPtr, ref item) == IntPtr.Zero)
{
throw new Win32Exception();
item.fmt &= ~Win32Imports.HDITEM.Format.SortUp;
item.fmt |= Win32Imports.HDITEM.Format.SortDown;
}
if (Win32Imports.SendMessage(columnHeader, HDM_SETITEM, columnPtr, ref item) == IntPtr.Zero) throw new Win32Exception();
}
}

View File

@ -1,6 +1,9 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using BizHawk.Common;
using SlimDX.XInput;
#pragma warning disable 169
@ -16,9 +19,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;
@ -46,32 +46,33 @@ namespace BizHawk.Client.EmuHawk
{
try
{
//some users wont even have xinput installed. in order to avoid spurious exceptions and possible instability, check for the library first
HasGetInputStateEx = true;
LibraryHandle = Win32.LoadLibrary("xinput1_3.dll");
if(LibraryHandle == IntPtr.Zero)
LibraryHandle = Win32.LoadLibrary("xinput1_4.dll");
if(LibraryHandle == IntPtr.Zero)
// some users won't even have xinput installed. in order to avoid spurious exceptions and possible instability, check for the library first
var llManager = OSTailoredCode.LinkedLibManager;
var libraryHandle = llManager.LoadOrNull("xinput1_3.dll") ?? llManager.LoadOrNull("xinput1_4.dll");
if (libraryHandle != null)
{
HasGetInputStateEx = true;
XInputGetStateExProc = (XInputGetStateExProcDelegate) Marshal.GetDelegateForFunctionPointer(
Win32Imports.GetProcAddressOrdinal(libraryHandle.Value, new IntPtr(100)),
typeof(XInputGetStateExProcDelegate)
);
}
else
{
LibraryHandle = Win32.LoadLibrary("xinput9_1_0.dll");
HasGetInputStateEx = false;
libraryHandle = llManager.LoadOrNull("xinput9_1_0.dll");
}
_isAvailable = libraryHandle != null;
LibraryHandle = libraryHandle ?? IntPtr.Zero;
if (LibraryHandle != IntPtr.Zero)
{
if (HasGetInputStateEx)
{
IntPtr proc = GetProcAddressOrdinal(LibraryHandle, new IntPtr(100));
XInputGetStateExProc = (XInputGetStateExProcDelegate)Marshal.GetDelegateForFunctionPointer(proc, typeof(XInputGetStateExProcDelegate));
}
//don't remove this code. it's important to catch errors on systems with broken xinput installs.
//(probably, checking for the library was adequate, but lets not get rid of this anyway)
var test = new SlimDX.XInput.Controller(UserIndex.One).IsConnected;
_isAvailable = true;
}
// don't remove this code. it's important to catch errors on systems with broken xinput installs.
// (probably, checking for the library was adequate, but let's not get rid of this anyway)
if (_isAvailable) _ = new Controller(UserIndex.One).IsConnected;
}
catch
{
// ignored
}
catch { }
}
public static void Initialize()

View File

@ -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;

View File

@ -118,12 +118,12 @@ namespace BizHawk.Client.EmuHawk
return;
if (oldOut == IntPtr.Zero)
oldOut = Win32.GetStdHandle( -11 ); //STD_OUTPUT_HANDLE
oldOut = ConsoleImports.GetStdHandle( -11 ); //STD_OUTPUT_HANDLE
var fileType = Win32.GetFileType(oldOut);
var fileType = ConsoleImports.GetFileType(oldOut);
//stdout is already connected to something. keep using it and don't let the console interfere
shouldRedirectStdout = (fileType == Win32.FileType.FileTypeUnknown || fileType == Win32.FileType.FileTypePipe);
shouldRedirectStdout = (fileType == ConsoleImports.FileType.FileTypeUnknown || fileType == ConsoleImports.FileType.FileTypePipe);
//attach to an existing console
attachedConsole = false;
@ -131,7 +131,7 @@ namespace BizHawk.Client.EmuHawk
//ever since a recent KB, XP-based systems glitch out when attachconsole is called and there's no console to attach to.
if (Environment.OSVersion.Version.Major != 5)
{
if (Win32.AttachConsole(-1))
if (ConsoleImports.AttachConsole(-1))
{
hasConsole = true;
attachedConsole = true;
@ -140,12 +140,12 @@ namespace BizHawk.Client.EmuHawk
if (!attachedConsole)
{
Win32.FreeConsole();
if (Win32.AllocConsole())
ConsoleImports.FreeConsole();
if (ConsoleImports.AllocConsole())
{
//set icons for the console so we can tell them apart from the main window
Win32.SendMessage(Win32.GetConsoleWindow(), 0x0080/*WM_SETICON*/, (IntPtr)0/*ICON_SMALL*/, Properties.Resources.console16x16.GetHicon());
Win32.SendMessage(Win32.GetConsoleWindow(), 0x0080/*WM_SETICON*/, (IntPtr)1/*ICON_LARGE*/, Properties.Resources.console32x32.GetHicon());
Win32Imports.SendMessage(ConsoleImports.GetConsoleWindow(), 0x0080/*WM_SETICON*/, (IntPtr)0/*ICON_SMALL*/, Properties.Resources.console16x16.GetHicon());
Win32Imports.SendMessage(ConsoleImports.GetConsoleWindow(), 0x0080/*WM_SETICON*/, (IntPtr)1/*ICON_LARGE*/, Properties.Resources.console32x32.GetHicon());
hasConsole = true;
}
else
@ -156,17 +156,17 @@ namespace BizHawk.Client.EmuHawk
if (hasConsole)
{
IntPtr ptr = Win32.GetCommandLine();
IntPtr ptr = ConsoleImports.GetCommandLine();
string commandLine = Marshal.PtrToStringAuto(ptr);
Console.Title = SkipEverythingButProgramInCommandLine(commandLine);
}
if (shouldRedirectStdout)
{
conOut = Win32.CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, 3, 0, IntPtr.Zero);
conOut = ConsoleImports.CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, 3, 0, IntPtr.Zero);
if (!Win32.SetStdHandle(-11, conOut))
throw new Exception($"{nameof(Win32.SetStdHandle)}() failed");
if (!ConsoleImports.SetStdHandle(-11, conOut))
throw new Exception($"{nameof(ConsoleImports.SetStdHandle)}() failed");
}
//DotNetRewireConout();
@ -188,15 +188,15 @@ namespace BizHawk.Client.EmuHawk
if (shouldRedirectStdout)
{
Win32.CloseHandle(conOut);
ConsoleImports.CloseHandle(conOut);
}
if (!attachedConsole)
{
Win32.FreeConsole();
ConsoleImports.FreeConsole();
}
Win32.SetStdHandle(-11, oldOut);
ConsoleImports.SetStdHandle(-11, oldOut);
conOut = IntPtr.Zero;
hasConsole = false;
@ -217,8 +217,8 @@ namespace BizHawk.Client.EmuHawk
if (Global.Config.WIN32_CONSOLE)
{
IntPtr x = Win32.GetConsoleWindow();
Win32.SetForegroundWindow(x);
IntPtr x = ConsoleImports.GetConsoleWindow();
ConsoleImports.SetForegroundWindow(x);
}
}

View File

@ -2865,6 +2865,7 @@
this.GBASubMenu.Name = "GBASubMenu";
this.GBASubMenu.Size = new System.Drawing.Size(39, 17);
this.GBASubMenu.Text = "GBA";
this.GBASubMenu.DropDownOpened += new System.EventHandler(this.GBASubMenu_DropDownOpened);
//
// GBACoreSelectionSubMenu
//

View File

@ -284,11 +284,12 @@ namespace BizHawk.Client.EmuHawk
StopAVIMenuItem.ShortcutKeyDisplayString = Config.HotkeyBindings["Stop A/V"].Bindings;
CaptureOSDMenuItem.Checked = Config.AVI_CaptureOSD;
RecordAVMenuItem.Enabled = !string.IsNullOrEmpty(Config.VideoWriter) && _currAviWriter == null;
RecordAVMenuItem.Enabled = OSTailoredCode.IsUnixHost || !string.IsNullOrEmpty(Global.Config.VideoWriter) && _currAviWriter == null;
SynclessRecordingMenuItem.Enabled = !OSTailoredCode.IsUnixHost;
if (_currAviWriter == null)
{
ConfigAndRecordAVMenuItem.Enabled = true;
ConfigAndRecordAVMenuItem.Enabled = !OSTailoredCode.IsUnixHost;
StopAVIMenuItem.Enabled = false;
}
else
@ -751,6 +752,8 @@ namespace BizHawk.Client.EmuHawk
DisplayLagCounterMenuItem.Enabled = Emulator.CanPollInput();
DisplayMessagesMenuItem.Checked = Config.DisplayMessages;
DisplayLogWindowMenuItem.Enabled = !OSTailoredCode.IsUnixHost;
}
private void WindowSizeSubMenu_DropDownOpened(object sender, EventArgs e)
@ -2114,6 +2117,7 @@ namespace BizHawk.Client.EmuHawk
private void GBSubMenu_DropDownOpened(object sender, EventArgs e)
{
LoadGBInSGBMenuItem.Checked = Config.GB_AsSGB;
GBGPUViewerMenuItem.Enabled = !OSTailoredCode.IsUnixHost;
}
private void GBCoreSettingsMenuItem_Click(object sender, EventArgs e)
@ -2174,6 +2178,11 @@ namespace BizHawk.Client.EmuHawk
FlagNeedsReboot();
}
private void GBASubMenu_DropDownOpened(object sender, EventArgs e)
{
GbaGpuViewerMenuItem.Enabled = !OSTailoredCode.IsUnixHost;
}
private void GBACoreSelectionSubMenu_DropDownOpened(object sender, EventArgs e)
{
GBAmGBAMenuItem.Checked = Config.GBA_UsemGBA;
@ -2237,6 +2246,7 @@ namespace BizHawk.Client.EmuHawk
}
SNESControllerConfigurationMenuItem.Enabled = MovieSession.Movie.NotActive();
SnesGfxDebuggerMenuItem.Enabled = !OSTailoredCode.IsUnixHost;
}
private void SNESControllerConfigurationMenuItem_Click(object sender, EventArgs e)

View File

@ -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.

View File

@ -1,4 +1,6 @@
using System.Linq;
using BizHawk.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
@ -102,7 +104,8 @@ namespace BizHawk.Client.EmuHawk
_exitRequestPending = true;
break;
case "Record A/V":
RecordAv();
if (OSTailoredCode.IsUnixHost) GlobalWin.OSD.AddMessage("(A/V only available on Windows for now)");
else RecordAv();
break;
case "Stop A/V":
StopAv();

View File

@ -223,7 +223,7 @@ namespace BizHawk.Client.EmuHawk
InitializeComponent();
SetImages();
Game = GameInfo.NullInstance;
if (Config.ShowLogWindow)
if (Config.ShowLogWindow && !OSTailoredCode.IsUnixHost)
{
LogConsole.ShowConsole();
DisplayLogWindowMenuItem.Checked = true;
@ -493,7 +493,8 @@ namespace BizHawk.Client.EmuHawk
// start dumping, if appropriate
if (_argParser.cmdDumpType != null && _argParser.cmdDumpName != null)
{
RecordAv(_argParser.cmdDumpType, _argParser.cmdDumpName);
if (OSTailoredCode.IsUnixHost) Console.WriteLine("A/V dump requires Win32 API calls, ignored");
else RecordAv(_argParser.cmdDumpType, _argParser.cmdDumpName);
}
SetMainformMovieInfo();
@ -511,7 +512,7 @@ namespace BizHawk.Client.EmuHawk
public int ProgramRunLoop()
{
CheckMessages(); // can someone leave a note about why this is needed?
LogConsole.PositionConsole();
if (!OSTailoredCode.IsUnixHost) LogConsole.PositionConsole();
// needs to be done late, after the log console snaps on top
// fullscreen should snap on top even harder!
@ -3206,10 +3207,7 @@ namespace BizHawk.Client.EmuHawk
/// </summary>
private void RecordAvBase(string videoWriterName, string filename, bool unattended)
{
if (_currAviWriter != null)
{
return;
}
if (_currAviWriter != null || OSTailoredCode.IsUnixHost) return;
// select IVideoWriter to use
IVideoWriter aw;
@ -3632,7 +3630,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;

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -8,6 +8,7 @@ using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Client.EmuHawk.WinFormExtensions;
using BizHawk.Common;
namespace BizHawk.Client.EmuHawk
{
@ -84,7 +85,7 @@ namespace BizHawk.Client.EmuHawk
public void Clear()
{
var lockBits = BMP.LockBits(new Rectangle(0, 0, BMP.Width, BMP.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
Win32.MemSet(lockBits.Scan0, 0xff, (uint)(lockBits.Height * lockBits.Stride));
Win32Imports.MemSet(lockBits.Scan0, 0xff, (uint)(lockBits.Height * lockBits.Stride));
BMP.UnlockBits(lockBits);
Refresh();
}

View File

@ -7,6 +7,8 @@ using BizHawk.Client.Common;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Emulation.Cores.Nintendo.GBA;
using System.Collections.Generic;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
@ -409,7 +411,7 @@ namespace BizHawk.Client.EmuHawk
Bitmap bmp = mbv.BmpView.BMP;
var lockdata = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
// Clear()
Win32.MemSet(lockdata.Scan0, 0xff, (uint)(lockdata.Height * lockdata.Stride));
Win32Imports.MemSet(lockdata.Scan0, 0xff, (uint)(lockdata.Height * lockdata.Stride));
int* pixels = (int*)lockdata.Scan0;
int pitch = lockdata.Stride / sizeof(int);
@ -501,7 +503,7 @@ namespace BizHawk.Client.EmuHawk
if (tophalfonly)
{
Win32.MemSet(lockdata.Scan0, 0xff, (uint)(128 * lockdata.Stride));
Win32Imports.MemSet(lockdata.Scan0, 0xff, (uint)(128 * lockdata.Stride));
pixels += 128 * pitch;
tiles += 16384;
}

View File

@ -289,30 +289,28 @@ namespace BizHawk.Client.EmuHawk
#endif
}
static FileAttributes GetPathAttribute(string path1)
{
var di = new DirectoryInfo(path1.Split('|').First());
if (di.Exists)
{
return FileAttributes.Directory;
}
var fi = new FileInfo(path1.Split('|').First());
if (fi.Exists)
{
return FileAttributes.Normal;
}
throw new FileNotFoundException();
}
var path = new StringBuilder(260 /* = MAX_PATH */);
return Win32.PathRelativePathTo(path, fromPath, GetPathAttribute(fromPath), toPath, GetPathAttribute(toPath))
return Win32Imports.PathRelativePathTo(path, fromPath, GetPathAttribute(fromPath), toPath, GetPathAttribute(toPath))
? path.ToString()
: throw new ArgumentException("Paths must have a common prefix");
}
/// <seealso cref="GetRelativePath"/>
private static Win32.FileAttributes GetPathAttribute(string path)
{
var di = new DirectoryInfo(path.Split('|').First());
if (di.Exists)
{
return Win32.FileAttributes.Directory;
}
var fi = new FileInfo(path.Split('|').First());
if (fi.Exists)
{
return Win32.FileAttributes.Normal;
}
throw new FileNotFoundException();
}
private void SystemDropDown_SelectedIndexChanged(object sender, EventArgs e)
{
Recalculate();

View File

@ -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))
{

View File

@ -896,7 +896,7 @@ namespace BizHawk.Client.EmuHawk
{
groupFreeze.SuspendLayout();
Win32.SendMessage(groupFreeze.Handle, 11, (IntPtr)0, IntPtr.Zero); //WM_SETREDRAW false
Win32Imports.SendMessage(groupFreeze.Handle, 11, (IntPtr)0, IntPtr.Zero); //WM_SETREDRAW false
var tp = tabctrlDetails.SelectedTab;
@ -916,7 +916,7 @@ namespace BizHawk.Client.EmuHawk
groupFreeze.ResumeLayout();
Win32.SendMessage(groupFreeze.Handle, 11, (IntPtr)1, IntPtr.Zero); //WM_SETREDRAW true
Win32Imports.SendMessage(groupFreeze.Handle, 11, (IntPtr)1, IntPtr.Zero); //WM_SETREDRAW true
groupFreeze.Refresh();
}

View File

@ -65,7 +65,6 @@
<Compile Include="BizInvoke\BizInvokeUtilities.cs" />
<Compile Include="BizInvoke\CallingConventionAdapter.cs" />
<Compile Include="BizInvoke\POSIXLibC.cs" />
<Compile Include="BizInvoke\DynamicLibraryImportResolver.cs" />
<Compile Include="BizInvoke\MemoryBlock.cs" />
<Compile Include="BizInvoke\MemoryBlockBase.cs" />
<Compile Include="BizInvoke\MemoryBlockUnix.cs" />
@ -84,7 +83,6 @@
<Compile Include="HawkFile.cs" />
<Compile Include="IImportResolver.cs" />
<Compile Include="IMonitor.cs" />
<Compile Include="InstanceDll.cs" />
<Compile Include="Log.cs" />
<Compile Include="MutableIntRange.cs" />
<Compile Include="OSTailoredCode.cs" />
@ -97,7 +95,13 @@
<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" />
<Compile Include="Win32\AVIWriterImports.cs" />
<Compile Include="Win32\ConsoleImports.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>

View File

@ -95,12 +95,9 @@ namespace BizHawk.Common.BizInvoke
}
}
public IntPtr Resolve(string entryPoint)
{
IntPtr ret;
EntryPoints.TryGetValue(entryPoint, out ret);
return ret;
}
public IntPtr? GetProcAddrOrNull(string entryPoint) => EntryPoints.TryGetValue(entryPoint, out var ret) ? ret : default;
public IntPtr GetProcAddrOrThrow(string entryPoint) => GetProcAddrOrNull(entryPoint) ?? throw new InvalidOperationException($"could not find {entryPoint} in exports");
}
static readonly Dictionary<Type, DelegateStorage> Impls = new Dictionary<Type, DelegateStorage>();

View File

@ -268,7 +268,7 @@ namespace BizHawk.Common.BizInvoke
return (o, dll, adapter) =>
{
var entryPtr = dll.SafeResolve(entryPointName);
var entryPtr = dll.GetProcAddrOrThrow(entryPointName);
var interopDelegate = adapter.GetDelegateForFunctionPointer(entryPtr, delegateType.CreateType());
o.GetType().GetField(field.Name).SetValue(o, interopDelegate);
};
@ -357,7 +357,7 @@ namespace BizHawk.Common.BizInvoke
return (o, dll, adapter) =>
{
var entryPtr = dll.SafeResolve(entryPointName);
var entryPtr = dll.GetProcAddrOrThrow(entryPointName);
o.GetType().GetField(field.Name).SetValue(
o, adapter.GetDepartureFunctionPointer(entryPtr, new ParameterInfo(returnType, paramTypes), o));
};

View File

@ -1,78 +0,0 @@
using System;
using System.IO;
using System.Reflection;
namespace BizHawk.Common.BizInvoke
{
/// TODO move this and all in IImportResolver.cs to OSTailoredCode.cs and refactor
public class DynamicLibraryImportResolver : IImportResolver, IDisposable
{
private IntPtr _p;
private readonly OSTailoredCode.ILinkedLibManager libLoader = OSTailoredCode.LinkedLibManager; //TODO inline?
public DynamicLibraryImportResolver(string dllName)
{
_p = libLoader.LoadOrThrow(dllName);
}
private string[] RelativeSearchPaths = {
"/",
"/dll/"
};
private string[] AbsoluteSearchPaths = {
"/usr/lib/",
"/usr/lib/bizhawk/"
};
/// <remarks>this is needed to actually find the DLL properly on Unix</remarks>
private void ResolveFilePath(ref string dllName)
{
if (dllName.IndexOf('/') != -1) return; // relative paths shouldn't contain '/'
var currDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase).Replace("file:", "");
string dll;
foreach (var p in AbsoluteSearchPaths)
{
dll = p + dllName;
if (File.Exists(dll))
{
dllName = dll;
return;
}
}
foreach (var p in RelativeSearchPaths)
{
dll = currDir + p + dllName;
if (File.Exists(dll))
{
dllName = dll;
return;
}
}
}
public IntPtr Resolve(string entryPoint)
{
return libLoader.GetProcAddr(_p, entryPoint);
}
private void Free()
{
if (_p == IntPtr.Zero) return; // already freed
libLoader.FreeByPtr(_p);
_p = IntPtr.Zero;
}
public void Dispose()
{
Free();
GC.SuppressFinalize(this);
}
~DynamicLibraryImportResolver()
{
Free();
}
}
}

View File

@ -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>

View File

@ -1,58 +1,122 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.AccessControl;
namespace BizHawk.Common
{
/// <summary>
/// interface for a dynamic link library or similar
/// </summary>
/// <summary>Implementors are able to provide pointers to functions in dynamically-linked libraries, which are loaded through some undefined mechanism.</summary>
/// <seealso cref="PatchImportResolver"/>
public interface IImportResolver
{
IntPtr Resolve(string entryPoint);
IntPtr? GetProcAddrOrNull(string entryPoint);
IntPtr GetProcAddrOrThrow(string entryPoint);
}
public static class ImportResolverExtensions
public class DynamicLibraryImportResolver : IDisposable, IImportResolver
{
/// <summary>
/// Resolve an entry point and throw an exception if that resolution is NULL
/// </summary>
public static IntPtr SafeResolve(this IImportResolver dll, string entryPoint)
private static readonly Lazy<IEnumerable<string>> asdf = new Lazy<IEnumerable<string>>(() =>
{
var ret = dll.Resolve(entryPoint);
if (ret == IntPtr.Zero)
{
throw new NullReferenceException($"Couldn't resolve entry point \"{entryPoint}\"");
}
var currDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase).Replace("file:", "");
return new[] { "/usr/lib/", "/usr/lib/bizhawk/", "./", "./dll/" }.Select(dir => dir[0] == '.' ? currDir + dir.Substring(1) : dir);
});
return ret;
private IntPtr _p;
public DynamicLibraryImportResolver(string dllName)
{
static string ResolveFilePath(string orig) => orig[0] == '/' ? orig : asdf.Value.Select(dir => dir + orig).FirstOrDefault(File.Exists) ?? orig;
_p = OSTailoredCode.LinkedLibManager.LoadOrThrow(OSTailoredCode.IsUnixHost ? ResolveFilePath(dllName) : dllName);
}
public IntPtr? GetProcAddrOrNull(string entryPoint) => OSTailoredCode.LinkedLibManager.GetProcAddrOrNull(_p, entryPoint);
public IntPtr GetProcAddrOrThrow(string entryPoint) => OSTailoredCode.LinkedLibManager.GetProcAddrOrThrow(_p, entryPoint);
private void DisposeHelper()
{
if (_p == IntPtr.Zero) return; // already freed
OSTailoredCode.LinkedLibManager.FreeByPtr(_p);
_p = IntPtr.Zero;
}
public void Dispose()
{
DisposeHelper();
GC.SuppressFinalize(this);
}
~DynamicLibraryImportResolver()
{
DisposeHelper();
}
}
/// <summary>
/// compose multiple ImportResolvers, where subsequent ones takes precedence over earlier ones
/// </summary>
public class InstanceDll : IDisposable, IImportResolver
{
public IntPtr HModule { get; private set; }
public InstanceDll(string dllPath)
{
// copy the dll to a temp directory
var path = TempFileManager.GetTempFilename(Path.GetFileNameWithoutExtension(dllPath), ".dll", false);
using var stream = new FileStream(path, FileMode.Create, FileSystemRights.FullControl, FileShare.ReadWrite | FileShare.Delete, 4 * 1024, FileOptions.None);
using var sdll = File.OpenRead(dllPath);
sdll.CopyTo(stream);
// try to locate dlls in the current directory (for libretro cores)
// this isn't foolproof but it's a little better than nothing
// setting PWD temporarily doesn't work. that'd be ideal since it supposedly gets searched early on,
// but i guess not with SetDllDirectory in effect
var envpath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process);
try
{
var envpath_new = $"{Path.GetDirectoryName(path)};{envpath}";
Environment.SetEnvironmentVariable("PATH", envpath_new, EnvironmentVariableTarget.Process);
HModule = OSTailoredCode.LinkedLibManager.LoadOrThrow(path); // consider using LoadLibraryEx instead of shenanigans?
var newfname = TempFileManager.RenameTempFilenameForDelete(path);
File.Move(path, newfname);
}
catch
{
// ignored
}
Environment.SetEnvironmentVariable("PATH", envpath, EnvironmentVariableTarget.Process);
}
public IntPtr? GetProcAddrOrNull(string procName) => OSTailoredCode.LinkedLibManager.GetProcAddrOrNull(HModule, procName);
public IntPtr GetProcAddrOrThrow(string procName) => OSTailoredCode.LinkedLibManager.GetProcAddrOrThrow(HModule, procName);
public void Dispose()
{
if (HModule == IntPtr.Zero) return; // already freed
OSTailoredCode.LinkedLibManager.FreeByPtr(HModule);
HModule = IntPtr.Zero;
}
}
/// <summary>Aggregates <see cref="IImportResolver">resolvers</see>, resolving addresses by searching through them, starting with the last.</summary>
public class PatchImportResolver : IImportResolver
{
private readonly List<IImportResolver> _resolvers = new List<IImportResolver>();
private readonly List<IImportResolver> _resolvers;
public PatchImportResolver(params IImportResolver[] rr)
public PatchImportResolver(params IImportResolver[] resolvers)
{
Add(rr);
}
public void Add(params IImportResolver[] rr)
{
_resolvers.AddRange(rr);
_resolvers = resolvers.ToList();
}
public IntPtr Resolve(string entryPoint)
public IntPtr? GetProcAddrOrNull(string entryPoint)
{
for (int i = _resolvers.Count - 1; i >= 0; i--)
for (var i = _resolvers.Count - 1; i != -1; i--)
{
var ret = _resolvers[i].Resolve(entryPoint);
if (ret != IntPtr.Zero)
return ret;
var ret = _resolvers[i].GetProcAddrOrNull(entryPoint);
if (ret != null) return ret.Value;
}
return IntPtr.Zero;
return null;
}
public IntPtr GetProcAddrOrThrow(string entryPoint) => GetProcAddrOrNull(entryPoint) ?? throw new IOException($"{entryPoint} was not found in any of the aggregated resolvers");
}
}

View File

@ -1,90 +0,0 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
namespace BizHawk.Common
{
public class InstanceDll : IDisposable, IImportResolver
{
[DllImport("kernel32.dll")]
public static extern UInt32 GetLastError();
public InstanceDll(string dllPath)
{
// copy the dll to a temp directory
var path = TempFileManager.GetTempFilename(Path.GetFileNameWithoutExtension(dllPath), ".dll", false);
using (var stream = new FileStream(path, FileMode.Create, System.Security.AccessControl.FileSystemRights.FullControl, FileShare.ReadWrite | FileShare.Delete, 4 * 1024, FileOptions.None))
using (var sdll = File.OpenRead(dllPath))
sdll.CopyTo(stream);
// try to locate dlls in the current directory (for libretro cores)
// this isnt foolproof but its a little better than nothing
// setting PWD temporarily doesnt work. that'd be ideal since it supposedly gets searched early on,
// but i guess not with SetDllDirectory in effect
var envpath = Environment.GetEnvironmentVariable("PATH", EnvironmentVariableTarget.Process);
try
{
string envpath_new = $"{Path.GetDirectoryName(path)};{envpath}";
Environment.SetEnvironmentVariable("PATH", envpath_new, EnvironmentVariableTarget.Process);
_hModule = LoadLibrary(path); //consider using LoadLibraryEx instead of shenanigans?
if (_hModule == IntPtr.Zero)
{
var lastError = GetLastError();
throw new InvalidOperationException($"Failed to load plugin {path}, error code: 0x{lastError:X}");
}
var newfname = TempFileManager.RenameTempFilenameForDelete(path);
File.Move(path, newfname);
}
finally
{
Environment.SetEnvironmentVariable("PATH", envpath, EnvironmentVariableTarget.Process);
}
}
[Flags]
enum LoadLibraryFlags : uint
{
DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);
[DllImport("kernel32.dll")]
static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
static extern bool FreeLibrary(IntPtr hModule);
public IntPtr GetProcAddress(string procName)
{
return GetProcAddress(_hModule, procName);
}
public IntPtr HModule => _hModule;
IntPtr IImportResolver.Resolve(string entryPoint)
{
return GetProcAddress(entryPoint);
}
public void Dispose()
{
if (_hModule != IntPtr.Zero)
{
FreeLibrary(_hModule);
_hModule = IntPtr.Zero;
}
}
private IntPtr _hModule;
}
}

View File

@ -10,27 +10,19 @@ namespace BizHawk.Common
{
public static class OSTailoredCode
{
/// <remarks>
/// macOS doesn't use <see cref="PlatformID.MacOSX">PlatformID.MacOSX</see>
/// </remarks>
/// <remarks>macOS doesn't use <see cref="PlatformID.MacOSX">PlatformID.MacOSX</see></remarks>
public static readonly DistinctOS CurrentOS = Environment.OSVersion.Platform == PlatformID.Unix
? SimpleSubshell("uname", "-s", "Can't determine OS") == "Darwin" ? DistinctOS.macOS : DistinctOS.Linux
: DistinctOS.Windows;
public static readonly bool IsUnixHost = CurrentOS != DistinctOS.Windows;
private static readonly Lazy<ILinkedLibManager> _LinkedLibManager = new Lazy<ILinkedLibManager>(() =>
private static readonly Lazy<ILinkedLibManager> _LinkedLibManager = new Lazy<ILinkedLibManager>(() => CurrentOS switch
{
switch (CurrentOS)
{
case DistinctOS.Linux:
case DistinctOS.macOS:
return new UnixMonoLLManager();
case DistinctOS.Windows:
return new WindowsLLManager();
default:
throw new ArgumentOutOfRangeException();
}
DistinctOS.Linux => (ILinkedLibManager) new UnixMonoLLManager(),
DistinctOS.macOS => new UnixMonoLLManager(),
DistinctOS.Windows => new WindowsLLManager(),
_ => throw new ArgumentOutOfRangeException()
});
public static ILinkedLibManager LinkedLibManager => _LinkedLibManager.Value;
@ -38,78 +30,87 @@ namespace BizHawk.Common
/// <remarks>this interface's inheritors hide OS-specific implementation details</remarks>
public interface ILinkedLibManager
{
int FreeByPtr(IntPtr hModule);
IntPtr? GetProcAddrOrNull(IntPtr hModule, string procName);
IntPtr GetProcAddrOrThrow(IntPtr hModule, string procName);
IntPtr? LoadOrNull(string dllToLoad);
IntPtr LoadOrThrow(string dllToLoad);
IntPtr GetProcAddr(IntPtr hModule, string procName); //TODO also split into nullable and throwing?
int FreeByPtr(IntPtr hModule);
}
/// <remarks>This class is copied from a tutorial, so don't git blame and then email me expecting insight.</remarks>
private class UnixMonoLLManager : ILinkedLibManager
{
private const int RTLD_NOW = 2;
[DllImport("libdl.so.2")]
private static extern int dlclose(IntPtr handle);
[DllImport("libdl.so.2")]
private static extern IntPtr dlerror();
[DllImport("libdl.so.2")]
private static extern IntPtr dlopen(string fileName, int flags);
[DllImport("libdl.so.2")]
private static extern IntPtr dlsym(IntPtr handle, string symbol);
public IntPtr GetProcAddr(IntPtr hModule, string procName)
public int FreeByPtr(IntPtr hModule) => dlclose(hModule);
public IntPtr? GetProcAddrOrNull(IntPtr hModule, string procName)
{
dlerror();
var res = dlsym(hModule, procName);
var errPtr = dlerror();
if (errPtr != IntPtr.Zero) throw new InvalidOperationException($"error in {nameof(dlsym)}: {Marshal.PtrToStringAnsi(errPtr)}");
return res;
var p = dlsym(hModule, procName);
return p == IntPtr.Zero ? default : p;
}
public int FreeByPtr(IntPtr hModule) => dlclose(hModule);
public IntPtr GetProcAddrOrThrow(IntPtr hModule, string procName)
{
_ = dlerror(); // the Internet said to do this
var p = GetProcAddrOrNull(hModule, procName);
if (p != null) return p.Value;
var errCharPtr = dlerror();
throw new InvalidOperationException($"error in {nameof(dlsym)}{(errCharPtr == IntPtr.Zero ? string.Empty : $": {Marshal.PtrToStringAnsi(errCharPtr)}")}");
}
public IntPtr? LoadOrNull(string dllToLoad)
{
const int RTLD_NOW = 2;
var p = dlopen(dllToLoad, RTLD_NOW);
return p == IntPtr.Zero ? default(IntPtr?) : p;
return p == IntPtr.Zero ? default : p;
}
public IntPtr LoadOrThrow(string dllToLoad)
{
var p = LoadOrNull(dllToLoad);
if (!p.HasValue) throw new InvalidOperationException($"got null pointer from {nameof(dlopen)}, error: {Marshal.PtrToStringAnsi(dlerror())}");
return p.Value;
}
public IntPtr LoadOrThrow(string dllToLoad) => LoadOrNull(dllToLoad) ?? throw new InvalidOperationException($"got null pointer from {nameof(dlopen)}, error: {Marshal.PtrToStringAnsi(dlerror())}");
}
private class WindowsLLManager : ILinkedLibManager
{
// comments reference extern functions removed from SevenZip.NativeMethods
[DllImport("kernel32.dll")]
private static extern bool FreeLibrary(IntPtr hModule); // return type was annotated MarshalAs(UnmanagedType.Bool)
[DllImport("kernel32.dll")]
private static extern uint GetLastError();
[DllImport("kernel32.dll")] // had BestFitMapping = false, ThrowOnUnmappableChar = true
[DllImport("kernel32.dll", SetLastError = true)] // had BestFitMapping = false, ThrowOnUnmappableChar = true
private static extern IntPtr GetProcAddress(IntPtr hModule, string procName); // param procName was annotated `[MarshalAs(UnmanagedType.LPStr)]`
[DllImport("kernel32.dll")] // had BestFitMapping = false, ThrowOnUnmappableChar = true
[DllImport("kernel32.dll", SetLastError = true)] // had BestFitMapping = false, ThrowOnUnmappableChar = true
private static extern IntPtr LoadLibrary(string dllToLoad); // param dllToLoad was annotated `[MarshalAs(UnmanagedType.LPStr)]`
public IntPtr GetProcAddr(IntPtr hModule, string procName) => GetProcAddress(hModule, procName);
public int FreeByPtr(IntPtr hModule) => FreeLibrary(hModule) ? 0 : 1;
public int FreeByPtr(IntPtr hModule) => FreeLibrary(hModule) ? 1 : 0;
public IntPtr? GetProcAddrOrNull(IntPtr hModule, string procName)
{
var p = GetProcAddress(hModule, procName);
return p == IntPtr.Zero ? default : p;
}
public IntPtr GetProcAddrOrThrow(IntPtr hModule, string procName) => GetProcAddrOrNull(hModule, procName) ?? throw new InvalidOperationException($"got null pointer from {nameof(GetProcAddress)}, error code: {GetLastError()}");
public IntPtr? LoadOrNull(string dllToLoad)
{
var p = LoadLibrary(dllToLoad);
return p == IntPtr.Zero ? default(IntPtr?) : p;
return p == IntPtr.Zero ? default : p;
}
public IntPtr LoadOrThrow(string dllToLoad)
{
var p = LoadOrNull(dllToLoad);
if (!p.HasValue) throw new InvalidOperationException($"got null pointer from {nameof(LoadLibrary)}, error code: {GetLastError()}");
return p.Value;
}
public IntPtr LoadOrThrow(string dllToLoad) => LoadOrNull(dllToLoad) ?? throw new InvalidOperationException($"got null pointer from {nameof(LoadLibrary)}, error code: {GetLastError()}");
}
public enum DistinctOS : byte

View File

@ -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

View File

@ -0,0 +1,139 @@
using System;
using System.Runtime.InteropServices;
namespace BizHawk.Common
{
public static class AVIWriterImports
{
[Flags]
public enum OpenFileStyle : uint
{
OF_WRITE = 0x00000001,
OF_CREATE = 0x00001000
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct AVISTREAMINFOW
{
public int fccType;
public int fccHandler;
public int dwFlags;
public int dwCaps;
public short wPriority;
public short wLanguage;
public int dwScale;
public int dwRate;
public int dwStart;
public int dwLength;
public int dwInitialFrames;
public int dwSuggestedBufferSize;
public int dwQuality;
public int dwSampleSize;
public RECT rcFrame;
public int dwEditCount;
public int dwFormatChangeCount;
[MarshalAs(UnmanagedType.LPWStr, SizeConst=64)] public string szName;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BITMAPINFOHEADER
{
public uint biSize;
public int biWidth;
public int biHeight;
public ushort biPlanes;
public ushort biBitCount;
public uint biCompression;
public uint biSizeImage;
public int biXPelsPerMeter;
public int biYPelsPerMeter;
public uint biClrUsed;
public uint biClrImportant;
public void Init()
{
biSize = (uint)Marshal.SizeOf(this);
}
}
[StructLayout(LayoutKind.Sequential)]
public struct AVICOMPRESSOPTIONS
{
public int fccType;
public int fccHandler;
public int dwKeyFrameEvery;
public int dwQuality;
public int dwBytesPerSecond;
public int dwFlags;
public IntPtr lpFormat;
public int cbFormat;
public IntPtr lpParms;
public int cbParms;
public int dwInterleaveEvery;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct WAVEFORMATEX
{
public ushort wFormatTag;
public ushort nChannels;
public uint nSamplesPerSec;
public uint nAvgBytesPerSec;
public ushort nBlockAlign;
public ushort wBitsPerSample;
public ushort cbSize;
public void Init()
{
cbSize = (ushort)Marshal.SizeOf(this);
}
}
/// <summary>Create a new stream in an existing file and creates an interface to the new stream</summary>
[DllImport("avifil32.dll")]
public static extern int AVIFileCreateStreamW(IntPtr pfile, out IntPtr ppavi, ref AVISTREAMINFOW psi);
[DllImport("avifil32.dll", SetLastError = true)]
public static extern void AVIFileInit();
[DllImport("avifil32.dll", SetLastError = true)]
public static extern int AVIFileOpenW(ref IntPtr pAviFile, [MarshalAs(UnmanagedType.LPWStr)] string szFile, OpenFileStyle uMode, int lpHandler);
/// <summary>Release an open AVI stream</summary>
[DllImport("avifil32.dll")]
public static extern int AVIFileRelease(IntPtr pfile);
/// <summary>Create a compressed stream from an uncompressed stream and a compression filter, and returns the address of a pointer to the compressed stream</summary>
[DllImport("avifil32.dll")]
public static extern int AVIMakeCompressedStream(out IntPtr ppsCompressed, IntPtr psSource, ref AVICOMPRESSOPTIONS lpOptions, IntPtr pclsidHandler);
/// <summary>Retrieve the save options for a file and returns them in a buffer</summary>
[DllImport("avifil32.dll")]
public static extern unsafe int AVISaveOptions(IntPtr hwnd, int flags, int streams, void* ppAvi, void* plpOptions);
/// <inheritdoc cref="AVIFileRelease"/>
[DllImport("avifil32.dll")]
public static extern int AVIStreamRelease(IntPtr pavi);
/// <summary>Set the format of a stream at the specified position</summary>
[DllImport("avifil32.dll")]
public static extern int AVIStreamSetFormat(IntPtr pavi, int lPos, ref BITMAPINFOHEADER lpFormat, int cbFormat);
/// <inheritdoc cref="AVIStreamSetFormat(System.IntPtr,int,ref BizHawk.Common.AVIWriterImports.BITMAPINFOHEADER,int)"/>
[DllImport("avifil32.dll")]
public static extern int AVIStreamSetFormat(IntPtr pavi, int lPos, ref WAVEFORMATEX lpFormat, int cbFormat);
/// <summary>Write data to a stream</summary>
[DllImport("avifil32.dll")]
public static extern int AVIStreamWrite(IntPtr pavi, int lStart, int lSamples, IntPtr lpBuffer, int cbBuffer, int dwFlags, IntPtr plSampWritten, out int plBytesWritten);
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Runtime.InteropServices;
namespace BizHawk.Common
{
public static class ConsoleImports
{
public enum FileType : uint
{
FileTypeUnknown = 0,
FileTypeDisk = 1,
FileTypeChar = 2,
FileTypePipe = 3,
FileTypeRemote = 0x8000
}
[DllImport("kernel32.dll")]
public static extern FileType GetFileType(IntPtr hFile);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetCommandLine();
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll", SetLastError = true)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool AttachConsole(int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = false)]
public static extern bool FreeConsole();
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr GetStdHandle(int nStdHandle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool SetStdHandle(int nStdHandle, IntPtr hConsoleOutput);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CreateFile(string fileName, int desiredAccess, int shareMode, IntPtr securityAttributes, int creationDisposition, int flagsAndAttributes, IntPtr templateFile);
[DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)]
public static extern bool CloseHandle(IntPtr handle);
}
}

View File

@ -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");
}
}

View File

@ -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
}
}
}

View File

@ -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 */ {}
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,164 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
namespace BizHawk.Common
{
public static class Win32Imports
{
public const int MAX_PATH = 260;
public delegate int BFFCALLBACK(IntPtr hwnd, uint uMsg, IntPtr lParam, IntPtr lpData);
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct BROWSEINFO
{
public IntPtr hwndOwner;
public IntPtr pidlRoot;
public IntPtr pszDisplayName;
[MarshalAs(UnmanagedType.LPTStr)] public string lpszTitle;
public FLAGS ulFlags;
[MarshalAs(UnmanagedType.FunctionPtr)] public BFFCALLBACK lpfn;
public IntPtr lParam;
public int iImage;
[Flags]
public enum FLAGS
{
/// <remarks>BIF_RETURNONLYFSDIRS</remarks>
RestrictToFilesystem = 0x0001,
/// <remarks>BIF_DONTGOBELOWDOMAIN</remarks>
RestrictToDomain = 0x0002,
/// <remarks>BIF_RETURNFSANCESTORS</remarks>
RestrictToSubfolders = 0x0008,
/// <remarks>BIF_EDITBOX</remarks>
ShowTextBox = 0x0010,
/// <remarks>BIF_VALIDATE</remarks>
ValidateSelection = 0x0020,
/// <remarks>BIF_NEWDIALOGSTYLE</remarks>
NewDialogStyle = 0x0040,
/// <remarks>BIF_BROWSEFORCOMPUTER</remarks>
BrowseForComputer = 0x1000,
/// <remarks>BIF_BROWSEFORPRINTER</remarks>
BrowseForPrinter = 0x2000,
/// <remarks>BIF_BROWSEINCLUDEFILES</remarks>
BrowseForEverything = 0x4000
}
}
[StructLayout(LayoutKind.Sequential)]
public struct HDITEM
{
public Mask mask;
public int cxy;
[MarshalAs(UnmanagedType.LPTStr)] public string pszText;
public IntPtr hbm;
public int cchTextMax;
public Format fmt;
public IntPtr lParam;
// _WIN32_IE >= 0x0300
public int iImage;
public int iOrder;
// _WIN32_IE >= 0x0500
public uint type;
public IntPtr pvFilter;
// _WIN32_WINNT >= 0x0600
public uint state;
[Flags]
public enum Mask
{
Format = 0x4
}
[Flags]
public enum Format
{
SortDown = 0x200,
SortUp = 0x400
}
}
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00000002-0000-0000-C000-000000000046")]
public interface IMalloc
{
[PreserveSig] IntPtr Alloc([In] int cb);
[PreserveSig] IntPtr Realloc([In] IntPtr pv, [In] int cb);
[PreserveSig] void Free([In] IntPtr pv);
[PreserveSig] int GetSize([In] IntPtr pv);
[PreserveSig] int DidAlloc(IntPtr pv);
[PreserveSig] void HeapMinimize();
}
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint _control87(uint @new, uint mask);
[DllImport("kernel32.dll", EntryPoint = "DeleteFileW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
public static extern bool DeleteFileW([MarshalAs(UnmanagedType.LPWStr)] string lpFileName);
[DllImport("user32.dll")]
public static extern IntPtr GetActiveWindow();
[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("msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static extern IntPtr MemSet(IntPtr dest, int c, uint count);
[DllImport("shlwapi.dll", CharSet = CharSet.Auto)]
public static extern bool PathRelativePathTo([Out] StringBuilder pszPath, [In] string pszFrom, [In] FileAttributes dwAttrFrom, [In] string pszTo, [In] FileAttributes dwAttrTo);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, ref HDITEM lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern unsafe bool SetCurrentDirectoryW(byte* lpPathName);
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SHBrowseForFolder(ref BROWSEINFO bi);
[DllImport("shell32.dll")]
public static extern int SHGetMalloc(out IMalloc ppMalloc);
[DllImport("shell32.dll")]
public static extern int SHGetPathFromIDList(IntPtr pidl, StringBuilder Path);
[DllImport("shell32.dll")]
public static extern int SHGetSpecialFolderLocation(IntPtr hwndOwner, int nFolder, out IntPtr ppidl);
[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);
}
}

View File

@ -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();
}
}
}

View File

@ -11,9 +11,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
/// </summary>
private IntPtr AudDll;
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
/// <summary>
/// Gets the size of the mupen64plus audio buffer
/// </summary>
@ -44,13 +41,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
/// <param name="core">Core with loaded core api</param>
public mupen64plusAudioApi(mupen64plusApi core)
{
T GetAudioDelegate<T>(string proc) where T : Delegate => mupen64plusApi.GetTypedDelegate<T>(AudDll, proc);
AudDll = core.AttachPlugin(mupen64plusApi.m64p_plugin_type.M64PLUGIN_AUDIO,
"mupen64plus-audio-bkm.dll");
// Connect dll functions
dllGetBufferSize = (GetBufferSize)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "GetBufferSize"), typeof(GetBufferSize));
dllReadAudioBuffer = (ReadAudioBuffer)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "ReadAudioBuffer"), typeof(ReadAudioBuffer));
dllGetAudioRate = (GetAudioRate)Marshal.GetDelegateForFunctionPointer(GetProcAddress(AudDll, "GetAudioRate"), typeof(GetAudioRate));
dllGetBufferSize = GetAudioDelegate<GetBufferSize>("GetBufferSize");
dllReadAudioBuffer = GetAudioDelegate<ReadAudioBuffer>("ReadAudioBuffer");
dllGetAudioRate = GetAudioDelegate<GetAudioRate>("GetAudioRate");
}
/// <summary>

View File

@ -576,46 +576,50 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
cb.GetType();
}
internal static T GetTypedDelegate<T>(IntPtr lib, string proc) where T : Delegate => (T) Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddrOrThrow(lib, proc), typeof(T));
/// <summary>
/// Look up function pointers in the dlls
/// </summary>
void connectFunctionPointers()
{
m64pCoreStartup = (CoreStartup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreStartup"), typeof(CoreStartup));
m64pCoreShutdown = (CoreShutdown)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreShutdown"), typeof(CoreShutdown));
m64pCoreDoCommandByteArray = (CoreDoCommandByteArray)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandByteArray));
m64pCoreDoCommandPtr = (CoreDoCommandPtr)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandPtr));
m64pCoreDoCommandRefInt = (CoreDoCommandRefInt)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRefInt));
m64pCoreDoCommandFrameCallback = (CoreDoCommandFrameCallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandFrameCallback));
m64pCoreDoCommandVICallback = (CoreDoCommandVICallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandVICallback));
m64pCoreDoCommandRenderCallback = (CoreDoCommandRenderCallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDoCommand"), typeof(CoreDoCommandRenderCallback));
m64pCoreAttachPlugin = (CoreAttachPlugin)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreAttachPlugin"), typeof(CoreAttachPlugin));
m64pCoreDetachPlugin = (CoreDetachPlugin)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "CoreDetachPlugin"), typeof(CoreDetachPlugin));
m64pConfigOpenSection = (ConfigOpenSection)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "ConfigOpenSection"), typeof(ConfigOpenSection));
m64pConfigSetParameter = (ConfigSetParameter)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameter));
m64pConfigSetParameterStr = (ConfigSetParameterStr)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "ConfigSetParameter"), typeof(ConfigSetParameterStr));
m64pCoreSaveState = (savestates_save_bkm)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "savestates_save_bkm"), typeof(savestates_save_bkm));
m64pCoreLoadState = (savestates_load_bkm)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "savestates_load_bkm"), typeof(savestates_load_bkm));
m64pDebugMemGetPointer = (DebugMemGetPointer)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugMemGetPointer"), typeof(DebugMemGetPointer));
m64pDebugSetCallbacks = (DebugSetCallbacks)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugSetCallbacks"), typeof(DebugSetCallbacks));
m64pDebugBreakpointLookup = (DebugBreakpointLookup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugBreakpointLookup"), typeof(DebugBreakpointLookup));
m64pDebugBreakpointCommand = ( DebugBreakpointCommand )Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugBreakpointCommand"), typeof(DebugBreakpointCommand));
m64pDebugGetState = (DebugGetState)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugGetState"), typeof(DebugGetState));
m64pDebugSetRunState = (DebugSetRunState)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugSetRunState"), typeof(DebugSetRunState));
m64pDebugStep = (DebugStep)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "DebugStep"), typeof(DebugStep));
m64pMemGetSize = (MemGetSize)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "MemGetSize"), typeof(MemGetSize));
m64pinit_saveram = (init_saveram)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "init_saveram"), typeof(init_saveram));
m64psave_saveram = (save_saveram)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "save_saveram"), typeof(save_saveram));
m64pload_saveram = (load_saveram)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "load_saveram"), typeof(load_saveram));
T GetCoreDelegate<T>(string proc) where T : Delegate => GetTypedDelegate<T>(CoreDll, proc);
m64pSetTraceCallback = (SetTraceCallback)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "SetTraceCallback"), typeof(SetTraceCallback));
m64pCoreStartup = GetCoreDelegate<CoreStartup>("CoreStartup");
m64pCoreShutdown = GetCoreDelegate<CoreShutdown>("CoreShutdown");
m64pCoreDoCommandByteArray = GetCoreDelegate<CoreDoCommandByteArray>("CoreDoCommand");
m64pCoreDoCommandPtr = GetCoreDelegate<CoreDoCommandPtr>("CoreDoCommand");
m64pCoreDoCommandRefInt = GetCoreDelegate<CoreDoCommandRefInt>("CoreDoCommand");
m64pCoreDoCommandFrameCallback = GetCoreDelegate<CoreDoCommandFrameCallback>("CoreDoCommand");
m64pCoreDoCommandVICallback = GetCoreDelegate<CoreDoCommandVICallback>("CoreDoCommand");
m64pCoreDoCommandRenderCallback = GetCoreDelegate<CoreDoCommandRenderCallback>("CoreDoCommand");
m64pCoreAttachPlugin = GetCoreDelegate<CoreAttachPlugin>("CoreAttachPlugin");
m64pCoreDetachPlugin = GetCoreDelegate<CoreDetachPlugin>("CoreDetachPlugin");
m64pConfigOpenSection = GetCoreDelegate<ConfigOpenSection>("ConfigOpenSection");
m64pConfigSetParameter = GetCoreDelegate<ConfigSetParameter>("ConfigSetParameter");
m64pConfigSetParameterStr = GetCoreDelegate<ConfigSetParameterStr>("ConfigSetParameter");
m64pCoreSaveState = GetCoreDelegate<savestates_save_bkm>("savestates_save_bkm");
m64pCoreLoadState = GetCoreDelegate<savestates_load_bkm>("savestates_load_bkm");
m64pDebugMemGetPointer = GetCoreDelegate<DebugMemGetPointer>("DebugMemGetPointer");
m64pDebugSetCallbacks = GetCoreDelegate<DebugSetCallbacks>("DebugSetCallbacks");
m64pDebugBreakpointLookup = GetCoreDelegate<DebugBreakpointLookup>("DebugBreakpointLookup");
m64pDebugBreakpointCommand = GetCoreDelegate<DebugBreakpointCommand>("DebugBreakpointCommand");
m64pDebugGetState = GetCoreDelegate<DebugGetState>("DebugGetState");
m64pDebugSetRunState = GetCoreDelegate<DebugSetRunState>("DebugSetRunState");
m64pDebugStep = GetCoreDelegate<DebugStep>("DebugStep");
m64pMemGetSize = GetCoreDelegate<MemGetSize>("MemGetSize");
m64pinit_saveram = GetCoreDelegate<init_saveram>("init_saveram");
m64psave_saveram = GetCoreDelegate<save_saveram>("save_saveram");
m64pload_saveram = GetCoreDelegate<load_saveram>("load_saveram");
m64pGetRegisters = (GetRegisters)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "GetRegisters"), typeof(GetRegisters));
m64pSetTraceCallback = GetCoreDelegate<SetTraceCallback>("SetTraceCallback");
m64p_read_memory_8 = (biz_read_memory)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "biz_read_memory"), typeof(biz_read_memory));
m64p_write_memory_8 = (biz_write_memory)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "biz_write_memory"), typeof(biz_write_memory));
m64pGetRegisters = GetCoreDelegate<GetRegisters>("GetRegisters");
m64p_decode_op = (biz_r4300_decode_op)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(CoreDll, "biz_r4300_decode_op"), typeof(biz_r4300_decode_op));
m64p_read_memory_8 = GetCoreDelegate<biz_read_memory>("biz_read_memory");
m64p_write_memory_8 = GetCoreDelegate<biz_write_memory>("biz_write_memory");
m64p_decode_op = GetCoreDelegate<biz_r4300_decode_op>("biz_r4300_decode_op");
}
/// <summary>
@ -711,28 +715,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)
@ -933,8 +990,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
AttachedPlugin plugin;
plugin.dllHandle = libLoader.LoadOrThrow(PluginName);
plugin.dllStartup = (PluginStartup)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(plugin.dllHandle, "PluginStartup"), typeof(PluginStartup));
plugin.dllShutdown = (PluginShutdown)Marshal.GetDelegateForFunctionPointer(libLoader.GetProcAddr(plugin.dllHandle, "PluginShutdown"), typeof(PluginShutdown));
plugin.dllStartup = GetTypedDelegate<PluginStartup>(plugin.dllHandle, "PluginStartup");
plugin.dllShutdown = GetTypedDelegate<PluginShutdown>(plugin.dllHandle, "PluginShutdown");
plugin.dllStartup(CoreDll, null, null);
m64p_error result = m64pCoreAttachPlugin(type, plugin.dllHandle);

View File

@ -11,9 +11,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
{
IntPtr InpDll;
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);// Input plugin specific
/// <summary>
/// Sets a callback to use when the mupen core wants controller buttons
/// </summary>
@ -66,14 +63,16 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
public mupen64plusInputApi(mupen64plusApi core)
{
T GetInputDelegate<T>(string proc) where T : Delegate => mupen64plusApi.GetTypedDelegate<T>(InpDll, proc);
InpDll = core.AttachPlugin(mupen64plusApi.m64p_plugin_type.M64PLUGIN_INPUT,
"mupen64plus-input-bkm.dll");
mupen64plusApi.m64p_error result;
InpSetInputCallback = (SetInputCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetInputCallback"), typeof(SetInputCallback));
InpSetRumbleCallback = (SetRumbleCallback)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetRumbleCallback"), typeof(SetRumbleCallback));
InpSetControllerPakType = (SetControllerPakType)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetControllerPakType"), typeof(SetControllerPakType));
InpSetControllerConnected = (SetControllerConnected)Marshal.GetDelegateForFunctionPointer(GetProcAddress(InpDll, "SetControllerConnected"), typeof(SetControllerConnected));
InpSetInputCallback = GetInputDelegate<SetInputCallback>("SetInputCallback");
InpSetRumbleCallback = GetInputDelegate<SetRumbleCallback>("SetRumbleCallback");
InpSetControllerPakType = GetInputDelegate<SetControllerPakType>("SetControllerPakType");
InpSetControllerConnected = GetInputDelegate<SetControllerConnected>("SetControllerConnected");
m64pRumbleCallback = new RumbleCallback(FireOnRumbleChange);
result = InpSetRumbleCallback(m64pRumbleCallback);

View File

@ -6,14 +6,13 @@ using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
{
class mupen64plusVideoApi
{
IntPtr GfxDll;// Graphics plugin specific
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
IntPtr GfxDll;
/// <summary>
/// Fills a provided buffer with the mupen64plus framebuffer
@ -64,10 +63,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
GfxDll = core.AttachPlugin(mupen64plusApi.m64p_plugin_type.M64PLUGIN_GFX,
videoplugin);
GFXReadScreen2 = (ReadScreen2)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "ReadScreen2"), typeof(ReadScreen2));
GFXReadScreen2Res = (ReadScreen2Res)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "ReadScreen2"), typeof(ReadScreen2Res));
if(GetProcAddress(GfxDll, "GetScreenTextureID") != IntPtr.Zero)
GFXGetScreenTextureID = (GetScreenTextureID)Marshal.GetDelegateForFunctionPointer(GetProcAddress(GfxDll, "GetScreenTextureID"), typeof(GetScreenTextureID));
GFXReadScreen2 = mupen64plusApi.GetTypedDelegate<ReadScreen2>(GfxDll, "ReadScreen2");
GFXReadScreen2Res = mupen64plusApi.GetTypedDelegate<ReadScreen2Res>(GfxDll, "ReadScreen2");
var funcPtr = OSTailoredCode.LinkedLibManager.GetProcAddrOrNull(GfxDll, "GetScreenTextureID");
if (funcPtr != null) GFXGetScreenTextureID = (GetScreenTextureID) Marshal.GetDelegateForFunctionPointer(funcPtr.Value, typeof(GetScreenTextureID));
}
public void GetScreenDimensions(ref int width, ref int height)

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
@ -90,40 +91,31 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
IDisposable Save();
}
private class Win32_FPCtrl : IFPCtrl
{
[DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern uint _control87(uint @new, uint mask);
[Conditional("DEBUG")]
public static void PrintCurrentFP() => Console.WriteLine($"Current FP word: 0x{Win32Imports._control87(0, 0):X8}");
public static void PrintCurrentFP()
{
uint curr = _control87(0, 0);
Console.WriteLine("Current FP word: 0x{0:x8}", curr);
}
uint cw;
private uint cw;
public IDisposable Save()
{
cw = _control87(0, 0);
_control87(0x00000, 0x30000);
cw = Win32Imports._control87(0, 0);
Win32Imports._control87(0x00000, 0x30000);
return this;
}
public void Dispose()
{
_control87(cw, 0x30000);
Win32Imports._control87(cw, 0x30000);
}
}
private class Unix_FPCtrl : IFPCtrl
{
public IDisposable Save()
{
return this;
}
public void Dispose()
{ }
public IDisposable Save() => this;
public void Dispose() {}
}
IFPCtrl FP;

View File

@ -210,9 +210,9 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK
_push = push;
_pull = pull;
_exporter = BizExvoker.GetExvoker(this, CallingConventionAdapters.Waterbox);
_readcb = _exporter.SafeResolve("CommsReadCallback");
_pollcb = _exporter.SafeResolve("CommsPollCallback");
_writecb = _exporter.SafeResolve("CommsWriteCallback");
_readcb = _exporter.GetProcAddrOrThrow("CommsReadCallback");
_pollcb = _exporter.GetProcAddrOrThrow("CommsPollCallback");
_writecb = _exporter.GetProcAddrOrThrow("CommsWriteCallback");
ConnectPointers();
}

View File

@ -5,6 +5,8 @@ using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using BizHawk.Common;
namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
{
/*
@ -25,35 +27,22 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
public class GenDbgHlp : IDisposable
{
private static class Win32
{
[DllImport("kernel32.dll")]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
public static extern bool FreeLibrary(IntPtr hModule);
}
// config
const string modulename = "libgenplusgx.dll";
const string symbolname = @"D:\encodes\bizhawksrc\genplus-gx\libretro\msvc\Debug\vars.txt";
const int start = 0x0c7d8000 - 0x0c540000;
const int length = 0x01082000;
bool disposed = false;
private bool disposed => DllBase == IntPtr.Zero;
public void Dispose()
{
if (!disposed)
{
Win32.FreeLibrary(DllBase);
DllBase = IntPtr.Zero;
disposed = true;
}
if (DllBase == IntPtr.Zero) return; // already freed
OSTailoredCode.LinkedLibManager.FreeByPtr(DllBase);
DllBase = IntPtr.Zero;
}
IntPtr DllBase;
private IntPtr DllBase;
List<Symbol> SymbolsByAddr = new List<Symbol>();
Dictionary<string, Symbol> SymbolsByName = new Dictionary<string, Symbol>();
@ -145,10 +134,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
}
SymbolsByAddr.Sort();
}
DllBase = Win32.LoadLibrary(modulename);
if (DllBase == IntPtr.Zero)
throw new Exception();
DllBase = OSTailoredCode.LinkedLibManager.LoadOrThrow(modulename);
}
public List<Symbol> Find(IntPtr addr, int length)

View File

@ -23,9 +23,6 @@ namespace BizHawk.Emulation.Cores.Libretro
//YUCK
public LibretroCore core;
[DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
public static unsafe extern void* CopyMemory(void* dest, void* src, ulong count);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate IntPtr DllInit(IntPtr dllModule);
@ -49,6 +46,8 @@ namespace BizHawk.Emulation.Cores.Libretro
public LibretroApi(string dllPath, string corePath)
{
T GetTypedDelegate<T>(string proc) where T : Delegate => (T) Marshal.GetDelegateForFunctionPointer(instanceDll.GetProcAddrOrThrow(proc), typeof(T));
InstanceName = "libretro_" + Guid.NewGuid().ToString();
var pipeName = InstanceName;
@ -56,11 +55,11 @@ namespace BizHawk.Emulation.Cores.Libretro
instanceDll = new InstanceDll(dllPath);
instanceDllCore = new InstanceDll(corePath);
var dllinit = (DllInit)Marshal.GetDelegateForFunctionPointer(instanceDll.GetProcAddress("DllInit"), typeof(DllInit));
Message = (MessageApi)Marshal.GetDelegateForFunctionPointer(instanceDll.GetProcAddress("Message"), typeof(MessageApi));
_copyBuffer = (BufferApi)Marshal.GetDelegateForFunctionPointer(instanceDll.GetProcAddress("CopyBuffer"), typeof(BufferApi));
_setBuffer = (BufferApi)Marshal.GetDelegateForFunctionPointer(instanceDll.GetProcAddress("SetBuffer"), typeof(BufferApi));
SetVariable = (SetVariableApi)Marshal.GetDelegateForFunctionPointer(instanceDll.GetProcAddress("SetVariable"), typeof(SetVariableApi));
var dllinit = GetTypedDelegate<DllInit>("DllInit");
Message = GetTypedDelegate<MessageApi>("Message");
_copyBuffer = GetTypedDelegate<BufferApi>("CopyBuffer");
_setBuffer = GetTypedDelegate<BufferApi>("SetBuffer");
SetVariable = GetTypedDelegate<SetVariableApi>("SetVariable");
comm = (CommStruct*)dllinit(instanceDllCore.HModule).ToPointer();
@ -68,10 +67,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);

View File

@ -390,18 +390,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
#endregion
public IntPtr Resolve(string entryPoint)
{
SymbolEntry<long> sym;
if (_symdict.TryGetValue(entryPoint, out sym))
{
return Z.SS(sym.Value + _loadoffset);
}
else
{
return IntPtr.Zero;
}
}
public IntPtr? GetProcAddrOrNull(string entryPoint) => _symdict.TryGetValue(entryPoint, out var sym) ? Z.SS(sym.Value + _loadoffset) : default;
public IntPtr GetProcAddrOrThrow(string entryPoint) => GetProcAddrOrNull(entryPoint) ?? throw new InvalidOperationException($"could not find {entryPoint} in exports");
#region state

View File

@ -97,19 +97,16 @@ namespace BizHawk.Emulation.Cores.Waterbox
var imports = _parent._exports[moduleName];
var pointers = entries.Select(e =>
{
var ptr = imports.Resolve(e);
if (ptr == IntPtr.Zero)
var ptr = imports.GetProcAddrOrNull(e);
if (ptr != null) return ptr.Value;
var s = $"Trapped on unimplemented function {moduleName}:{e}";
Action del = () =>
{
var s = $"Trapped on unimplemented function {moduleName}:{e}";
Action del = () =>
{
Console.WriteLine(s);
throw new InvalidOperationException(s);
};
_traps.Add(del);
ptr = CallingConventionAdapters.Waterbox.GetFunctionPointerForDelegate(del);
}
return ptr;
Console.WriteLine(s);
throw new InvalidOperationException(s);
};
_traps.Add(del);
return CallingConventionAdapters.Waterbox.GetFunctionPointerForDelegate(del);
}).ToArray();
Marshal.Copy(pointers, 0, table, pointers.Length);
}
@ -1063,7 +1060,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
@ -1071,8 +1068,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
// run unmanaged init code
var libcEnter = _exports["libc.so"].SafeResolve("__libc_entry_routine");
var psxInit = _exports["libpsxscl.so"].SafeResolve("__psx_init");
var libcEnter = _exports["libc.so"].GetProcAddrOrThrow("__libc_entry_routine");
var psxInit = _exports["libpsxscl.so"].GetProcAddrOrThrow("__psx_init");
var del = (LibcEntryRoutineD)CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer(libcEnter, typeof(LibcEntryRoutineD));
// the current mmglue code doesn't use the main pointer at all, and this just returns
@ -1101,11 +1098,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
}
public IntPtr Resolve(string entryPoint)
{
// modules[0] is always the main module
return _modules[0].Resolve(entryPoint);
}
public IntPtr? GetProcAddrOrNull(string entryPoint) => _modules[0].GetProcAddrOrNull(entryPoint); // _modules[0] is always the main module
public IntPtr GetProcAddrOrThrow(string entryPoint) => _modules[0].GetProcAddrOrThrow(entryPoint);
public void Seal()
{
@ -1121,7 +1116,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
if (_exports.TryGetValue("libco.so", out libco))
{
Console.WriteLine("Calling co_clean()...");
CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer<Action>(libco.SafeResolve("co_clean"))();
CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer<Action>(libco.GetProcAddrOrThrow("co_clean"))();
}
_sealedheap.Seal();

View File

@ -301,12 +301,9 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
}
public IntPtr Resolve(string entryPoint)
{
IntPtr ret;
ExportsByName.TryGetValue(entryPoint, out ret);
return ret;
}
public IntPtr? GetProcAddrOrNull(string entryPoint) => ExportsByName.TryGetValue(entryPoint, out var ret) ? ret : default;
public IntPtr GetProcAddrOrThrow(string entryPoint) => GetProcAddrOrNull(entryPoint) ?? throw new InvalidOperationException($"could not find {entryPoint} in exports");
public void ConnectImports(string moduleName, IImportResolver module)
{
@ -321,7 +318,7 @@ namespace BizHawk.Emulation.Cores.Waterbox
{
foreach (var kvp in imports)
{
var valueArray = new IntPtr[] { module.SafeResolve(kvp.Key) };
var valueArray = new IntPtr[] { module.GetProcAddrOrThrow(kvp.Key) };
Marshal.Copy(valueArray, 0, kvp.Value, 1);
}
}

View File

@ -5,6 +5,8 @@ using System.Globalization;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using BizHawk.Common;
namespace BizHawk.Emulation.DiscSystem
{
/// <summary>
@ -92,19 +94,10 @@ namespace BizHawk.Emulation.DiscSystem
static void CheckLibrary()
{
IntPtr lib = LoadLibrary("mednadisc.dll");
if (lib == IntPtr.Zero)
{
_IsLibraryAvailable = false;
return;
}
IntPtr addr = GetProcAddress(lib, "mednadisc_LoadCD");
FreeLibrary(lib);
if (addr == IntPtr.Zero)
{
_IsLibraryAvailable = false;
}
_IsLibraryAvailable = true;
var lib = OSTailoredCode.LinkedLibManager.LoadOrNull("mednadisc.dll");
_IsLibraryAvailable = lib != null
&& OSTailoredCode.LinkedLibManager.GetProcAddrOrNull(lib.Value, "mednadisc_LoadCD") != null;
if (lib != null) OSTailoredCode.LinkedLibManager.FreeByPtr(lib.Value);
}
static MednaDisc()
@ -142,13 +135,6 @@ namespace BizHawk.Emulation.DiscSystem
public bool Valid { get { return _validByte != 0; } }
};
[DllImport("kernel32.dll")]
static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll")]
static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
[DllImport("kernel32.dll")]
static extern bool FreeLibrary(IntPtr hModule);
[DllImport("mednadisc.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr mednadisc_LoadCD(string path);