Merge pull request #1568 from TASVideos/unix_prep

Preparation for Unix port
This commit is contained in:
James Groom 2019-05-29 15:01:27 +10:00 committed by GitHub
commit 27a4062ea2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 463 additions and 462 deletions

5
.gitignore vendored
View File

@ -12,6 +12,7 @@ svnrev.cs
**/ipch/**
*.ilk
*.il
*.tlog
*.obj
*.o
@ -74,3 +75,7 @@ libsnes/vs2015/libsnes.VC.db
waterbox/**/*.wbx
waterbox/**/*.wbx.in
/BizHawkTool_template.zip
mono_crash*
.idea

View File

@ -8,11 +8,14 @@ libpath=""
if [ "$(command -v lsb_release)" ]; then
case "$(lsb_release -i | cut -c17- | tr -d "\n")" in
"Arch"|"ManjaroLinux") libpath="/usr/lib/wine";;
"Debian"|"Ubuntu"|"LinuxMint") libpath="/usr/lib/x86_64-linux-gnu/wine";;
"Debian"|"LinuxMint") libpath="/usr/lib/x86_64-linux-gnu/wine";;
"Ubuntu") libpath="/usr/lib/x86_64-linux-gnu/wine"; export MONO_WINFORMS_XIM_STYLE=disabled;; # see https://bugzilla.xamarin.com/show_bug.cgi?id=28047#c9
esac
else
printf "Distro does not provide LSB release info API! (You've met with a terrible fate, haven't you?)\n"
fi
if [ -z "$libpath" ]; then
printf "%s\n" "Unknown distro, assuming WINE library location is /usr/lib/wine..."
libpath="/usr/lib/wine"
fi
LD_LIBRARY_PATH="$libpath" mono ./EmuHawk.exe
LD_LIBRARY_PATH="$libpath" mono ./EmuHawk.exe >EmuHawkMono_laststdout.txt

View File

@ -89,7 +89,7 @@ namespace SevenZip
// private static string _LibraryVersion;
private static bool? _modifyCapabale;
private static readonly PlatformLinkedLibSingleton.PlatformLinkedLibManager libLoader = PlatformLinkedLibSingleton.LinkedLibManager;
private static readonly OSTailoredCode.ILinkedLibManager libLoader = OSTailoredCode.LinkedLibManager;
private static void InitUserInFormat(object user, InArchiveFormat format)
{

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Drawing;
using BizHawk.Common;
using BizHawk.Emulation.Common;
// ReSharper disable FieldCanBeMadeReadOnly.Global
@ -341,8 +342,13 @@ namespace BizHawk.Client.Common
public int DispPrescale = 1;
// warning: we dont even want to deal with changing this at runtime. but we want it changed here for config purposes. so dont check this variable. check in GlobalWin or something like that.
public EDispMethod DispMethod = EDispMethod.SlimDX9;
/// <remarks>
/// warning: we dont even want to deal with changing this at runtime. but we want it changed here for config purposes. so dont check this variable. check in GlobalWin or something like that.
/// force DX for Windows and GDI+ for Unix when a new config is generated
/// </remarks>
public EDispMethod DispMethod = OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows
? EDispMethod.SlimDX9
: EDispMethod.GdiPlus;
public int DispChrome_FrameWindowed = 2;
public bool DispChrome_StatusBarWindowed = true;
@ -370,11 +376,9 @@ namespace BizHawk.Client.Common
public int DispCropBottom = 0;
// Sound options
#if WINDOWS
public ESoundOutputMethod SoundOutputMethod = ESoundOutputMethod.DirectSound;
#else
public ESoundOutputMethod SoundOutputMethod = ESoundOutputMethod.OpenAL;
#endif
public ESoundOutputMethod SoundOutputMethod = OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows
? ESoundOutputMethod.DirectSound
: ESoundOutputMethod.OpenAL; // force OpenAL for Unix when config is generated
public bool SoundEnabled = true;
public bool SoundEnabledNormal = true;
public bool SoundEnabledRWFF = true;

View File

@ -1,5 +1,8 @@
using System;
using System.Runtime.InteropServices;
using BizHawk.Common;
using NLua;
// TODO - evaluate for re-entrancy problems
@ -18,12 +21,10 @@ namespace BizHawk.Client.Common
private string _currentDirectory;
#if WINDOWS
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetCurrentDirectoryW(byte* lpPathName);
[DllImport("kernel32.dll", SetLastError=true)]
static extern uint GetCurrentDirectoryW(uint nBufferLength, byte* pBuffer);
#endif
private bool CoolSetCurrentDirectory(string path, string currDirSpeedHack = null)
{
@ -42,40 +43,43 @@ namespace BizHawk.Client.Common
return true;
}
// WARNING: setting the current directory is SLOW!!! security checks for some reason.
// so we're bypassing it with windows hacks
#if WINDOWS
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
{
// WARNING: setting the current directory is SLOW!!! security checks for some reason.
// so we're bypassing it with windows hacks
fixed (byte* pstr = &System.Text.Encoding.Unicode.GetBytes($"{target}\0")[0])
return SetCurrentDirectoryW(pstr);
#else
if (System.IO.Directory.Exists(CurrentDirectory)) // race condition for great justice
{
Environment.CurrentDirectory = CurrentDirectory; // thats right, you can't set a directory as current that doesnt exist because .net's got to do SENSELESS SLOW-ASS SECURITY CHECKS on it and it can't do that on a NONEXISTENT DIRECTORY
return true;
}
else
{
return false;
}
#endif
}
else
{
if (System.IO.Directory.Exists(_currentDirectory)) // race condition for great justice
{
Environment.CurrentDirectory = _currentDirectory; // thats right, you can't set a directory as current that doesnt exist because .net's got to do SENSELESS SLOW-ASS SECURITY CHECKS on it and it can't do that on a NONEXISTENT DIRECTORY
return true;
}
else
{
return false;
}
}
}
private string CoolGetCurrentDirectory()
{
// GUESS WHAT!
// .NET DOES A SECURITY CHECK ON THE DIRECTORY WE JUST RETRIEVED
// AS IF ASKING FOR THE CURRENT DIRECTORY IS EQUIVALENT TO TRYING TO ACCESS IT
// SCREW YOU
#if WINDOWS
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
{
// GUESS WHAT!
// .NET DOES A SECURITY CHECK ON THE DIRECTORY WE JUST RETRIEVED
// AS IF ASKING FOR THE CURRENT DIRECTORY IS EQUIVALENT TO TRYING TO ACCESS IT
// SCREW YOU
var buf = new byte[32768];
fixed(byte* pBuf = &buf[0])
{
uint ret = GetCurrentDirectoryW(32767, pBuf);
return System.Text.Encoding.Unicode.GetString(buf, 0, (int)ret*2);
}
#else
fixed (byte* pBuf = &buf[0])
return System.Text.Encoding.Unicode.GetString(buf, 0, 2 * (int) GetCurrentDirectoryW(32767, pBuf));
}
else
{
return Environment.CurrentDirectory;
#endif
}
}
private void Sandbox(Action callback, Action exceptionCallback)

View File

