2015-12-04 13:10:04 +00:00
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.Drawing ;
using System.IO ;
using System.Linq ;
using System.Reflection ;
using System.Windows.Forms ;
using BizHawk.Client.Common ;
namespace BizHawk.Client.ApiHawk
{
/// <summary>
/// This static class handle all ExternalTools
/// </summary>
public static class ExternalToolManager
{
#region Fields
2015-12-20 17:13:32 +00:00
private static FileSystemWatcher directoryMonitor ;
2015-12-04 13:10:04 +00:00
private static List < ToolStripMenuItem > menuItems = new List < ToolStripMenuItem > ( ) ;
#endregion
#region cTor ( s )
/// <summary>
/// Initilization
/// </summary>
static ExternalToolManager ( )
{
2015-12-20 17:13:32 +00:00
if ( ! Directory . Exists ( Global . Config . PathEntries [ "Global" , "External Tools" ] . Path ) )
{
Directory . CreateDirectory ( Global . Config . PathEntries [ "Global" , "External Tools" ] . Path ) ;
}
directoryMonitor = new FileSystemWatcher ( Global . Config . PathEntries [ "Global" , "External Tools" ] . Path , "*.dll" ) ;
2015-12-04 13:10:04 +00:00
directoryMonitor . IncludeSubdirectories = false ;
2015-12-24 13:00:08 +00:00
directoryMonitor . NotifyFilter = NotifyFilters . LastAccess | NotifyFilters . LastWrite | NotifyFilters . FileName ;
directoryMonitor . Filter = "*.dll" ;
directoryMonitor . Created + = new FileSystemEventHandler ( DirectoryMonitor_Created ) ;
directoryMonitor . EnableRaisingEvents = true ;
2015-12-04 13:10:04 +00:00
2016-03-16 22:06:53 +00:00
ClientApi . RomLoaded + = delegate { BuildToolStrip ( ) ; } ;
2015-12-04 13:10:04 +00:00
BuildToolStrip ( ) ;
}
#endregion
#region Methods
/// <summary>
/// Build the toolstrip menu
/// </summary>
private static void BuildToolStrip ( )
{
menuItems . Clear ( ) ;
if ( Directory . Exists ( directoryMonitor . Path ) )
{
DirectoryInfo dInfo = new DirectoryInfo ( directoryMonitor . Path ) ;
foreach ( FileInfo fi in dInfo . GetFiles ( "*.dll" ) )
{
menuItems . Add ( GenerateToolTipFromFileName ( fi . FullName ) ) ;
}
}
}
/// <summary>
/// Generate a <see cref="ToolStripMenuItem"/> from an
/// external tool dll.
/// The assembly must have <see cref="BizHawkExternalToolAttribute"/> in its
/// assembly attributes
/// </summary>
/// <param name="fileName">File that will be reflected</param>
/// <returns>A new <see cref="ToolStripMenuItem"/>; assembly path can be found in the Tag property</returns>
2016-05-29 14:50:16 +00:00
/// <remarks>For the moment, you could only load a dll that have a form (which implements <see cref="BizHawk.Client.EmuHawk.IExternalToolForm"/>)</remarks>
2015-12-04 13:10:04 +00:00
private static ToolStripMenuItem GenerateToolTipFromFileName ( string fileName )
{
Type customFormType ;
Assembly externalToolFile ;
ToolStripMenuItem item = null ;
2016-05-29 14:50:16 +00:00
2015-12-04 13:10:04 +00:00
try
{
externalToolFile = Assembly . LoadFrom ( fileName ) ;
object [ ] attributes = externalToolFile . GetCustomAttributes ( typeof ( BizHawkExternalToolAttribute ) , false ) ;
if ( attributes ! = null & & attributes . Count ( ) = = 1 )
{
BizHawkExternalToolAttribute attribute = ( BizHawkExternalToolAttribute ) attributes [ 0 ] ;
item = new ToolStripMenuItem ( attribute . Name ) ;
item . ToolTipText = attribute . Description ;
if ( attribute . IconResourceName ! = string . Empty )
{
Stream s = externalToolFile . GetManifestResourceStream ( string . Format ( "{0}.{1}" , externalToolFile . GetName ( ) . Name , attribute . IconResourceName ) ) ;
if ( s ! = null )
{
item . Image = new Bitmap ( s ) ;
}
}
customFormType = externalToolFile . GetTypes ( ) . FirstOrDefault < Type > ( t = > t ! = null & & t . FullName = = "BizHawk.Client.EmuHawk.CustomMainForm" ) ;
if ( customFormType = = null )
{
item . ToolTipText = "Does not have a CustomMainForm" ;
item . Enabled = false ;
}
item . Tag = fileName ;
2016-03-16 22:06:53 +00:00
attributes = externalToolFile . GetCustomAttributes ( typeof ( BizHawkExternalToolUsageAttribute ) , false ) ;
if ( attributes ! = null & & attributes . Count ( ) = = 1 )
{
BizHawkExternalToolUsageAttribute attribute2 = ( BizHawkExternalToolUsageAttribute ) attributes [ 0 ] ;
if ( Global . Emulator . SystemId = = "NULL" & & attribute2 . ToolUsage ! = BizHawkExternalToolUsage . Global )
{
item . ToolTipText = "This tool doesn't work if nothing is loaded" ;
item . Enabled = false ;
}
2016-03-26 22:07:44 +00:00
else if ( attribute2 . ToolUsage = = BizHawkExternalToolUsage . EmulatorSpecific & & Global . Emulator . SystemId ! = ClientApi . SystemIdConverter . ConvertBack ( attribute2 . System ) )
2016-03-16 22:06:53 +00:00
{
item . ToolTipText = "This tool doesn't work for current system" ;
item . Enabled = false ;
}
2016-03-20 22:05:38 +00:00
else if ( attribute2 . ToolUsage = = BizHawkExternalToolUsage . GameSpecific & & Global . Game . Hash ! = attribute2 . GameHash )
2016-03-16 22:06:53 +00:00
{
item . ToolTipText = "This tool doesn't work for current game" ;
item . Enabled = false ;
}
}
2015-12-04 13:10:04 +00:00
}
else
{
item = new ToolStripMenuItem ( externalToolFile . GetName ( ) . Name ) ;
item . ToolTipText = "BizHawkExternalTool attribute hasn't been found" ;
item . Enabled = false ;
}
}
catch ( BadImageFormatException )
{
item = new ToolStripMenuItem ( fileName ) ;
item . ToolTipText = "This is not an assembly" ;
item . Enabled = false ;
}
#if DEBUG //I added special debug stuff to get additionnal informations. Don(t think it can be usefull for released versions
catch ( ReflectionTypeLoadException ex )
{
foreach ( Exception e in ex . LoaderExceptions )
{
Debug . WriteLine ( e . Message ) ;
}
item . ToolTipText = "Something goes wrong while trying to load" ;
item . Enabled = false ;
}
#else
catch ( ReflectionTypeLoadException )
{
item . ToolTipText = "Something goes wrong while trying to load" ;
item . Enabled = false ;
}
#endif
return item ;
}
/// <summary>
/// This event is raised when we add a dll file into
/// the external tools path.
/// It will automatically load the assembly and add it into the list
/// </summary>
/// <param name="sender">Object that raised the event</param>
/// <param name="e">Event arguments</param>
private static void DirectoryMonitor_Created ( object sender , FileSystemEventArgs e )
{
menuItems . Add ( GenerateToolTipFromFileName ( e . FullPath ) ) ;
}
#endregion
#region Properties
/// <summary>
/// Gets a prebuild <see cref="ToolStripMenuItem"/>
/// This list auto-updated by the <see cref="ExternalToolManager"/> itself
/// </summary>
public static IEnumerable < ToolStripMenuItem > ToolStripMenu
{
get
{
return menuItems ;
}
}
#endregion
}
}