diff --git a/BizHawk.Client.ApiHawk/Classes/ExternalToolManager.cs b/BizHawk.Client.ApiHawk/Classes/ExternalToolManager.cs index 52249ad767..6a4d669e18 100644 --- a/BizHawk.Client.ApiHawk/Classes/ExternalToolManager.cs +++ b/BizHawk.Client.ApiHawk/Classes/ExternalToolManager.cs @@ -102,13 +102,15 @@ namespace BizHawk.Client.ApiHawk } } - var customFormType = externalToolFile.GetTypes().FirstOrDefault(t => t != null && t.FullName == "BizHawk.Client.EmuHawk.CustomMainForm"); + var availTypes = externalToolFile.GetTypes(); + var customFormType = availTypes.FirstOrDefault(t => t.FullName == "BizHawk.Client.EmuHawk.CustomMainForm") + ?? availTypes.SingleOrDefault(t => typeof(IExternalToolForm).IsAssignableFrom(t) && t.CustomAttributes.Any(cad => cad.AttributeType == typeof(ExternalToolEntryPointFormAttribute))); if (customFormType == null) { - item.ToolTipText = "Does not have a CustomMainForm"; + item.ToolTipText = "Does not have a correctly-formatted CustomMainForm or a form decorated with [ExternalToolEntryPointForm]"; item.Enabled = false; } - item.Tag = fileName; + item.Tag = (fileName, customFormType?.FullName); attributes = externalToolFile.GetCustomAttributes(typeof(BizHawkExternalToolUsageAttribute), false); if (attributes != null && attributes.Length == 1) diff --git a/BizHawk.Client.Common/Api/ExternalToolEntryPointFormAttribute.cs b/BizHawk.Client.Common/Api/ExternalToolEntryPointFormAttribute.cs new file mode 100644 index 0000000000..b6e457167c --- /dev/null +++ b/BizHawk.Client.Common/Api/ExternalToolEntryPointFormAttribute.cs @@ -0,0 +1,7 @@ +using System; + +namespace BizHawk.Client.Common +{ + [AttributeUsage(AttributeTargets.Class)] + public class ExternalToolEntryPointFormAttribute : Attribute {} +} diff --git a/BizHawk.Client.EmuHawk/MainForm.Events.cs b/BizHawk.Client.EmuHawk/MainForm.Events.cs index ad98b6d966..c2e080f5c4 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Events.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Events.cs @@ -1415,7 +1415,8 @@ namespace BizHawk.Client.EmuHawk { item.Click += delegate { - Tools.Load((string)item.Tag); + var (fileName, customFormTypeName) = ((string, string)) item.Tag; + Tools.LoadExternalToolForm(fileName, customFormTypeName); }; } else diff --git a/BizHawk.Client.EmuHawk/tools/ToolManager.cs b/BizHawk.Client.EmuHawk/tools/ToolManager.cs index 9812ded25f..742dd73a9c 100644 --- a/BizHawk.Client.EmuHawk/tools/ToolManager.cs +++ b/BizHawk.Client.EmuHawk/tools/ToolManager.cs @@ -94,84 +94,49 @@ namespace BizHawk.Client.EmuHawk public T Load(string toolPath, bool focus = true) where T : class, IToolForm { - bool isExternal = typeof(T) == typeof(IExternalToolForm); - - if (!IsAvailable() && !isExternal) - { - return null; - } - - T existingTool; - if (isExternal) - { - existingTool = (T)_tools.FirstOrDefault(t => t is T && t.GetType().Assembly.Location == toolPath); - } - else - { - existingTool = (T)_tools.FirstOrDefault(t => t is T); - } + if (!IsAvailable()) return null; + var existingTool = _tools.OfType().FirstOrDefault(); if (existingTool != null) { - if (existingTool.IsDisposed) - { - _tools.Remove(existingTool); - } - else + if (!existingTool.IsDisposed) { if (focus) { existingTool.Show(); existingTool.Focus(); } - return existingTool; } + _tools.Remove(existingTool); } - IToolForm newTool = CreateInstance(toolPath); - - if (newTool == null) - { - return null; - } - - if (newTool is Form form) - { - form.Owner = _owner; - } - - if (isExternal) - { - ApiInjector.UpdateApis(_apiProvider, newTool); - } + var newTool = CreateInstance(toolPath); + if (newTool == null) return null; + if (newTool is Form form) form.Owner = _owner; ServiceInjector.UpdateServices(_emulator.ServiceProvider, newTool); SetBaseProperties(newTool); - string toolType = typeof(T).ToString(); - + var toolTypeName = typeof(T).ToString(); // auto settings - if (newTool is IToolFormAutoConfig tool) + if (newTool is IToolFormAutoConfig autoConfigTool) { - if (!_config.CommonToolSettings.TryGetValue(toolType, out var settings)) - { - settings = new ToolDialogSettings(); - _config.CommonToolSettings[toolType] = settings; - } - - AttachSettingHooks(tool, settings); + AttachSettingHooks( + autoConfigTool, + _config.CommonToolSettings.TryGetValue(toolTypeName, out var settings) + ? settings + : (_config.CommonToolSettings[toolTypeName] = new ToolDialogSettings()) + ); } - // custom settings if (HasCustomConfig(newTool)) { - if (!_config.CustomToolSettings.TryGetValue(toolType, out var settings)) - { - settings = new Dictionary(); - _config.CustomToolSettings[toolType] = settings; - } - - InstallCustomConfig(newTool, settings); + InstallCustomConfig( + newTool, + _config.CustomToolSettings.TryGetValue(toolTypeName, out var settings) + ? settings + : (_config.CustomToolSettings[toolTypeName] = new Dictionary()) + ); } newTool.Restart(); @@ -186,6 +151,56 @@ namespace BizHawk.Client.EmuHawk return (T)newTool; } + /// Loads the external tool's entry form. + public IExternalToolForm LoadExternalToolForm(string toolPath, string customFormTypeName, bool focus = true) + { + var existingTool = _tools.OfType().FirstOrDefault(t => t.GetType().Assembly.Location == toolPath); + if (existingTool != null) + { + if (!existingTool.IsDisposed) + { + if (focus) + { + existingTool.Show(); + existingTool.Focus(); + } + return existingTool; + } + _tools.Remove(existingTool); + } + + var newTool = (IExternalToolForm) CreateInstance(typeof(IExternalToolForm), toolPath, customFormTypeName); + if (newTool == null) return null; + if (newTool is Form form) form.Owner = _owner; + ApiInjector.UpdateApis(_apiProvider, newTool); + ServiceInjector.UpdateServices(_emulator.ServiceProvider, newTool); + SetBaseProperties(newTool); + // auto settings + if (newTool is IToolFormAutoConfig autoConfigTool) + { + AttachSettingHooks( + autoConfigTool, + _config.CommonToolSettings.TryGetValue(customFormTypeName, out var settings) + ? settings + : (_config.CommonToolSettings[customFormTypeName] = new ToolDialogSettings()) + ); + } + // custom settings + if (HasCustomConfig(newTool)) + { + InstallCustomConfig( + newTool, + _config.CustomToolSettings.TryGetValue(customFormTypeName, out var settings) + ? settings + : (_config.CustomToolSettings[customFormTypeName] = new Dictionary()) + ); + } + + newTool.Restart(); + newTool.Show(); + return newTool; + } + public void AutoLoad() { var genericSettings = _config.CommonToolSettings @@ -629,8 +644,9 @@ namespace BizHawk.Client.EmuHawk /// /// Type of tool you want to create /// Path dll for an external tool + /// For external tools, of the entry form's type ( will be ) /// New instance of an IToolForm - private IToolForm CreateInstance(Type toolType, string dllPath) + private IToolForm CreateInstance(Type toolType, string dllPath, string toolTypeName = null) { IToolForm tool; @@ -645,7 +661,7 @@ namespace BizHawk.Client.EmuHawk { try { - tool = Activator.CreateInstanceFrom(dllPath, "BizHawk.Client.EmuHawk.CustomMainForm").Unwrap() as IExternalToolForm; + tool = Activator.CreateInstanceFrom(dllPath, toolTypeName ?? "BizHawk.Client.EmuHawk.CustomMainForm").Unwrap() as IExternalToolForm; if (tool == null) { MessageBox.Show($"It seems that the object CustomMainForm does not implement {nameof(IExternalToolForm)}. Please review the code.", "No, no, no. Wrong Way !", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);