@ -6,6 +6,7 @@ using System.Diagnostics;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
@ -85,12 +86,9 @@ namespace BizHawk.Client.EmuHawk
try
{
_ffmpeg = new Process();
#if WINDOWS
_ffmpeg.StartInfo.FileName = Path.Combine(PathManager.GetDllDirectory(), "ffmpeg.exe");
#else
ffmpeg.StartInfo.FileName = "ffmpeg"; // expecting native version to be in path
#endif
_ffmpeg.StartInfo.FileName = OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows
? Path.Combine(PathManager.GetDllDirectory(), "ffmpeg.exe")
: "ffmpeg";
_ffmpeg.StartInfo.Arguments = $"-y -f nut -i - {_token.Commandline} \"{_baseName}{(_segment == 0 ? string.Empty : $"_{_segment}")}{_ext}\"";
_ffmpeg.StartInfo.CreateNoWindow = true;

View File

@ -113,8 +113,8 @@
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\BizHawk.Common\PlatformLinkedLibSingleton.cs">
<Link>PlatformLinkedLibSingleton.cs</Link>
<Compile Include="..\BizHawk.Common\OSTailoredCode.cs">
<Link>OSTailoredCode.cs</Link>
</Compile>
<Compile Include="..\Version\svnrev.cs">
<Link>svnrev.cs</Link>
@ -2283,4 +2283,4 @@
<PreBuildEvent />
</PropertyGroup>
<Import Project="$(SolutionDir)Build\Common.targets" />
</Project>
</Project>

View File

@ -123,24 +123,24 @@ namespace BizHawk.Client.EmuHawk
public static void Initialize()
{
if (PlatformLinkedLibSingleton.RunningOnUnix)
{
OTK_Keyboard.Initialize();
// OTK_Gamepad.Initialize();
}
else
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
{
KeyInput.Initialize();
IPCKeyInput.Initialize();
GamePad.Initialize();
GamePad360.Initialize();
}
else
{
OTK_Keyboard.Initialize();
// OTK_Gamepad.Initialize();
}
Instance = new Input();
}
public static void Cleanup()
{
if (!PlatformLinkedLibSingleton.RunningOnUnix)
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
{
KeyInput.Cleanup();
GamePad.Cleanup();
@ -331,18 +331,18 @@ namespace BizHawk.Client.EmuHawk
{
while (true)
{
var keyEvents = PlatformLinkedLibSingleton.RunningOnUnix
? OTK_Keyboard.Update()
: KeyInput.Update().Concat(IPCKeyInput.Update());
if (PlatformLinkedLibSingleton.RunningOnUnix)
{
//TODO
}
else
var keyEvents = OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows
? KeyInput.Update().Concat(IPCKeyInput.Update())
: OTK_Keyboard.Update();
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
{
GamePad.UpdateAll();
GamePad360.UpdateAll();
}
else
{
//TODO
}
//this block is going to massively modify data structures that the binding method uses, so we have to lock it all
lock (this)

View File

@ -25,6 +25,7 @@ using BizHawk.Client.EmuHawk.WinFormExtensions;
using BizHawk.Client.EmuHawk.ToolExtensions;
using BizHawk.Emulation.Cores.Computers.AppleII;
using BizHawk.Client.ApiHawk;
using BizHawk.Common;
using BizHawk.Emulation.Cores.Computers.Commodore64;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Emulation.Cores.Computers.SinclairSpectrum;
@ -1469,7 +1470,14 @@ namespace BizHawk.Client.EmuHawk
private void RamSearchMenuItem_Click(object sender, EventArgs e)
{
GlobalWin.Tools.Load<RamSearch>();
var ramSearch = GlobalWin.Tools.Load<RamSearch>();
if (OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows)
{
// this is apparently needed for weird mono-forms-on-different-thread issues
// dont do .Show() within Load<T>() for RamSearch - instead put an instance of it here on MainForm, then show here
// the mono winforms implementation is.... weird and buggy
ramSearch.Show();
}
}
private void LuaConsoleMenuItem_Click(object sender, EventArgs e)

View File

@ -161,7 +161,9 @@ namespace BizHawk.Client.EmuHawk
Database.LoadDatabase(Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "gamedb.txt"));
// TODO GL - a lot of disorganized wiring-up here
CGC.CGCBinPath = Path.Combine(PathManager.GetDllDirectory(), "cgc.exe");
CGC.CGCBinPath = OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows
? Path.Combine(PathManager.GetDllDirectory(), "cgc.exe")
: "cgc"; // installed separately (via package manager or from https://developer.nvidia.com/cg-toolkit-download), look in $PATH
PresentationPanel = new PresentationPanel();
PresentationPanel.GraphicsControl.MainWindow = true;
GlobalWin.DisplayManager = new DisplayManager(PresentationPanel);
@ -1057,7 +1059,7 @@ namespace BizHawk.Client.EmuHawk
if (!_inFullscreen)
{
SuspendLayout();
#if WINDOWS
// Work around an AMD driver bug in >= vista:
// It seems windows will activate opengl fullscreen mode when a GL control is occupying the exact space of a screen (0,0 and dimensions=screensize)
// AMD cards manifest a problem under these circumstances, flickering other monitors.
@ -1065,7 +1067,9 @@ namespace BizHawk.Client.EmuHawk
// (this could be determined with more work; other side affects of the fullscreen mode include: corrupted taskbar, no modal boxes on top of GL control, no screenshots)
// At any rate, we can solve this by adding a 1px black border around the GL control
// Please note: It is important to do this before resizing things, otherwise momentarily a GL control without WS_BORDER will be at the magic dimensions and cause the flakeout
if (Global.Config.DispFullscreenHacks && Global.Config.DispMethod == Config.EDispMethod.OpenGL)
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows
&& Global.Config.DispFullscreenHacks
&& Global.Config.DispMethod == Config.EDispMethod.OpenGL)
{
//ATTENTION: this causes the statusbar to not work well, since the backcolor is now set to black instead of SystemColors.Control.
//It seems that some statusbar elements composite with the backcolor.
@ -1076,7 +1080,6 @@ namespace BizHawk.Client.EmuHawk
// FUTURE WORK:
// re-add this padding back into the display manager (so the image will get cut off a little but, but a few more resolutions will fully fit into the screen)
}
#endif
_windowedLocation = Location;
@ -1093,13 +1096,15 @@ namespace BizHawk.Client.EmuHawk
WindowState = FormWindowState.Normal;
#if WINDOWS
// do this even if DispFullscreenHacks arent enabled, to restore it in case it changed underneath us or something
Padding = new Padding(0);
// it's important that we set the form color back to this, because the statusbar icons blend onto the mainform, not onto the statusbar--
// so we need the statusbar and mainform backdrop color to match
BackColor = SystemColors.Control;
#endif
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
{
// do this even if DispFullscreenHacks arent enabled, to restore it in case it changed underneath us or something
Padding = new Padding(0);
// it's important that we set the form color back to this, because the statusbar icons blend onto the mainform, not onto the statusbar--
// so we need the statusbar and mainform backdrop color to match
BackColor = SystemColors.Control;
}
_inFullscreen = false;
@ -2071,7 +2076,22 @@ namespace BizHawk.Client.EmuHawk
// sends an alt+mnemonic combination
private void SendAltKeyChar(char c)
{
typeof(ToolStrip).InvokeMember("ProcessMnemonicInternal", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Instance, null, MainformMenu, new object[] { c });
switch (OSTailoredCode.CurrentOS)
{
case OSTailoredCode.DistinctOS.Linux:
case OSTailoredCode.DistinctOS.macOS:
// no mnemonics for you
break;
case OSTailoredCode.DistinctOS.Windows:
//HACK
var _ = typeof(ToolStrip).InvokeMember(
"ProcessMnemonicInternal",
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Instance,
null,
MainformMenu,
new object[] { c });
break;
}
}
public static string FormatFilter(params string[] args)

View File

@ -6,9 +6,6 @@ using sysdrawing2d=System.Drawing.Drawing2D;
using System.IO;
using System.Threading;
using System.Windows.Forms;
#if WINDOWS
using SlimDX;
#endif
using BizHawk.Client.Common;
using BizHawk.Bizware.BizwareGL;

View File

@ -1,21 +1,19 @@
using System;
using System.Linq;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;
#if WINDOWS
using Microsoft.VisualBasic.ApplicationServices;
#endif
using BizHawk.Common;
using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk
{
static class Program
internal static class Program
{
static Program()
{
@ -23,56 +21,52 @@ namespace BizHawk.Client.EmuHawk
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var libLoader = EXE_PROJECT.PlatformLinkedLibSingleton.LinkedLibManager;
//http://www.codeproject.com/Articles/310675/AppDomain-AssemblyResolve-Event-Tips
//try loading libraries we know we'll need
//something in the winforms, etc. code below will cause .net to popup a missing msvcr100.dll in case that one's missing
//but oddly it lets us proceed and we'll then catch it here
var libExt = EXE_PROJECT.PlatformLinkedLibSingleton.RunningOnUnix ? ".dll.so" : ".dll";
var d3dx9 = libLoader.LoadPlatformSpecific($"d3dx9_43{libExt}");
var vc2015 = libLoader.LoadPlatformSpecific($"vcruntime140{libExt}");
var vc2012 = libLoader.LoadPlatformSpecific($"msvcr120{libExt}"); //TODO - check version?
var vc2010 = libLoader.LoadPlatformSpecific($"msvcr100{libExt}"); //TODO - check version?
var vc2010p = libLoader.LoadPlatformSpecific($"msvcp100{libExt}");
bool fail = false, warn = false;
warn |= d3dx9 == IntPtr.Zero;
fail |= vc2015 == IntPtr.Zero;
fail |= vc2010 == IntPtr.Zero;
fail |= vc2012 == IntPtr.Zero;
fail |= vc2010p == IntPtr.Zero;
if (fail || warn)
if (EXE_PROJECT.OSTailoredCode.CurrentOS == EXE_PROJECT.OSTailoredCode.DistinctOS.Windows)
{
var sw = new System.IO.StringWriter();
sw.WriteLine("[ OK ] .Net 4.6.1 (You couldn't even get here without it)");
sw.WriteLine("[{0}] Direct3d 9", d3dx9 == IntPtr.Zero ? "FAIL" : " OK ");
sw.WriteLine("[{0}] Visual C++ 2010 SP1 Runtime", (vc2010 == IntPtr.Zero || vc2010p == IntPtr.Zero) ? "FAIL" : " OK ");
sw.WriteLine("[{0}] Visual C++ 2012 Runtime", (vc2012 == IntPtr.Zero) ? "FAIL" : " OK ");
sw.WriteLine("[{0}] Visual C++ 2015 Runtime", (vc2015 == IntPtr.Zero) ? "FAIL" : " OK ");
var str = sw.ToString();
var box = new BizHawk.Client.EmuHawk.CustomControls.PrereqsAlert(!fail);
box.textBox1.Text = str;
box.ShowDialog();
if (!fail) { }
else
System.Diagnostics.Process.GetCurrentProcess().Kill();
}
var libLoader = EXE_PROJECT.OSTailoredCode.LinkedLibManager;
libLoader.FreePlatformSpecific(d3dx9);
libLoader.FreePlatformSpecific(vc2015);
libLoader.FreePlatformSpecific(vc2012);
libLoader.FreePlatformSpecific(vc2010);
libLoader.FreePlatformSpecific(vc2010p);
//http://www.codeproject.com/Articles/310675/AppDomain-AssemblyResolve-Event-Tips
//try loading libraries we know we'll need
//something in the winforms, etc. code below will cause .net to popup a missing msvcr100.dll in case that one's missing
//but oddly it lets us proceed and we'll then catch it here
var d3dx9 = libLoader.LoadPlatformSpecific("d3dx9_43.dll");
var vc2015 = libLoader.LoadPlatformSpecific("vcruntime140.dll");
var vc2012 = libLoader.LoadPlatformSpecific("msvcr120.dll"); //TODO - check version?
var vc2010 = libLoader.LoadPlatformSpecific("msvcr100.dll"); //TODO - check version?
var vc2010p = libLoader.LoadPlatformSpecific("msvcp100.dll");
var fail = vc2015 == IntPtr.Zero || vc2010 == IntPtr.Zero || vc2012 == IntPtr.Zero || vc2010p == IntPtr.Zero;
var warn = d3dx9 == IntPtr.Zero;
if (fail || warn)
{
var alertLines = new[]
{
"[ OK ] .NET CLR (You wouldn't even get here without it)",
$"[{(d3dx9 == IntPtr.Zero ? "WARN" : " OK ")}] Direct3d 9",
$"[{(vc2010 == IntPtr.Zero || vc2010p == IntPtr.Zero ? "FAIL" : " OK ")}] Visual C++ 2010 SP1 Runtime",
$"[{(vc2012 == IntPtr.Zero ? "FAIL" : " OK ")}] Visual C++ 2012 Runtime",
$"[{(vc2015 == IntPtr.Zero ? "FAIL" : " OK ")}] Visual C++ 2015 Runtime"
};
var box = new BizHawk.Client.EmuHawk.CustomControls.PrereqsAlert(!fail)
{
textBox1 = { Text = string.Concat("\n", alertLines) }
};
box.ShowDialog();
if (fail) System.Diagnostics.Process.GetCurrentProcess().Kill();
}
libLoader.FreePlatformSpecific(d3dx9);
libLoader.FreePlatformSpecific(vc2015);
libLoader.FreePlatformSpecific(vc2012);
libLoader.FreePlatformSpecific(vc2010);
libLoader.FreePlatformSpecific(vc2010p);
if (!EXE_PROJECT.PlatformLinkedLibSingleton.RunningOnUnix)
{
// this will look in subdirectory "dll" to load pinvoked stuff
string dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll");
var dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll");
SetDllDirectory(dllDir);
//in case assembly resolution fails, such as if we moved them into the dll subdiretory, this event handler can reroute to them
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
//but before we even try doing that, whack the MOTW from everything in that directory (thats a dll)
//otherwise, some people will have crashes at boot-up due to .net security disliking MOTW.
@ -84,129 +78,20 @@ namespace BizHawk.Client.EmuHawk
}
[STAThread]
static int Main(string[] args)
private static int Main(string[] args)
{
return SubMain(args);
}
private interface PlatformSpecificMainLoopCrashHandler
{
void TryCatchFinally(string[] args);
}
private class Win32MainLoopCrashHandler : PlatformSpecificMainLoopCrashHandler
{
public void TryCatchFinally(string[] args)
var exitCode = SubMain(args);
if (EXE_PROJECT.OSTailoredCode.CurrentOS == EXE_PROJECT.OSTailoredCode.DistinctOS.Linux)
{
try
{
if (Global.Config.SingleInstanceMode)
{
try
{
new SingleInstanceController(args).Run(args);
}
catch (ObjectDisposedException)
{
// Eat it, MainForm disposed itself and Run attempts to dispose of itself. Eventually we would want to figure out a way to prevent that, but in the meantime it is harmless, so just eat the error
}
}
else
{
using (var mf = new MainForm(args))
{
var title = mf.Text;
mf.Show();
mf.Text = title;
try
{
GlobalWin.ExitCode = mf.ProgramRunLoop();
}
catch (Exception e) when (!Debugger.IsAttached && !VersionInfo.DeveloperBuild && Global.MovieSession.Movie.IsActive)
{
var result = MessageBox.Show(
"EmuHawk has thrown a fatal exception and is about to close.\nA movie has been detected. Would you like to try to save?\n(Note: Depending on what caused this error, this may or may not succeed)",
$"Fatal error: {e.GetType().Name}",
MessageBoxButtons.YesNo,
MessageBoxIcon.Exclamation
);
if (result == DialogResult.Yes)
{
Global.MovieSession.Movie.Save();
}
}
}
}
}
catch (Exception e) when (!Debugger.IsAttached)
{
new ExceptionBox(e).ShowDialog();
}
finally
{
if (GlobalWin.Sound != null)
{
GlobalWin.Sound.Dispose();
GlobalWin.Sound = null;
}
GlobalWin.GL.Dispose();
Input.Cleanup();
}
Console.WriteLine("BizHawk has completed its shutdown routines, killing process...");
Process.GetCurrentProcess().Kill();
}
return exitCode;
}
private class UnixMonoMainLoopCrashHandler : PlatformSpecificMainLoopCrashHandler
{
// Identical to the implementation in Win32MainLoopCrashHandler sans the single-instance check.
public void TryCatchFinally(string[] args)
{
try
{
using (var mf = new MainForm(args))
{
var title = mf.Text;
mf.Show();
mf.Text = title;
try
{
GlobalWin.ExitCode = mf.ProgramRunLoop();
}
catch (Exception e) when (!Debugger.IsAttached && !VersionInfo.DeveloperBuild && Global.MovieSession.Movie.IsActive)
{
var result = MessageBox.Show(
"EmuHawk has thrown a fatal exception and is about to close.\nA movie has been detected. Would you like to try to save?\n(Note: Depending on what caused this error, this may or may not succeed)",
$"Fatal error: {e.GetType().Name}",
MessageBoxButtons.YesNo,
MessageBoxIcon.Exclamation
);
if (result == DialogResult.Yes)
{
Global.MovieSession.Movie.Save();
}
}
}
}
catch (Exception e) when (!Debugger.IsAttached)
{
new ExceptionBox(e).ShowDialog();
}
finally
{
if (GlobalWin.Sound != null)
{
GlobalWin.Sound.Dispose();
GlobalWin.Sound = null;
}
GlobalWin.GL.Dispose();
Input.Cleanup();
}
}
}
private static PlatformSpecificMainLoopCrashHandler mainLoopCrashHandler = EXE_PROJECT.PlatformLinkedLibSingleton.RunningOnUnix
? (PlatformSpecificMainLoopCrashHandler) new UnixMonoMainLoopCrashHandler()
: (PlatformSpecificMainLoopCrashHandler) new Win32MainLoopCrashHandler();
//NoInlining should keep this code from getting jammed into Main() which would create dependencies on types which havent been setup by the resolver yet... or something like that
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
static int SubMain(string[] args)
private static int SubMain(string[] args)
{
// this check has to be done VERY early. i stepped through a debug build with wrong .dll versions purposely used,
// and there was a TypeLoadException before the first line of SubMain was reached (some static ColorType init?)
@ -228,7 +113,7 @@ namespace BizHawk.Client.EmuHawk
HawkFile.ArchiveHandlerFactory = new SevenZipSharpArchiveHandler();
ArgParser argParser = new ArgParser();
var argParser = new ArgParser();
argParser.ParseArguments(args);
if (argParser.cmdConfigFile != null) PathManager.SetDefaultIniPath(argParser.cmdConfigFile);
@ -248,13 +133,9 @@ namespace BizHawk.Client.EmuHawk
BizHawk.Client.Common.StringLogUtil.DefaultToAWE = Global.Config.MoviesInAWE;
// super hacky! this needs to be done first. still not worth the trouble to make this system fully proper
for (int i = 0; i < args.Length; i++)
if (Array.Exists(args, arg => arg.StartsWith("--gdi", StringComparison.InvariantCultureIgnoreCase)))
{
var arg = args[i].ToLower();
if (arg.StartsWith("--gdi"))
{
Global.Config.DispMethod = Config.EDispMethod.GdiPlus;
}
Global.Config.DispMethod = Config.EDispMethod.GdiPlus;
}
// create IGL context. we do this whether or not the user has selected OpenGL, so that we can run opengl-based emulator cores
@ -265,8 +146,10 @@ namespace BizHawk.Client.EmuHawk
GlobalWin.GLManager = GLManager.Instance;
//now create the "GL" context for the display method. we can reuse the IGL_TK context if opengl display method is chosen
if (EXE_PROJECT.PlatformLinkedLibSingleton.RunningOnUnix) Global.Config.DispMethod = Config.EDispMethod.GdiPlus;
REDO_DISPMETHOD:
if (EXE_PROJECT.OSTailoredCode.CurrentOS != EXE_PROJECT.OSTailoredCode.DistinctOS.Windows)
Global.Config.DispMethod = Config.EDispMethod.GdiPlus;
REDO_DISPMETHOD:
if (Global.Config.DispMethod == Config.EDispMethod.GdiPlus)
GlobalWin.GL = new Bizware.BizwareGL.Drivers.GdiPlus.IGL_GdiPlus();
else if (Global.Config.DispMethod == Config.EDispMethod.SlimDX9)
@ -277,8 +160,7 @@ namespace BizHawk.Client.EmuHawk
}
catch(Exception ex)
{
var e2 = new Exception("Initialization of Direct3d 9 Display Method failed; falling back to GDI+", ex);
new ExceptionBox(e2).ShowDialog();
new ExceptionBox(new Exception("Initialization of Direct3d 9 Display Method failed; falling back to GDI+", ex)).ShowDialog();
// fallback
Global.Config.DispMethod = Config.EDispMethod.GdiPlus;
@ -290,8 +172,7 @@ namespace BizHawk.Client.EmuHawk
GlobalWin.GL = GlobalWin.IGL_GL;
// check the opengl version and dont even try to boot this crap up if its too old
int version = GlobalWin.IGL_GL.Version;
if (version < 200)
if (GlobalWin.IGL_GL.Version < 200)
{
// fallback
Global.Config.DispMethod = Config.EDispMethod.GdiPlus;
@ -306,26 +187,75 @@ namespace BizHawk.Client.EmuHawk
}
catch(Exception ex)
{
var e2 = new Exception("Initialization of Display Method failed; falling back to GDI+", ex);
new ExceptionBox(e2).ShowDialog();
new ExceptionBox(new Exception("Initialization of Display Method failed; falling back to GDI+", ex)).ShowDialog();
//fallback
Global.Config.DispMethod = Config.EDispMethod.GdiPlus;
goto REDO_DISPMETHOD;
}
if (!EXE_PROJECT.PlatformLinkedLibSingleton.RunningOnUnix)
if (EXE_PROJECT.OSTailoredCode.CurrentOS == EXE_PROJECT.OSTailoredCode.DistinctOS.Windows)
{
//WHY do we have to do this? some intel graphics drivers (ig7icd64.dll 10.18.10.3304 on an unknown chip on win8.1) are calling SetDllDirectory() for the process, which ruins stuff.
//The relevant initialization happened just before in "create IGL context".
//It isn't clear whether we need the earlier SetDllDirectory(), but I think we do.
//note: this is pasted instead of being put in a static method due to this initialization code being sensitive to things like that, and not wanting to cause it to break
//pasting should be safe (not affecting the jit order of things)
string dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll");
var dllDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll");
SetDllDirectory(dllDir);
}
// Using a simple conditional to skip the single-instancing step caused crashes on GNU+Linux, even though the single-instancing step wasn't being executed. Something about the way instantiation works in C# means this workaround is possible.
mainLoopCrashHandler.TryCatchFinally(args);
try
{
if (Global.Config.SingleInstanceMode)
{
try
{
new SingleInstanceController(args).Run();
}
catch (ObjectDisposedException)
{
// Eat it, MainForm disposed itself and Run attempts to dispose of itself. Eventually we would want to figure out a way to prevent that, but in the meantime it is harmless, so just eat the error
}
}
else
{
using (var mf = new MainForm(args))
{
var title = mf.Text;
mf.Show();
mf.Text = title;
try
{
GlobalWin.ExitCode = mf.ProgramRunLoop();
}
catch (Exception e) when (Global.MovieSession.Movie.IsActive && !(Debugger.IsAttached || VersionInfo.DeveloperBuild))
{
var result = MessageBox.Show(
"EmuHawk has thrown a fatal exception and is about to close.\nA movie has been detected. Would you like to try to save?\n(Note: Depending on what caused this error, this may or may not succeed)",
$"Fatal error: {e.GetType().Name}",
MessageBoxButtons.YesNo,
MessageBoxIcon.Exclamation
);
if (result == DialogResult.Yes)
{
Global.MovieSession.Movie.Save();
}
}
}
}
}
catch (Exception e) when (!Debugger.IsAttached)
{
new ExceptionBox(e).ShowDialog();
}
finally
{
GlobalWin.Sound?.Dispose();
GlobalWin.Sound = null;
GlobalWin.GL.Dispose();
Input.Cleanup();
}
//cleanup:
//cleanup IGL stuff so we can get better refcounts when exiting process, for debugging
@ -341,19 +271,19 @@ namespace BizHawk.Client.EmuHawk
} //SubMain
//declared here instead of a more usual place to avoid dependencies on the more usual place
#if WINDOWS
[DllImport("kernel32.dll", SetLastError = true)]
static extern uint SetDllDirectory(string lpPathName);
private static extern uint SetDllDirectory(string lpPathName);
[DllImport("kernel32.dll", EntryPoint = "DeleteFileW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
static extern bool DeleteFileW([MarshalAs(UnmanagedType.LPWStr)]string lpFileName);
private static extern bool DeleteFileW([MarshalAs(UnmanagedType.LPWStr)]string lpFileName);
public static void RemoveMOTW(string path)
private static void RemoveMOTW(string path)
{
DeleteFileW($"{path}:Zone.Identifier");
}
static void WhackAllMOTW(string dllDir)
private static void WhackAllMOTW(string dllDir)
{
var todo = new Queue<DirectoryInfo>(new[] { new DirectoryInfo(dllDir) });
while (todo.Count > 0)
@ -365,14 +295,11 @@ namespace BizHawk.Client.EmuHawk
foreach (var fi in di.GetFiles("*.exe"))
RemoveMOTW(fi.FullName);
}
}
#endif
static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string requested = args.Name;
var requested = args.Name;
//mutate filename depending on selection of lua core. here's how it works
//1. we build NLua to the output/dll/lua directory. that brings KopiLua with it
@ -380,52 +307,43 @@ namespace BizHawk.Client.EmuHawk
//3. When NLua assembly attempts to load, it can't find it
//I. if LuaInterface is selected by the user, we switch to requesting that.
// (those DLLs are built into the output/DLL directory)
//II. if NLua is selected by the user, we skip over this part;
//II. if NLua is selected by the user, we skip over this part;
// later, we look for NLua or KopiLua assembly names and redirect them to files located in the output/DLL/nlua directory
if (new AssemblyName(requested).Name == "NLua")
{
//this method referencing Global.Config makes assemblies get loaded, which isnt smart from the assembly resolver.
//so.. we're going to resort to something really bad.
//avert your eyes.
bool UseNLua = true;
string configPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "config.ini");
if (File.Exists(configPath))
var configPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "config.ini");
if (EXE_PROJECT.OSTailoredCode.CurrentOS == EXE_PROJECT.OSTailoredCode.DistinctOS.Windows // LuaInterface is not currently working on Mono
&& File.Exists(configPath)
&& (Array.Find(File.ReadAllLines(configPath), line => line.Contains(" \"UseNLua\": ")) ?? string.Empty)
.Contains("false"))
{
var cfg = File.ReadAllLines(configPath);
var usenlua_key = cfg.FirstOrDefault(line=>line.Contains(" \"UseNLua\": "));
if (usenlua_key != null)
if (usenlua_key.Contains("false"))
UseNLua = false;
requested = "LuaInterface";
}
if (UseNLua) { }
else requested = "LuaInterface";
}
lock (AppDomain.CurrentDomain)
{
var asms = AppDomain.CurrentDomain.GetAssemblies();
foreach (var asm in asms)
if (asm.FullName == requested)
return asm;
var firstAsm = Array.Find(AppDomain.CurrentDomain.GetAssemblies(), asm => asm.FullName == requested);
if (firstAsm != null) return firstAsm;
//load missing assemblies by trying to find them in the dll directory
string dllname = $"{new AssemblyName(requested).Name}.dll";
string directory = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll");
string simpleName = new AssemblyName(requested).Name;
var dllname = $"{new AssemblyName(requested).Name}.dll";
var directory = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "dll");
var simpleName = new AssemblyName(requested).Name;
if (simpleName == "NLua" || simpleName == "KopiLua") directory = Path.Combine(directory, "nlua");
string fname = Path.Combine(directory, dllname);
if (!File.Exists(fname)) return null;
//it is important that we use LoadFile here and not load from a byte array; otherwise mixed (managed/unamanged) assemblies can't load
return Assembly.LoadFile(fname);
var fname = Path.Combine(directory, dllname);
//it is important that we use LoadFile here and not load from a byte array; otherwise mixed (managed/unmanaged) assemblies can't load
return File.Exists(fname) ? Assembly.LoadFile(fname) : null;
}
}
#if WINDOWS
public class SingleInstanceController : WindowsFormsApplicationBase
private class SingleInstanceController : WindowsFormsApplicationBase
{
readonly string[] cmdArgs;
private readonly string[] cmdArgs;
public SingleInstanceController(string[] args)
{
cmdArgs = args;
@ -433,10 +351,12 @@ namespace BizHawk.Client.EmuHawk
StartupNextInstance += this_StartupNextInstance;
}
void this_StartupNextInstance(object sender, StartupNextInstanceEventArgs e)
public void Run() => Run(cmdArgs);
private void this_StartupNextInstance(object sender, StartupNextInstanceEventArgs e)
{
if (e.CommandLine.Count >= 1)
(MainForm as MainForm).LoadRom(e.CommandLine[0], new MainForm.LoadRomArgs() { OpenAdvanced = new OpenAdvanced_OpenRom() });
((MainForm)MainForm).LoadRom(e.CommandLine[0], new MainForm.LoadRomArgs { OpenAdvanced = new OpenAdvanced_OpenRom() });
}
protected override void OnCreateMainForm()
@ -445,11 +365,8 @@ namespace BizHawk.Client.EmuHawk
var title = MainForm.Text;
MainForm.Show();
MainForm.Text = title;
GlobalWin.ExitCode = (MainForm as MainForm).ProgramRunLoop();
GlobalWin.ExitCode = ((MainForm)MainForm).ProgramRunLoop();
}
}
#endif
}
}

View File

@ -1,80 +1,66 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices;
using BizHawk.Client.Common;
using BizHawk.Common;
namespace BizHawk.Client.EmuHawk
{
// Derived from http://www.codeproject.com/KB/cs/ScreenSaverControl.aspx
/// <remarks>Derived from http://www.codeproject.com/KB/cs/ScreenSaverControl.aspx</remarks>
public static class ScreenSaver
{
private interface PlatformSpecificScreenBlankInterface
private interface IScreenBlankTimer
{
Int32 Get();
void Set(Int32 v);
/// <summary>
/// The screen saver timeout setting, in seconds
/// </summary>
int Duration { get; set; }
}
private class WinScreenBlankInterface : PlatformSpecificScreenBlankInterface
private class Win32ScreenBlankTimer : IScreenBlankTimer
{
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool SystemParametersInfo(int uAction, int uParam, ref int lpvParam, int flags);
public Int32 Get()
{
Int32 value = 0;
SystemParametersInfo(SPI_GETSCREENSAVERTIMEOUT, 0, ref value, 0);
return value;
}
public void Set(Int32 v)
{
int nullVar = 0;
SystemParametersInfo(SPI_SETSCREENSAVERTIMEOUT, v, ref nullVar, SPIF_SENDWININICHANGE);
}
}
private class MiscUnixScreenBlankInterface : PlatformSpecificScreenBlankInterface
{
public Int32 Get()
{
return 0; //TODO implement
}
public void Set(Int32 v)
{
//TODO implement
}
}
private static PlatformSpecificScreenBlankInterface screenBlankInterface = PlatformLinkedLibSingleton.RunningOnUnix
? (PlatformSpecificScreenBlankInterface) new MiscUnixScreenBlankInterface()
: (PlatformSpecificScreenBlankInterface) new WinScreenBlankInterface();
private const int SPI_GETSCREENSAVERTIMEOUT = 14;
private const int SPI_SETSCREENSAVERTIMEOUT = 15;
private const int SPIF_SENDWININICHANGE = 2;
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);
return value;
}
set
{
var nullVar = 0;
SystemParametersInfo(SPI_SETSCREENSAVERTIMEOUT, value, ref nullVar, SPIF_SENDWININICHANGE);
}
}
}
private class UnixScreenBlankTimer : IScreenBlankTimer
{
public int Duration { get; set; } = 0; //TODO implementation
}
private static readonly IScreenBlankTimer _screenBlankTimer = OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows
? (IScreenBlankTimer) new Win32ScreenBlankTimer()
: new UnixScreenBlankTimer();
private static int ctr;
public static void ResetTimerImmediate()
{
SetScreenSaverTimeout(GetScreenSaverTimeout());
_screenBlankTimer.Duration = _screenBlankTimer.Duration;
}
private static int ctr;
public static void ResetTimerPeriodically()
{
ctr++;
if (ctr == 120)
{
SetScreenSaverTimeout(GetScreenSaverTimeout());
ctr = 0;
}
}
// Returns the screen saver timeout setting, in seconds
private static Int32 GetScreenSaverTimeout()
{
return screenBlankInterface.Get();
}
// Pass in the number of seconds to set the screen saver timeout value.
private static void SetScreenSaverTimeout(Int32 Value)
{
screenBlankInterface.Set(Value);
if (++ctr < 120) return;
ctr = 0;
ResetTimerImmediate();
}
}
}
}

