2011-01-11 02:55:51 +00:00
using System ;
2012-10-29 08:37:22 +00:00
using System.IO ;
2013-07-27 00:30:08 +00:00
using System.Collections.Generic ;
2012-10-29 08:37:22 +00:00
using System.Reflection ;
using System.Runtime.InteropServices ;
2011-01-11 02:55:51 +00:00
using System.Windows.Forms ;
2012-03-12 04:44:34 +00:00
#if WINDOWS
2011-01-11 02:55:51 +00:00
using SlimDX.DirectSound ;
2011-05-23 00:33:05 +00:00
using Microsoft.VisualBasic.ApplicationServices ;
2012-03-12 04:44:34 +00:00
#endif
2011-01-11 02:55:51 +00:00
2013-02-24 20:17:12 +00:00
#pragma warning disable 618
2013-10-27 22:07:40 +00:00
using BizHawk.Common ;
2013-10-25 00:57:23 +00:00
using BizHawk.Client.Common ;
2013-11-03 03:54:37 +00:00
namespace BizHawk.Client.EmuHawk
2011-01-11 02:55:51 +00:00
{
2011-06-19 23:39:25 +00:00
static class Program
{
2013-01-02 20:11:27 +00:00
static Program ( )
2011-06-19 23:39:25 +00:00
{
2013-02-24 20:17:12 +00:00
//http://www.codeproject.com/Articles/310675/AppDomain-AssemblyResolve-Event-Tips
2012-10-29 08:37:22 +00:00
#if WINDOWS
// this will look in subdirectory "dll" to load pinvoked stuff
2013-11-03 16:05:49 +00:00
string dllDir = System . IO . Path . Combine ( Path . GetDirectoryName ( Assembly . GetExecutingAssembly ( ) . Location ) , "dll" ) ;
2013-07-27 00:30:08 +00:00
SetDllDirectory ( dllDir ) ;
//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.
//some people are getting MOTW through a combination of browser used to download bizhawk, and program used to dearchive it
WhackAllMOTW ( dllDir ) ;
2012-09-04 00:20:36 +00:00
2012-10-29 08:37:22 +00:00
//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 ) ;
#endif
2013-01-02 20:11:27 +00:00
}
[STAThread]
2013-08-19 01:43:18 +00:00
static void Main ( string [ ] args )
2013-01-02 20:11:27 +00:00
{
SubMain ( args ) ;
}
//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 void SubMain ( string [ ] args )
{
2013-01-01 23:10:47 +00:00
// 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?)
2012-12-25 20:36:04 +00:00
// zero 25-dec-2012 - only do for public builds. its annoying during development
2014-06-04 17:02:54 +00:00
if ( ! VersionInfo . DeveloperBuild )
2012-12-17 15:38:56 +00:00
{
var thisversion = typeof ( Program ) . Assembly . GetName ( ) . Version ;
2013-11-03 16:05:49 +00:00
var utilversion = Assembly . LoadWithPartialName ( "Bizhawk.Client.Common" ) . GetName ( ) . Version ;
2013-11-15 14:12:27 +00:00
var emulversion = Assembly . LoadWithPartialName ( "Bizhawk.Emulation.Cores" ) . GetName ( ) . Version ;
2012-12-17 15:38:56 +00:00
if ( thisversion ! = utilversion | | thisversion ! = emulversion )
{
MessageBox . Show ( "Conflicting revisions found! Don't mix .dll versions!" ) ;
return ;
}
}
2013-01-01 23:10:47 +00:00
Application . EnableVisualStyles ( ) ;
Application . SetCompatibleTextRenderingDefault ( false ) ;
2013-11-03 16:05:49 +00:00
string iniPath = System . IO . Path . Combine ( Path . GetDirectoryName ( Assembly . GetExecutingAssembly ( ) . Location ) , "config.ini" ) ;
2013-12-22 02:47:35 +00:00
Global . Config = ConfigService . Load < Config > ( iniPath ) ;
2013-08-11 19:55:13 +00:00
Global . Config . ResolveDefaults ( ) ;
2013-10-27 22:07:40 +00:00
BizHawk . Common . HawkFile . ArchiveHandlerFactory = new SevenZipSharpArchiveHandler ( ) ;
2012-10-10 02:43:33 +00:00
#if WINDOWS
2013-11-03 16:07:58 +00:00
try { GlobalWin . DSound = SoundEnumeration . Create ( ) ; }
2011-06-19 23:39:25 +00:00
catch
{
2012-03-02 03:39:09 +00:00
MessageBox . Show ( "Couldn't initialize DirectSound! Things may go poorly for you. Try changing your sound driver to 41khz instead of 48khz in mmsys.cpl." , "Initialization Error" , MessageBoxButtons . OK , MessageBoxIcon . Error ) ;
2011-06-19 23:39:25 +00:00
}
2012-03-12 04:44:34 +00:00
#endif
2011-01-11 02:55:51 +00:00
2014-01-27 05:37:04 +00:00
//create IGL context.
//at some point in the future, we may need to select from several drivers
GlobalWin . GL = new BizHawk . Bizware . BizwareGL . Drivers . OpenTK . IGL_TK ( ) ;
2014-06-08 23:30:34 +00:00
GlobalWin . GLManager = new GLManager ( ) ;
GlobalWin . CR_GL = GlobalWin . GLManager . GetContextForIGL ( GlobalWin . GL ) ;
2014-01-27 05:37:04 +00:00
2011-06-19 23:39:25 +00:00
try
{
2012-03-12 04:44:34 +00:00
#if WINDOWS
2011-06-19 23:39:25 +00:00
if ( Global . Config . SingleInstanceMode )
{
2013-08-25 22:43:34 +00:00
try
{
new SingleInstanceController ( args ) . Run ( args ) ;
}
2013-09-14 19:34:14 +00:00
catch ( ObjectDisposedException )
2013-08-25 22:43:34 +00:00
{
/*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*/
}
2011-06-19 23:39:25 +00:00
}
else
{
2012-03-12 04:44:34 +00:00
#endif
2012-04-16 08:18:41 +00:00
using ( var mf = new MainForm ( args ) )
{
var title = mf . Text ;
mf . Show ( ) ;
mf . Text = title ;
2013-11-23 02:07:02 +00:00
try
{
mf . ProgramRunLoop ( ) ;
}
catch ( Exception e )
{
#if WINDOWS
2014-06-04 17:02:54 +00:00
if ( ! VersionInfo . DeveloperBuild & & Global . MovieSession . Movie . IsActive )
2013-11-23 02:07:02 +00:00
{
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 succeed)" ,
"Fatal error: " + e . GetType ( ) . Name ,
MessageBoxButtons . YesNo ,
MessageBoxIcon . Exclamation
) ;
if ( result = = DialogResult . Yes )
{
2013-11-23 18:18:58 +00:00
Global . MovieSession . Movie . Save ( ) ;
2013-11-23 02:07:02 +00:00
}
}
#endif
2013-12-14 06:26:05 +00:00
throw ;
2013-11-23 02:07:02 +00:00
}
2012-04-16 08:18:41 +00:00
}
2012-03-12 04:44:34 +00:00
#if WINDOWS
2011-06-19 23:39:25 +00:00
}
2012-12-17 15:38:56 +00:00
#endif
2011-06-19 23:39:25 +00:00
}
catch ( Exception e )
{
2013-03-25 00:44:29 +00:00
string message = e . ToString ( ) ;
if ( e . InnerException ! = null )
{
message + = "\n\nInner Exception:\n\n" + e . InnerException ;
}
2013-12-14 06:26:05 +00:00
message + = "\n\nStackTrace:\n" + e . StackTrace ;
2013-04-16 00:19:31 +00:00
MessageBox . Show ( message ) ;
2011-06-19 23:39:25 +00:00
}
2012-03-12 04:44:34 +00:00
#if WINDOWS
2011-06-19 23:39:25 +00:00
finally
{
2013-11-03 16:07:58 +00:00
if ( GlobalWin . DSound ! = null & & GlobalWin . DSound . Disposed = = false )
GlobalWin . DSound . Dispose ( ) ;
2014-01-27 05:37:04 +00:00
GlobalWin . GL . Dispose ( ) ;
2012-11-09 19:21:33 +00:00
GamePad . CloseAll ( ) ;
2011-06-19 23:39:25 +00:00
}
2012-03-12 04:44:34 +00:00
#endif
2011-06-19 23:39:25 +00:00
}
2011-05-23 00:33:05 +00:00
2012-10-29 08:37:22 +00:00
//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 bool SetDllDirectory ( string lpPathName ) ;
2013-07-27 00:30:08 +00:00
[DllImport("kernel32.dll", EntryPoint = "DeleteFileW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
static extern bool DeleteFileW ( [ MarshalAs ( UnmanagedType . LPWStr ) ] string lpFileName ) ;
static void RemoveMOTW ( string path )
{
DeleteFileW ( path + ":Zone.Identifier" ) ;
}
//for debugging purposes, this is provided. when we're satisfied everyone understands whats going on, we'll get rid of this
[DllImportAttribute("kernel32.dll", EntryPoint = "CreateFileW")]
public static extern System . IntPtr CreateFileW ( [ InAttribute ( ) ] [ MarshalAsAttribute ( UnmanagedType . LPWStr ) ] string lpFileName , int dwDesiredAccess , int dwShareMode , [ InAttribute ( ) ] int lpSecurityAttributes , int dwCreationDisposition , int dwFlagsAndAttributes , [ InAttribute ( ) ] int hTemplateFile ) ;
static void ApplyMOTW ( string path )
{
int generic_write = 0x40000000 ;
int file_share_write = 2 ;
int create_always = 2 ;
var adsHandle = CreateFileW ( path + ":Zone.Identifier" , generic_write , file_share_write , 0 , create_always , 0 , 0 ) ;
using ( var sfh = new Microsoft . Win32 . SafeHandles . SafeFileHandle ( adsHandle , true ) )
{
var adsStream = new System . IO . FileStream ( sfh , FileAccess . Write ) ;
StreamWriter sw = new StreamWriter ( adsStream ) ;
sw . Write ( "[ZoneTransfer]\r\nZoneId=3" ) ;
sw . Flush ( ) ;
adsStream . Close ( ) ;
}
}
static void WhackAllMOTW ( string dllDir )
{
var todo = new Queue < DirectoryInfo > ( new [ ] { new DirectoryInfo ( dllDir ) } ) ;
while ( todo . Count > 0 )
{
var di = todo . Dequeue ( ) ;
foreach ( var disub in di . GetDirectories ( ) ) todo . Enqueue ( disub ) ;
foreach ( var fi in di . GetFiles ( "*.dll" ) )
RemoveMOTW ( fi . FullName ) ;
}
}
2012-10-29 08:37:22 +00:00
#endif
static Assembly CurrentDomain_AssemblyResolve ( object sender , ResolveEventArgs args )
{
2013-01-02 20:11:27 +00:00
lock ( AppDomain . CurrentDomain )
{
var asms = AppDomain . CurrentDomain . GetAssemblies ( ) ;
foreach ( var asm in asms )
if ( asm . FullName = = args . Name )
return asm ;
//load missing assemblies by trying to find them in the dll directory
string dllname = new AssemblyName ( args . Name ) . Name + ".dll" ;
2013-11-03 16:05:49 +00:00
string directory = System . IO . Path . Combine ( Path . GetDirectoryName ( Assembly . GetExecutingAssembly ( ) . Location ) , "dll" ) ;
2013-01-02 20:11:27 +00:00
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 ) ;
}
2012-10-29 08:37:22 +00:00
}
2012-03-12 04:44:34 +00:00
#if WINDOWS
2011-06-19 23:39:25 +00:00
public class SingleInstanceController : WindowsFormsApplicationBase
{
2013-04-16 00:19:31 +00:00
readonly string [ ] cmdArgs ;
2011-06-19 23:39:25 +00:00
public SingleInstanceController ( string [ ] args )
{
cmdArgs = args ;
IsSingleInstance = true ;
StartupNextInstance + = this_StartupNextInstance ;
}
void this_StartupNextInstance ( object sender , StartupNextInstanceEventArgs e )
{
2013-08-25 22:43:34 +00:00
( MainForm as MainForm ) . LoadRom ( e . CommandLine [ 0 ] ) ;
2011-06-19 23:39:25 +00:00
}
2011-05-23 00:33:05 +00:00
2011-06-19 23:39:25 +00:00
protected override void OnCreateMainForm ( )
{
2013-08-25 22:43:34 +00:00
MainForm = new MainForm ( cmdArgs ) ;
var title = MainForm . Text ;
MainForm . Show ( ) ;
MainForm . Text = title ;
( MainForm as MainForm ) . ProgramRunLoop ( ) ;
}
2011-06-19 23:39:25 +00:00
}
2011-08-21 01:07:58 +00:00
2014-01-27 05:37:04 +00:00
2012-03-12 04:44:34 +00:00
#endif
2011-06-19 23:39:25 +00:00
}
2011-01-11 02:55:51 +00:00
}