View File

@ -1,5 +1,4 @@
#if WINDOWS
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@ -164,4 +163,3 @@ namespace BizHawk.Client.EmuHawk
}
}
}
#endif

View File

@ -1,5 +1,4 @@
#if WINDOWS
using System;
using System;
using System.Collections.Generic;
using System.Linq;
@ -185,4 +184,3 @@ namespace BizHawk.Client.EmuHawk
}
}
}
#endif

View File

@ -25,15 +25,17 @@ namespace BizHawk.Client.EmuHawk
public Sound(IntPtr mainWindowHandle)
{
if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.OpenAL)
_outputDevice = new OpenALSoundOutput(this);
if (!PlatformLinkedLibSingleton.RunningOnUnix)
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
{
if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.OpenAL)
_outputDevice = new OpenALSoundOutput(this);
if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.DirectSound)
_outputDevice = new DirectSoundSoundOutput(this, mainWindowHandle);
if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.XAudio2)
_outputDevice = new XAudio2SoundOutput(this);
}
else _outputDevice = new OpenALSoundOutput(this); // at the moment unix/mono can only support OpenAL (so ignore whatever is set in the config)
if (_outputDevice == null)
_outputDevice = new DummySoundOutput(this);
}

View File

@ -153,14 +153,16 @@ namespace BizHawk.Client.EmuHawk
}
private class UnixMonoSysTimer : PlatformSpecificSysTimer
{
[DllImport("winmm.dll.so", EntryPoint = "timeBeginPeriod")]
private static extern uint timeBeginPeriod(uint uMilliseconds);
public uint TimeBeginPeriod(uint ms)
{
return timeBeginPeriod(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 PlatformSpecificSysTimer sysTimer = PlatformLinkedLibSingleton.RunningOnUnix ? (PlatformSpecificSysTimer) new UnixMonoSysTimer() : (PlatformSpecificSysTimer) new WinSysTimer();
static PlatformSpecificSysTimer sysTimer = OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows
? (PlatformSpecificSysTimer) new WinSysTimer()
: new UnixMonoSysTimer();
static uint TimeBeginPeriod(uint ms)
{
return sysTimer.TimeBeginPeriod(ms);
@ -362,18 +364,23 @@ namespace BizHawk.Client.EmuHawk
int sleepTime = (int)((timePerFrame - elapsedTime) * 1000 / afsfreq);
if (sleepTime >= 2 || paused)
{
#if WINDOWS
// Assuming a timer period of 1 ms (i.e. TimeBeginPeriod(1)): The actual sleep time
// on Windows XP is generally within a half millisecond either way of the requested
// time. The actual sleep time on Windows 8 is generally between the requested time
// and up to a millisecond over. So we'll subtract 1 ms from the time to avoid
// sleeping longer than desired.
sleepTime -= 1;
#else
// The actual sleep time on OS X with Mono is generally between the request time
// and up to 25% over. So we'll scale the sleep time back to account for that.
sleepTime = sleepTime * 4 / 5;
#endif
switch (OSTailoredCode.CurrentOS)
{
case OSTailoredCode.DistinctOS.Linux: //TODO repro
case OSTailoredCode.DistinctOS.macOS:
// The actual sleep time on OS X with Mono is generally between the request time
// and up to 25% over. So we'll scale the sleep time back to account for that.
sleepTime = sleepTime * 4 / 5;
break;
case OSTailoredCode.DistinctOS.Windows:
// Assuming a timer period of 1 ms (i.e. TimeBeginPeriod(1)): The actual sleep time
// on Windows XP is generally within a half millisecond either way of the requested
// time. The actual sleep time on Windows 8 is generally between the requested time
// and up to a millisecond over. So we'll subtract 1 ms from the time to avoid
// sleeping longer than desired.
sleepTime -= 1;
break;
}
Thread.Sleep(Math.Max(sleepTime, 1));
}

View File

@ -3,6 +3,7 @@ using System.IO;
using System.Windows.Forms;
using BizHawk.Emulation.Common;
using BizHawk.Client.Common;
using BizHawk.Common;
namespace BizHawk.Client.EmuHawk
{
@ -91,6 +92,16 @@ namespace BizHawk.Client.EmuHawk
txtCropBottom.Text = Global.Config.DispCropBottom.ToString();
RefreshAspectRatioOptions();
if (OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows)
{
// Disable SlimDX on Unix
rbD3D9.Enabled = false;
rbD3D9.AutoCheck = false;
cbAlternateVsync.Enabled = false;
label13.Enabled = false;
label8.Enabled = false;
}
}
private void btnOk_Click(object sender, EventArgs e)

View File

@ -358,6 +358,8 @@ namespace BizHawk.Client.EmuHawk
private void tbbOpenFolder_Click(object sender, EventArgs e)
{
var frmWares = PathManager.MakeAbsolutePath(Global.Config.PathEntries.FirmwaresPathFragment, null);
if (OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows && !Directory.Exists(frmWares))
Directory.CreateDirectory(frmWares);
System.Diagnostics.Process.Start(frmWares);
}

View File

@ -71,7 +71,7 @@ namespace BizHawk.Client.EmuHawk
protected override void OnMouseClick(MouseEventArgs e)
{
if (!PlatformLinkedLibSingleton.RunningOnUnix) HideCaret(Handle);
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows) HideCaret(Handle);
base.OnMouseClick(e);
}
@ -264,7 +264,7 @@ namespace BizHawk.Client.EmuHawk
protected override void OnGotFocus(EventArgs e)
{
if (!PlatformLinkedLibSingleton.RunningOnUnix) HideCaret(Handle);
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows) HideCaret(Handle);
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)

View File

@ -4,6 +4,7 @@ using System.Linq;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Common;
namespace BizHawk.Client.EmuHawk
{
@ -24,10 +25,14 @@ namespace BizHawk.Client.EmuHawk
cbEnableNormal.Checked = Global.Config.SoundEnabledNormal;
cbEnableRWFF.Checked = Global.Config.SoundEnabledRWFF;
cbMuteFrameAdvance.Checked = Global.Config.MuteFrameAdvance;
#if !WINDOWS
rbOutputMethodDirectSound.Enabled = false;
rbOutputMethodXAudio2.Enabled = false;
#endif
if (OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows)
{
// Disable DirectSound and XAudio2 on Mono
rbOutputMethodDirectSound.Enabled = false;
rbOutputMethodXAudio2.Enabled = false;
}
rbOutputMethodDirectSound.Checked = Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.DirectSound;
rbOutputMethodXAudio2.Checked = Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.XAudio2;
rbOutputMethodOpenAL.Checked = Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.OpenAL;
@ -83,11 +88,13 @@ namespace BizHawk.Client.EmuHawk
private void PopulateDeviceList()
{
IEnumerable<string> deviceNames = Enumerable.Empty<string>();
#if WINDOWS
if (rbOutputMethodDirectSound.Checked) deviceNames = DirectSoundSoundOutput.GetDeviceNames();
if (rbOutputMethodXAudio2.Checked) deviceNames = XAudio2SoundOutput.GetDeviceNames();
#endif
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
{
if (rbOutputMethodDirectSound.Checked) deviceNames = DirectSoundSoundOutput.GetDeviceNames();
if (rbOutputMethodXAudio2.Checked) deviceNames = XAudio2SoundOutput.GetDeviceNames();
}
if (rbOutputMethodOpenAL.Checked) deviceNames = OpenALSoundOutput.GetDeviceNames();
listBoxSoundDevices.Items.Clear();
listBoxSoundDevices.Items.Add("<default>");
listBoxSoundDevices.SelectedIndex = 0;

View File

@ -7,6 +7,7 @@ using BizHawk.Emulation.Common;
using BizHawk.Client.Common;
using BizHawk.Client.EmuHawk.ToolExtensions;
using BizHawk.Common;
//TODO - select which memorydomains go out to the CDL file. will this cause a problem when re-importing it?
//perhaps missing domains shouldnt fail a check
@ -98,7 +99,16 @@ namespace BizHawk.Client.EmuHawk
if (_cdl == null)
{
lvCDL.BeginUpdate();
lvCDL.Items.Clear();
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
{
lvCDL.Items.Clear();
}
else
{
// this is a winforms implementation problem for mono
// see https://github.com/mono/mono/issues/11070
// until this is resolved in mono we should just skip this call
}
lvCDL.EndUpdate();
return;
}

View File

@ -186,9 +186,9 @@ namespace BizHawk.Client.EmuHawk
}
var currentScripts = LuaImp?.ScriptList; // Temp fix for now
LuaImp = PlatformLinkedLibSingleton.RunningOnUnix
? (PlatformEmuLuaLibrary) new NotReallyLuaLibrary()
: (PlatformEmuLuaLibrary) new EmuLuaLibrary(Emulator.ServiceProvider);
LuaImp = OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows
? (PlatformEmuLuaLibrary) new EmuLuaLibrary(Emulator.ServiceProvider)
: (PlatformEmuLuaLibrary) new NotReallyLuaLibrary();
if (currentScripts != null)
{
LuaImp.ScriptList.AddRange(currentScripts);

View File

@ -7,6 +7,7 @@ using System.Windows.Forms;
using BizHawk.Emulation.Common;
using BizHawk.Client.ApiHawk;
using BizHawk.Common;
namespace BizHawk.Client.EmuHawk
{
@ -68,6 +69,8 @@ namespace BizHawk.Client.EmuHawk
continue;
// if (!ApiInjector.IsAvailable(, t))
// continue;
if (t == typeof(HexView) && OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows)
continue; // Skip this tool on Unix. It isn't finished and only causes exceptions
var instance = Activator.CreateInstance(t);

View File

@ -159,7 +159,15 @@ namespace BizHawk.Client.EmuHawk
}
newTool.Restart();
newTool.Show();
if (OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows
&& newTool is RamSearch)
{
// the mono winforms implementation is buggy, skip to the return statement and call Show in MainForm instead
}
else
{
newTool.Show();
}
return (T)newTool;
}
@ -740,7 +748,7 @@ namespace BizHawk.Client.EmuHawk
return false;
}
if (t == typeof(LuaConsole) && PlatformLinkedLibSingleton.RunningOnUnix) return false;
if (t == typeof(LuaConsole) && OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows) return false;
var tool = Assembly
.GetExecutingAssembly()

View File

@ -85,7 +85,7 @@
<Compile Include="MruStack.cs" />
<Compile Include="MutableIntRange.cs" />
<Compile Include="NDBDatabase.cs" />
<Compile Include="PlatformLinkedLibSingleton.cs" />
<Compile Include="OSTailoredCode.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="QuickCollections.cs" />
<Compile Include="Serializer.cs" />

View File

@ -8,12 +8,12 @@ namespace BizHawk.Common.BizInvoke
public class DynamicLibraryImportResolver : IImportResolver, IDisposable
{
private IntPtr _p;
private readonly PlatformLinkedLibSingleton.PlatformLinkedLibManager libLoader = PlatformLinkedLibSingleton.LinkedLibManager;
private readonly OSTailoredCode.ILinkedLibManager libLoader = OSTailoredCode.LinkedLibManager;
public DynamicLibraryImportResolver(string dllName)
{
_p = libLoader.LoadPlatformSpecific(dllName);
if (_p == IntPtr.Zero) throw new InvalidOperationException($"null pointer returned by {nameof(PlatformLinkedLibSingleton.PlatformLinkedLibManager.LoadPlatformSpecific)}");
if (_p == IntPtr.Zero) throw new InvalidOperationException($"null pointer returned by {nameof(libLoader.LoadPlatformSpecific)}");
}
public IntPtr Resolve(string entryPoint)

View File

@ -79,6 +79,9 @@ namespace BizHawk.Common.BizInvoke
/// <param name="size"></param>
public MemoryBlock(ulong start, ulong size)
{
if (OSTailoredCode.CurrentOS != OSTailoredCode.DistinctOS.Windows)
throw new InvalidOperationException("MemoryBlock ctor called on Unix");
if (!WaterboxUtils.Aligned(start))
throw new ArgumentOutOfRangeException();
if (size == 0)

View File

@ -1,44 +1,73 @@
using System;
using System.Runtime.InteropServices;
//put in a different namespace for EXE so we can have an instance of this type (by linking to this file rather than copying it) built-in to the exe
//so the exe doesnt implicitly depend on the dll
using System.Diagnostics;
using System.Runtime.InteropServices;
//put in a different namespace for EXE so we can have an instance of this type (by linking to this file rather than copying it) built-in to the exe
//so the exe doesnt implicitly depend on the dll
#if EXE_PROJECT
namespace EXE_PROJECT
#else
namespace BizHawk.Common
#endif
{
public sealed class PlatformLinkedLibSingleton
{
public sealed class OSTailoredCode
{
public static readonly bool RunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX;
/// <remarks>macOS doesn't use PlatformID.MacOSX</remarks>
public static readonly DistinctOS CurrentOS = Environment.OSVersion.Platform == PlatformID.Unix
? currentIsMacOS() ? DistinctOS.macOS : DistinctOS.Linux
: DistinctOS.Windows;
private static readonly Lazy<PlatformLinkedLibManager> lazy = new Lazy<PlatformLinkedLibManager>(() => RunningOnUnix
? (PlatformLinkedLibManager) new UnixMonoLinkedLibManager()
: (PlatformLinkedLibManager) new Win32LinkedLibManager());
private static readonly Lazy<ILinkedLibManager> lazy = new Lazy<ILinkedLibManager>(() =>
{
switch (CurrentOS)
{
case DistinctOS.Linux:
case DistinctOS.macOS:
return new UnixMonoLLManager();
case DistinctOS.Windows:
return new WindowsLLManager();
default:
throw new ArgumentOutOfRangeException();
}
});
public static PlatformLinkedLibManager LinkedLibManager { get { return lazy.Value; } }
public static ILinkedLibManager LinkedLibManager => lazy.Value;
private PlatformLinkedLibSingleton() {}
private static bool currentIsMacOS()
{
var proc = new Process {
StartInfo = new ProcessStartInfo {
Arguments = "-s",
CreateNoWindow = true,
FileName = "uname",
RedirectStandardOutput = true,
UseShellExecute = false
}
};
proc.Start();
if (proc.StandardOutput.EndOfStream) throw new Exception("Can't determine OS (uname wrote nothing to stdout)!");
return proc.StandardOutput.ReadLine() == "Darwin";
}
public interface PlatformLinkedLibManager
private OSTailoredCode() {}
public interface ILinkedLibManager
{
IntPtr LoadPlatformSpecific(string dllToLoad);
IntPtr GetProcAddr(IntPtr hModule, string procName);
int FreePlatformSpecific(IntPtr hModule);
}
public class UnixMonoLinkedLibManager : PlatformLinkedLibManager
/// <remarks>This class is copied from a tutorial, so don't git blame and then email me expecting insight.</remarks>
private class UnixMonoLLManager : ILinkedLibManager
{
// This class is copied from a tutorial, so don't git blame and then email me expecting insight.
const int RTLD_NOW = 2;
private const int RTLD_NOW = 2;
[DllImport("libdl.so.2")]
private static extern IntPtr dlopen(String fileName, int flags);
private static extern IntPtr dlopen(string fileName, int flags);
[DllImport("libdl.so.2")]
private static extern IntPtr dlerror();
[DllImport("libdl.so.2")]
private static extern IntPtr dlsym(IntPtr handle, String symbol);
private static extern IntPtr dlsym(IntPtr handle, string symbol);
[DllImport("libdl.so.2")]
private static extern int dlclose(IntPtr handle);
public IntPtr LoadPlatformSpecific(string dllToLoad)
@ -59,10 +88,10 @@ public sealed class PlatformLinkedLibSingleton
}
}
public class Win32LinkedLibManager : PlatformLinkedLibManager
private class WindowsLLManager : ILinkedLibManager
{
[DllImport("kernel32.dll")]
private static extern UInt32 GetLastError();
private static extern uint GetLastError();
// was annotated `[DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)]` in SevenZip.NativeMethods
// param dllToLoad was annotated `[MarshalAs(UnmanagedType.LPStr)]` in SevenZip.NativeMethods
[DllImport("kernel32.dll")]
@ -89,5 +118,12 @@ public sealed class PlatformLinkedLibSingleton
return FreeLibrary(hModule) ? 1 : 0;
}
}
public enum DistinctOS : byte
{
Linux,
macOS,
Windows
}
}
}
}

View File

@ -59,10 +59,8 @@ namespace BizHawk.Common
}
}
#if WINDOWS
[DllImport("kernel32.dll", EntryPoint = "DeleteFileW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
static extern bool DeleteFileW([MarshalAs(UnmanagedType.LPWStr)]string lpFileName);
#endif
static void ThreadProc()
{
@ -94,12 +92,10 @@ namespace BizHawk.Common
{
try
{
// SHUT. UP. THE. EXCEPTIONS.
#if WINDOWS
DeleteFileW(fi.FullName);
#else
fi.Delete();
#endif
if (OSTailoredCode.CurrentOS == OSTailoredCode.DistinctOS.Windows)
DeleteFileW(fi.FullName); // SHUT. UP. THE. EXCEPTIONS.
else
fi.Delete();
}
catch
{

View File

@ -27,7 +27,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64.NativeApi
bool event_frameend = false;
bool event_breakpoint = false;
private static readonly PlatformLinkedLibSingleton.PlatformLinkedLibManager libLoader = PlatformLinkedLibSingleton.LinkedLibManager;
private static readonly OSTailoredCode.ILinkedLibManager libLoader = OSTailoredCode.LinkedLibManager;
public enum m64p_error
{

View File

@ -59,8 +59,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Client.MultiHawk",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BizHawk.Client.ApiHawk", "BizHawk.Client.ApiHawk\BizHawk.Client.ApiHawk.csproj", "{8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Virtu", "ExternalCoreProjects\Virtu\Virtu.csproj", "{8E522778-7A2C-4364-BDCE-0BA5623828E1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -127,18 +125,6 @@ Global
{8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E2F11F2-3955-4382-8C3A-CEBA1276CAEA}.Release|Any CPU.Build.0 = Release|Any CPU
{8E522778-7A2C-4364-BDCE-0BA5623828E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8E522778-7A2C-4364-BDCE-0BA5623828E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8E522778-7A2C-4364-BDCE-0BA5623828E1}.Debug|x64.ActiveCfg = Debug|Any CPU
{8E522778-7A2C-4364-BDCE-0BA5623828E1}.Debug|x64.Build.0 = Debug|Any CPU
{8E522778-7A2C-4364-BDCE-0BA5623828E1}.Debug|x86.ActiveCfg = Debug|Any CPU
{8E522778-7A2C-4364-BDCE-0BA5623828E1}.Debug|x86.Build.0 = Debug|Any CPU
{8E522778-7A2C-4364-BDCE-0BA5623828E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8E522778-7A2C-4364-BDCE-0BA5623828E1}.Release|Any CPU.Build.0 = Release|Any CPU
{8E522778-7A2C-4364-BDCE-0BA5623828E1}.Release|x64.ActiveCfg = Release|Any CPU
{8E522778-7A2C-4364-BDCE-0BA5623828E1}.Release|x64.Build.0 = Release|Any CPU
{8E522778-7A2C-4364-BDCE-0BA5623828E1}.Release|x86.ActiveCfg = Release|Any CPU
{8E522778-7A2C-4364-BDCE-0BA5623828E1}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

2
Dist/BuildDebug.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
cd "$(dirname "$0")/.." && msbuild /p:Configuration=Debug BizHawk.sln

2
Dist/BuildRelease.sh Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
cd "$(dirname "$0")/.." && msbuild /p:Configuration=Release BizHawk.sln

View File

@ -1,12 +0,0 @@
#!/bin/sh
cd "`dirname "$0"`"
if test -d .git ; then
REV="`git svn info | grep Revision: | cut -d' ' -f2`"
else
REV="`svn info | grep Revision: | cut -d' ' -f2`"
fi
sed -e 's/\$WCREV\$/'$REV'/g' "$1/Properties/svnrev_template" > "$1/Properties/svnrev.cs.tmp"
cmp -s "$1/Properties/svnrev.cs.tmp" "$1/Properties/svnrev.cs" || cp "$1/Properties/svnrev.cs.tmp" "$1/Properties/svnrev.cs"